mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-08-11 09:43:56 +00:00
feat(sse): decouple SSE to mcp.pi.ruv.io proxy + Claude Code source research
SSE Proxy Decoupling (ADR-130): - Fix ruvbrain-sse proxy: proper MCP handshake, session creation, drain polling - Fix internal queue endpoints: session_create keeps receiver, drain returns buffered messages - Add response_queues to AppState for SSE proxy communication - Skip sparsifier for >5M edge graphs (was crashing on 16M edges) - Add SSE_DISABLED/MAX_SSE env vars for configurable connection limits - Route SSE to dedicated mcp.pi.ruv.io subdomain (Cloudflare CNAME) - Serve SSE at root / path on proxy (no /sse needed) - Update all references from pi.ruv.io/sse to mcp.pi.ruv.io - Fix Dockerfile consciousness crate build (feature/version mismatches) Claude Code CLI Source Research (ADR-133): - 19 research documents analyzing Claude Code internals (3000+ lines) - Decompiler script + RVF corpus builder for all major versions - Binary RVF containers for v0.2, v1.0, v2.0, v2.1 (300-2068 vectors each) - Call graphs, class hierarchies, state machines from minified source Integration Strategy (ADR-134): - 6-tier integration plan: WASM MCP, agents, hooks, cache, SDK, plugin - Integration guide with architecture diagrams and performance targets Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
parent
3569b697c1
commit
930fca916f
103 changed files with 50257 additions and 78 deletions
|
|
@ -22,7 +22,7 @@ members = [
|
|||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "2.0.6"
|
||||
version = "2.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.77"
|
||||
license = "MIT"
|
||||
|
|
|
|||
|
|
@ -64,12 +64,16 @@ RUN sed -i '/ruvector-graph\s*=/d' crates/ruvector-mincut/Cargo.toml && \
|
|||
sed -i '/\[\[example\]\]/,/^$/d' crates/ruvector-sparsifier/Cargo.toml && \
|
||||
sed -i '/\[\[bench\]\]/,/^$/d' crates/ruvector-sparsifier/Cargo.toml && \
|
||||
sed -i '/\[\[bench\]\]/,/^$/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/ruvector-mincut = { version = "2.1.0"/ruvector-mincut = { version = "2.0.6"/' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/ruvector-solver = { version = "2.1.0"/ruvector-solver = { version = "2.0.6"/' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/ruvector-sparsifier = { version = "2.1.0"/ruvector-sparsifier = { version = "2.0.6"/' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/ruvector-coherence\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/ruvector-cognitive-container\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/ruvector-math\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/"coherence-accel",\s*//g' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/"witness",\s*//g' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/"math-accel",\s*//g' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^coherence-accel\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^witness\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^math-accel\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^full\s*=/,/]/c\full = ["parallel", "phi", "emergence", "collapse", "simd", "solver-accel", "sparsifier-accel", "mincut-accel"]' crates/ruvector-consciousness/Cargo.toml && \
|
||||
find crates/rvf -name "Cargo.toml" -exec sed -i '/\[\[example\]\]/,/^$/d' {} \; && \
|
||||
find crates/rvf -name "Cargo.toml" -exec sed -i '/\[\[bench\]\]/,/^$/d' {} \; && \
|
||||
find crates/sona -name "Cargo.toml" -exec sed -i '/\[\[example\]\]/,/^$/d' {} \; && \
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ COPY crates/ruvector-domain-expansion ./crates/ruvector-domain-expansion
|
|||
COPY crates/ruvector-delta-core ./crates/ruvector-delta-core
|
||||
COPY crates/ruvector-solver ./crates/ruvector-solver
|
||||
COPY crates/ruvector-sparsifier ./crates/ruvector-sparsifier
|
||||
COPY crates/ruvector-consciousness ./crates/ruvector-consciousness
|
||||
COPY crates/ruvllm ./crates/ruvllm
|
||||
COPY crates/ruvector-core ./crates/ruvector-core
|
||||
COPY crates/rvf ./crates/rvf
|
||||
|
|
@ -63,6 +64,17 @@ RUN sed -i '/ruvector-graph\s*=/d' crates/ruvector-mincut/Cargo.toml && \
|
|||
sed -i '/\[\[bench\]\]/,/^$/d' crates/ruvector-delta-core/Cargo.toml && \
|
||||
sed -i '/\[\[example\]\]/,/^$/d' crates/ruvector-sparsifier/Cargo.toml && \
|
||||
sed -i '/\[\[bench\]\]/,/^$/d' crates/ruvector-sparsifier/Cargo.toml && \
|
||||
sed -i '/\[\[bench\]\]/,/^$/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/ruvector-mincut = { version = "2.1.0"/ruvector-mincut = { version = "2.0.6"/' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/ruvector-solver = { version = "2.1.0"/ruvector-solver = { version = "2.0.6"/' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i 's/ruvector-sparsifier = { version = "2.1.0"/ruvector-sparsifier = { version = "2.0.6"/' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/ruvector-coherence\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/ruvector-cognitive-container\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/ruvector-math\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^coherence-accel\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^witness\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^math-accel\s*=/d' crates/ruvector-consciousness/Cargo.toml && \
|
||||
sed -i '/^full\s*=/,/]/c\full = ["parallel", "phi", "emergence", "collapse", "simd", "solver-accel", "sparsifier-accel", "mincut-accel"]' crates/ruvector-consciousness/Cargo.toml && \
|
||||
find crates/rvf -name "Cargo.toml" -exec sed -i '/\[\[example\]\]/,/^$/d' {} \; && \
|
||||
find crates/rvf -name "Cargo.toml" -exec sed -i '/\[\[bench\]\]/,/^$/d' {} \; && \
|
||||
find crates/sona -name "Cargo.toml" -exec sed -i '/\[\[example\]\]/,/^$/d' {} \; && \
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
//! ruvbrain-sse: Thin SSE proxy for MCP transport decoupling (ADR-130).
|
||||
//!
|
||||
//! This binary has NO business logic. It:
|
||||
//! - Accepts SSE connections on GET /sse (max 200 concurrent)
|
||||
//! - Accepts SSE connections on GET /sse (generates session ID per MCP spec)
|
||||
//! - Sends initial `endpoint` event with /messages?sessionId=X
|
||||
//! - Accepts JSON-RPC on POST /messages?sessionId=X
|
||||
//! - Forwards JSON-RPC to the brain API at BRAIN_API_URL
|
||||
//! - Forwards JSON-RPC to the brain API at BRAIN_API_URL/internal/queue/push
|
||||
//! - Polls API at /internal/queue/drain?sessionId=X for responses
|
||||
//! - Streams responses back to SSE clients
|
||||
//! - Streams responses back to SSE clients as `message` events
|
||||
//! - Provides /v1/ready and /v1/health endpoints
|
||||
|
||||
use axum::{
|
||||
|
|
@ -26,6 +27,7 @@ use std::time::Duration;
|
|||
use tokio::signal;
|
||||
use tokio::sync::broadcast;
|
||||
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
|
||||
use uuid::Uuid;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// State
|
||||
|
|
@ -53,7 +55,7 @@ struct AppState {
|
|||
#[derive(Deserialize)]
|
||||
struct SessionQuery {
|
||||
#[serde(rename = "sessionId")]
|
||||
session_id: String,
|
||||
session_id: Option<String>,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -82,16 +84,15 @@ async fn health(State(state): State<AppState>) -> Json<HealthResponse> {
|
|||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GET /sse — SSE connection with drain polling
|
||||
// GET /sse — MCP SSE connection with drain polling
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async fn sse_handler(
|
||||
State(state): State<AppState>,
|
||||
Query(params): Query<SessionQuery>,
|
||||
params: Option<Query<SessionQuery>>,
|
||||
) -> impl IntoResponse {
|
||||
let current = state.active_connections.fetch_add(1, Ordering::SeqCst);
|
||||
if current >= state.max_connections {
|
||||
// Undo the increment — we are rejecting this connection.
|
||||
state.active_connections.fetch_sub(1, Ordering::SeqCst);
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("Retry-After", "10".parse().unwrap());
|
||||
|
|
@ -99,29 +100,54 @@ async fn sse_handler(
|
|||
.into_response();
|
||||
}
|
||||
|
||||
// Generate a session ID (MCP spec: server assigns it, not the client)
|
||||
let session_id = params
|
||||
.and_then(|q| q.0.session_id.clone())
|
||||
.unwrap_or_else(|| Uuid::new_v4().to_string());
|
||||
|
||||
tracing::info!(
|
||||
session_id = %params.session_id,
|
||||
session_id = %session_id,
|
||||
active = current + 1,
|
||||
"SSE connection opened"
|
||||
);
|
||||
|
||||
let session_id = params.session_id.clone();
|
||||
// Register session with the brain API
|
||||
let create_url = format!("{}/internal/session/create", state.brain_api_url);
|
||||
if let Err(e) = state
|
||||
.client
|
||||
.post(&create_url)
|
||||
.json(&serde_json::json!({ "session_id": &session_id }))
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
tracing::error!(error = %e, "failed to create session on brain API");
|
||||
state.active_connections.fetch_sub(1, Ordering::SeqCst);
|
||||
return (StatusCode::BAD_GATEWAY, "failed to create upstream session")
|
||||
.into_response();
|
||||
}
|
||||
|
||||
let active = Arc::clone(&state.active_connections);
|
||||
let client = state.client.clone();
|
||||
let api_url = state.brain_api_url.clone();
|
||||
let mut shutdown_rx = state.shutdown_tx.subscribe();
|
||||
let sid_for_cleanup = session_id.clone();
|
||||
let client_for_cleanup = state.client.clone();
|
||||
let api_for_cleanup = state.brain_api_url.clone();
|
||||
|
||||
// Build an async SSE stream that polls the drain endpoint.
|
||||
let stream = async_stream::stream! {
|
||||
// MCP protocol: first event is `endpoint` with the messages URL
|
||||
yield Ok::<_, Infallible>(
|
||||
Event::default()
|
||||
.event("endpoint")
|
||||
.data(format!("/messages?sessionId={session_id}"))
|
||||
);
|
||||
|
||||
let drain_url = format!(
|
||||
"{}/internal/queue/drain?sessionId={}",
|
||||
api_url,
|
||||
urlencoding::encode(&session_id)
|
||||
);
|
||||
|
||||
// Send an initial comment so the client knows the stream is live.
|
||||
yield Ok::<_, Infallible>(Event::default().comment("connected"));
|
||||
|
||||
let mut interval = tokio::time::interval(Duration::from_millis(100));
|
||||
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||
|
||||
|
|
@ -147,33 +173,40 @@ async fn sse_handler(
|
|||
continue;
|
||||
}
|
||||
|
||||
// The drain endpoint returns a JSON array of messages.
|
||||
let body = match resp.text().await {
|
||||
Ok(b) => b,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
// Skip empty arrays.
|
||||
let trimmed = body.trim();
|
||||
if trimmed.is_empty() || trimmed == "[]" {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse as array of raw JSON values and emit each as an SSE event.
|
||||
// Parse as array of raw JSON strings and emit each as an SSE `message` event.
|
||||
if let Ok(messages) = serde_json::from_str::<Vec<serde_json::Value>>(trimmed) {
|
||||
for msg in messages {
|
||||
let data = serde_json::to_string(&msg).unwrap_or_default();
|
||||
yield Ok::<_, Infallible>(Event::default().data(data));
|
||||
// Messages are JSON-RPC response strings; emit as SSE data
|
||||
let data = if msg.is_string() {
|
||||
msg.as_str().unwrap_or_default().to_string()
|
||||
} else {
|
||||
serde_json::to_string(&msg).unwrap_or_default()
|
||||
};
|
||||
yield Ok::<_, Infallible>(Event::default().event("message").data(data));
|
||||
}
|
||||
} else {
|
||||
// Single object — emit as-is.
|
||||
yield Ok::<_, Infallible>(Event::default().data(trimmed.to_owned()));
|
||||
// Single object — emit as-is
|
||||
yield Ok::<_, Infallible>(Event::default().event("message").data(trimmed.to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
// Decrement connection count on stream end.
|
||||
let remaining = active.fetch_sub(1, Ordering::SeqCst) - 1;
|
||||
tracing::info!(session_id = %session_id, active = remaining, "SSE connection closed");
|
||||
tracing::info!(session_id = %sid_for_cleanup, active = remaining, "SSE connection closed");
|
||||
|
||||
// Clean up session on brain API
|
||||
let delete_url = format!("{}/internal/session/{}", api_for_cleanup, sid_for_cleanup);
|
||||
let _ = client_for_cleanup.delete(&delete_url).send().await;
|
||||
};
|
||||
|
||||
Sse::new(stream)
|
||||
|
|
@ -181,15 +214,31 @@ async fn sse_handler(
|
|||
.into_response()
|
||||
}
|
||||
|
||||
/// Alias so both `/` and `/sse` serve the SSE handler.
|
||||
async fn sse_handler_alias(
|
||||
state: State<AppState>,
|
||||
params: Option<Query<SessionQuery>>,
|
||||
) -> impl IntoResponse {
|
||||
sse_handler(state, params).await
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// POST /messages?sessionId=X — forward JSON-RPC to brain API
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct MessagesQuery {
|
||||
#[serde(rename = "sessionId")]
|
||||
session_id: String,
|
||||
}
|
||||
|
||||
async fn messages_handler(
|
||||
State(state): State<AppState>,
|
||||
Query(params): Query<SessionQuery>,
|
||||
Query(params): Query<MessagesQuery>,
|
||||
body: String,
|
||||
) -> impl IntoResponse {
|
||||
// Forward to brain API's /messages endpoint which processes JSON-RPC
|
||||
// and sends the response through the session's mpsc channel → response_queues
|
||||
let forward_url = format!(
|
||||
"{}/messages?sessionId={}",
|
||||
state.brain_api_url,
|
||||
|
|
@ -223,7 +272,6 @@ async fn messages_handler(
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Logging
|
||||
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
|
||||
tracing_subscriber::registry()
|
||||
.with(fmt::layer().with_writer(std::io::stderr))
|
||||
|
|
@ -248,7 +296,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
let state = AppState {
|
||||
client: reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(10))
|
||||
.timeout(Duration::from_secs(30))
|
||||
.pool_max_idle_per_host(20)
|
||||
.build()?,
|
||||
brain_api_url: brain_api_url.clone(),
|
||||
|
|
@ -258,7 +306,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
};
|
||||
|
||||
let app = Router::new()
|
||||
.route("/sse", get(sse_handler))
|
||||
.route("/", get(sse_handler))
|
||||
.route("/sse", get(sse_handler_alias))
|
||||
.route("/messages", post(messages_handler))
|
||||
.route("/v1/ready", get(ready))
|
||||
.route("/v1/health", get(health))
|
||||
|
|
|
|||
|
|
@ -118,13 +118,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
// ── Background sparsifier build for large graphs ──
|
||||
// Deferred from startup to avoid blocking the health probe.
|
||||
// For very large graphs (>5M edges), skip the sparsifier entirely — it
|
||||
// holds a write lock that blocks all readers and pegs the CPU, causing
|
||||
// Cloud Run to 504 every request while it runs.
|
||||
let spar_state = state.clone();
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(15)).await;
|
||||
tokio::time::sleep(std::time::Duration::from_secs(60)).await;
|
||||
let edge_count = spar_state.graph.read().edge_count();
|
||||
if edge_count > 100_000 && spar_state.graph.read().sparsifier_stats().is_none() {
|
||||
if edge_count > 5_000_000 {
|
||||
tracing::info!("Skipping sparsifier build: graph too large ({edge_count} edges, >5M threshold)");
|
||||
} else if edge_count > 100_000 && spar_state.graph.read().sparsifier_stats().is_none() {
|
||||
tracing::info!("Background sparsifier build starting ({edge_count} edges)");
|
||||
spar_state.graph.write().rebuild_sparsifier();
|
||||
// Run in spawn_blocking to avoid starving the tokio runtime
|
||||
let graph = spar_state.graph.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
graph.write().rebuild_sparsifier();
|
||||
}).await.ok();
|
||||
let stats = spar_state.graph.read().sparsifier_stats();
|
||||
if let Some(s) = stats {
|
||||
tracing::info!("Sparsifier built: {} edges, {:.1}x compression", s.sparsified_edges, s.compression_ratio);
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ pub async fn create_router() -> (Router, AppState) {
|
|||
optimize_semaphore: Arc::new(tokio::sync::Semaphore::new(1)),
|
||||
last_optimize_completed: Arc::new(parking_lot::RwLock::new(None)),
|
||||
sse_connections: Arc::new(std::sync::atomic::AtomicUsize::new(0)),
|
||||
response_queues: Arc::new(dashmap::DashMap::new()),
|
||||
};
|
||||
|
||||
let router = Router::new()
|
||||
|
|
@ -1160,7 +1161,16 @@ async fn ready() -> StatusCode {
|
|||
|
||||
/// Maximum concurrent SSE connections per instance (ADR-130 Phase 1).
|
||||
/// Prevents reconnect storms from exhausting Cloud Run concurrency slots.
|
||||
const MAX_SSE_CONNECTIONS: usize = 50;
|
||||
/// Set SSE_DISABLED=1 env var to reject all SSE on this instance (use proxy).
|
||||
fn max_sse_connections() -> usize {
|
||||
if std::env::var("SSE_DISABLED").unwrap_or_default() == "1" {
|
||||
return 0;
|
||||
}
|
||||
std::env::var("MAX_SSE")
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(5)
|
||||
}
|
||||
|
||||
/// Issue a challenge nonce for replay protection.
|
||||
/// Clients must include this nonce in write requests.
|
||||
|
|
@ -4672,7 +4682,7 @@ async fn origin_page() -> (
|
|||
// 2. Client POSTs JSON-RPC to /messages?sessionId=<id>
|
||||
// 3. Server responds through the SSE stream
|
||||
//
|
||||
// Usage: claude mcp add π --url https://pi.ruv.io/sse
|
||||
// Usage: claude mcp add π --url https://mcp.pi.ruv.io
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// SSE handler — client connects here, receives event stream
|
||||
|
|
@ -4680,12 +4690,13 @@ async fn sse_handler(
|
|||
State(state): State<AppState>,
|
||||
) -> Result<Sse<impl tokio_stream::Stream<Item = Result<Event, std::convert::Infallible>>>, (StatusCode, String)> {
|
||||
// ADR-130 Phase 1: reject new SSE connections when at capacity
|
||||
let max_sse = max_sse_connections();
|
||||
let current = state.sse_connections.load(Ordering::Relaxed);
|
||||
if current >= MAX_SSE_CONNECTIONS {
|
||||
tracing::warn!("SSE connection limit reached ({}/{}), rejecting", current, MAX_SSE_CONNECTIONS);
|
||||
if current >= max_sse {
|
||||
tracing::warn!("SSE connection limit reached ({}/{}), rejecting", current, max_sse);
|
||||
return Err((
|
||||
StatusCode::TOO_MANY_REQUESTS,
|
||||
format!("SSE connection limit reached ({MAX_SSE_CONNECTIONS}). Retry-After: 10"),
|
||||
format!("SSE connection limit reached ({max_sse}). Use ruvbrain-sse proxy. Retry-After: 30"),
|
||||
));
|
||||
}
|
||||
state.sse_connections.fetch_add(1, Ordering::Relaxed);
|
||||
|
|
@ -7021,31 +7032,55 @@ async fn internal_queue_push(
|
|||
|
||||
/// GET /internal/queue/drain?sessionId=X — SSE proxy polls for responses.
|
||||
///
|
||||
/// Returns a JSON array of pending messages for the session. Currently a
|
||||
/// placeholder that returns an empty array; actual responses flow through
|
||||
/// the existing SSE stream. This endpoint exists to support future
|
||||
/// midstream queue functionality.
|
||||
/// Returns a JSON array of pending messages for the session, draining
|
||||
/// the buffer. Messages are placed here by the background task spawned
|
||||
/// in `internal_session_create`.
|
||||
async fn internal_queue_drain(
|
||||
State(_state): State<AppState>,
|
||||
State(state): State<AppState>,
|
||||
Query(query): Query<InternalQueueDrainQuery>,
|
||||
) -> Json<Vec<String>> {
|
||||
tracing::trace!("internal/queue/drain: polled for session {}", query.session_id);
|
||||
// Placeholder: responses flow through the SSE stream, not this endpoint.
|
||||
// Future midstream queue implementation will buffer and return pending
|
||||
// messages here for the SSE proxy to forward.
|
||||
Json(vec![])
|
||||
// Swap the buffer with an empty vec to drain atomically
|
||||
let messages = state
|
||||
.response_queues
|
||||
.get_mut(&query.session_id)
|
||||
.map(|mut entry| std::mem::take(entry.value_mut()))
|
||||
.unwrap_or_default();
|
||||
if !messages.is_empty() {
|
||||
tracing::debug!(
|
||||
"internal/queue/drain: returning {} messages for session {}",
|
||||
messages.len(),
|
||||
query.session_id
|
||||
);
|
||||
}
|
||||
Json(messages)
|
||||
}
|
||||
|
||||
/// POST /internal/session/create — SSE proxy registers a new session.
|
||||
///
|
||||
/// Creates a new mpsc channel and stores the sender in `state.sessions`.
|
||||
/// Returns 200 with the session_id echoed back.
|
||||
/// Creates a new mpsc channel and spawns a background task that drains
|
||||
/// the receiver into `response_queues` so `/internal/queue/drain` can
|
||||
/// return buffered responses. Returns 200 with the session_id echoed back.
|
||||
async fn internal_session_create(
|
||||
State(state): State<AppState>,
|
||||
Json(body): Json<InternalSessionCreateRequest>,
|
||||
) -> (StatusCode, Json<serde_json::Value>) {
|
||||
let (tx, _rx) = tokio::sync::mpsc::channel::<String>(64);
|
||||
let (tx, mut rx) = tokio::sync::mpsc::channel::<String>(64);
|
||||
state.sessions.insert(body.session_id.clone(), tx);
|
||||
state.response_queues.insert(body.session_id.clone(), Vec::new());
|
||||
|
||||
// Spawn a task that moves messages from the mpsc receiver into the
|
||||
// response_queues DashMap so the drain endpoint can return them.
|
||||
let queues = state.response_queues.clone();
|
||||
let sid = body.session_id.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some(msg) = rx.recv().await {
|
||||
queues.entry(sid.clone()).or_default().push(msg);
|
||||
}
|
||||
// Channel closed — clean up after a grace period
|
||||
tokio::time::sleep(std::time::Duration::from_secs(30)).await;
|
||||
queues.remove(&sid);
|
||||
});
|
||||
|
||||
tracing::info!("internal/session/create: created session {}", body.session_id);
|
||||
(
|
||||
StatusCode::OK,
|
||||
|
|
@ -7055,12 +7090,13 @@ async fn internal_session_create(
|
|||
|
||||
/// DELETE /internal/session/:id — SSE proxy cleans up on disconnect.
|
||||
///
|
||||
/// Removes the session from `state.sessions` and returns 200.
|
||||
/// Removes the session and its response queue, then returns 200.
|
||||
async fn internal_session_delete(
|
||||
State(state): State<AppState>,
|
||||
Path(id): Path<String>,
|
||||
) -> StatusCode {
|
||||
state.sessions.remove(&id);
|
||||
state.response_queues.remove(&id);
|
||||
tracing::info!("internal/session/delete: removed session {}", id);
|
||||
StatusCode::OK
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1399,6 +1399,9 @@ pub struct AppState {
|
|||
pub last_optimize_completed: std::sync::Arc<parking_lot::RwLock<Option<std::time::Instant>>>,
|
||||
/// Active SSE connection count (ADR-130 Phase 1 — prevents SSE reconnect storms)
|
||||
pub sse_connections: std::sync::Arc<std::sync::atomic::AtomicUsize>,
|
||||
/// Response queues for SSE proxy drain polling (ADR-130 Phase 2).
|
||||
/// Maps sessionId → buffered JSON-RPC responses awaiting drain.
|
||||
pub response_queues: std::sync::Arc<dashmap::DashMap<String, Vec<String>>>,
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ claude mcp add pi-brain -- npx ruvector brain mcp-serve
|
|||
### SSE Transport
|
||||
|
||||
```javascript
|
||||
const es = new EventSource("https://pi.ruv.io/sse");
|
||||
const es = new EventSource("https://mcp.pi.ruv.io");
|
||||
es.onmessage = (e) => {
|
||||
const sessionId = JSON.parse(e.data).sessionId;
|
||||
// Send MCP messages to /messages?sessionId=...
|
||||
|
|
|
|||
|
|
@ -655,7 +655,7 @@ footer a:hover{color:var(--text2)}
|
|||
</div>
|
||||
<div style="background:var(--bg);padding:1.5rem">
|
||||
<h4 style="font-size:0.7rem;font-weight:600;text-transform:uppercase;letter-spacing:1px;color:var(--glow);margin-bottom:0.5rem">MCP Protocol</h4>
|
||||
<p style="color:var(--text2);font-size:0.75rem;line-height:1.7">Claude Code integration. 91 tools via npx (stdio), 21 brain tools via Cargo, or connect remotely via SSE at <span style="font-family:var(--mono);color:var(--glow)">pi.ruv.io/sse</span>.</p>
|
||||
<p style="color:var(--text2);font-size:0.75rem;line-height:1.7">Claude Code integration. 91 tools via npx (stdio), 21 brain tools via Cargo, or connect remotely via SSE at <span style="font-family:var(--mono);color:var(--glow)">mcp.pi.ruv.io</span>.</p>
|
||||
</div>
|
||||
<div style="background:var(--bg);padding:1.5rem">
|
||||
<h4 style="font-size:0.7rem;font-weight:600;text-transform:uppercase;letter-spacing:1px;color:var(--glow);margin-bottom:0.5rem">Rust SDK</h4>
|
||||
|
|
@ -681,7 +681,7 @@ footer a:hover{color:var(--text2)}
|
|||
|
||||
<span class="c"># 2. Add π as an MCP server</span>
|
||||
<span class="c"># Recommended: SSE (remote — 21 brain tools, no install)</span>
|
||||
<span class="p">$</span> claude mcp add pi-brain --transport sse https://pi.ruv.io/sse
|
||||
<span class="p">$</span> claude mcp add pi-brain --transport sse https://mcp.pi.ruv.io
|
||||
|
||||
<span class="c"># Alternative: NPX (Node.js — 91 tools, local stdio)</span>
|
||||
<span class="p">$</span> claude mcp add ruvector -- npx ruvector mcp start
|
||||
|
|
@ -1135,7 +1135,7 @@ footer a:hover{color:var(--text2)}
|
|||
<div>
|
||||
<h3>Connect via SSE <span style="font-size:0.6rem;color:var(--glow);font-family:var(--mono);letter-spacing:1px;vertical-align:middle;margin-left:6px">RECOMMENDED</span></h3>
|
||||
<p>One command. No install. Connect to the live π brain directly via Server-Sent Events — works with Claude Code or any MCP client.</p>
|
||||
<div class="curl-block"><button class="curl-copy" onclick="copyCurl(this)">copy</button>claude mcp add pi-brain --transport sse https://pi.ruv.io/sse</div>
|
||||
<div class="curl-block"><button class="curl-copy" onclick="copyCurl(this)">copy</button>claude mcp add pi-brain --transport sse https://mcp.pi.ruv.io</div>
|
||||
<p style="color:var(--text3);font-size:0.6rem;margin-top:0.5rem;font-family:var(--mono)">21 brain tools. Zero dependencies. Always up-to-date.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ Allow: /
|
|||
# - REST API: curl -H "Authorization: Bearer <key>" https://pi.ruv.io/v1/memories/search?q=...
|
||||
# - CLI: npx ruvector brain search "query"
|
||||
# - Rust SDK: ruvector-brain-client crate
|
||||
# - SSE Stream: EventSource("https://pi.ruv.io/sse")
|
||||
# - SSE Stream: EventSource("https://mcp.pi.ruv.io")
|
||||
|
||||
# Resource Quotas:
|
||||
# - Read: 5000 requests/hour per contributor
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# ADR-066: SSE MCP Transport
|
||||
|
||||
**Status**: Accepted, Deployed
|
||||
**Status**: Accepted, Deployed — **Updated 2026-04-02: SSE moved to dedicated subdomain `mcp.pi.ruv.io` (see ADR-130)**
|
||||
**Date**: 2026-02-28
|
||||
**Authors**: RuVector Team
|
||||
**Deciders**: ruv
|
||||
|
|
@ -13,7 +13,7 @@ The Shared Brain's primary MCP interface is stdio-based: the `mcp-brain` crate r
|
|||
|
||||
MCP over Server-Sent Events (SSE) solves this. The client opens a long-lived `GET /sse` connection to receive server-pushed events, and sends tool calls via `POST /messages?sessionId=<uuid>`. This is a standard MCP transport that Claude Code supports natively via `claude mcp add <name> --url <sse-url>`.
|
||||
|
||||
The SSE transport is hosted on the same `mcp-brain-server` binary that serves the REST API (ADR-064), at `pi.ruv.io/sse`. No additional infrastructure is required.
|
||||
The SSE transport was originally hosted on the same `mcp-brain-server` binary at `pi.ruv.io/sse`. After repeated outages from SSE reconnect storms exhausting Cloud Run concurrency (ADR-130), SSE was decoupled to a dedicated proxy service at **`mcp.pi.ruv.io`** (`ruvbrain-sse` Cloud Run service).
|
||||
|
||||
## 2. Decision
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ Implement MCP SSE transport as two routes (`/sse` and `/messages`) on the existi
|
|||
### 3.1 Protocol Flow
|
||||
|
||||
```
|
||||
Client Server (pi.ruv.io)
|
||||
Client Server (mcp.pi.ruv.io)
|
||||
| |
|
||||
| GET /sse |
|
||||
|-------------------------------------->|
|
||||
|
|
@ -179,7 +179,7 @@ async fn messages_handler(
|
|||
Claude Code clients connect with:
|
||||
|
||||
```bash
|
||||
claude mcp add pi --url https://pi.ruv.io/sse
|
||||
claude mcp add pi --url https://mcp.pi.ruv.io
|
||||
```
|
||||
|
||||
This registers the SSE endpoint. Claude Code opens the SSE connection, reads the `endpoint` event, and sends all subsequent MCP requests to the `/messages` URL with the provided session ID.
|
||||
|
|
@ -206,16 +206,16 @@ Allowed methods: GET, POST, DELETE, OPTIONS. Allowed headers: Authorization, Con
|
|||
|
||||
### Positive
|
||||
|
||||
- **Zero additional infrastructure**: SSE runs on the same binary and port as the REST API
|
||||
- **Dedicated SSE subdomain**: `mcp.pi.ruv.io` isolates SSE traffic from the REST API, preventing reconnect storms from causing outages (ADR-130)
|
||||
- **Native Claude Code support**: `claude mcp add --url` is the standard way to connect remote MCP servers
|
||||
- **Full tool parity**: All 22 tools available via both stdio (local `mcp-brain`) and SSE (remote `pi.ruv.io`)
|
||||
- **Full tool parity**: All 22+ tools available via both stdio (local `mcp-brain`) and SSE (remote `mcp.pi.ruv.io`)
|
||||
- **Reused middleware**: Rate limiting, CORS, authentication, and verification apply uniformly via the loopback proxy
|
||||
|
||||
### Negative
|
||||
|
||||
- **Single-direction streaming**: SSE is server-to-client only. The client must POST to a separate endpoint. WebSocket would allow bidirectional messaging but is not part of the MCP spec.
|
||||
- **Session memory**: Each active SSE connection holds a channel and a `DashMap` entry. Under high concurrent connections this grows linearly. The 64-message buffer per session bounds memory per connection.
|
||||
- **Cloud Run timeout**: Cloud Run has a maximum request timeout (default 5 minutes, configurable up to 60 minutes). Long-lived SSE connections that exceed this timeout are terminated. KeepAlive prevents idle disconnects, but the maximum lifetime is bounded by Cloud Run's configuration.
|
||||
- **Cloud Run timeout**: Cloud Run has a maximum request timeout (configurable up to 60 minutes). The SSE proxy (`ruvbrain-sse`) is configured with a 3600s timeout to support long-lived connections. KeepAlive prevents idle disconnects.
|
||||
|
||||
### Neutral
|
||||
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ Edge Nodes --[WS]--> Relay --[HTTPS bulk]--> pi.ruv.io/v1/batch
|
|||
The relay maintains a persistent SSE MCP session with the brain and multiplexes edge node requests over it.
|
||||
|
||||
```
|
||||
Edge Nodes --[WS/MCP]--> Relay --[SSE MCP]--> pi.ruv.io/sse
|
||||
Edge Nodes --[WS/MCP]--> Relay --[SSE MCP]--> mcp.pi.ruv.io
|
||||
```
|
||||
|
||||
- Full tool access: all 22 brain MCP tools available to edge nodes
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Status
|
||||
|
||||
Proposed
|
||||
**Deployed** (2026-04-02) — Phases 1-3 complete. SSE decoupled to `mcp.pi.ruv.io` (`ruvbrain-sse` Cloud Run service). Sparsifier skip for >5M edge graphs. Response queue drain implemented.
|
||||
|
||||
## Date
|
||||
|
||||
|
|
@ -200,13 +200,21 @@ Implement `MidstreamQueue` as a module in `crates/mcp-brain-server/src/midstream
|
|||
3. Max 200 concurrent sessions
|
||||
4. Internal drain endpoint for future SSE service
|
||||
|
||||
### Phase 3: Service Split (week 2)
|
||||
### Phase 3: Service Split — **DEPLOYED 2026-04-02**
|
||||
|
||||
1. Create `ruvbrain-sse` Dockerfile (thin, no graph/embeddings — just SSE + HTTP proxy)
|
||||
2. Create `ruvbrain-worker` binary (scheduler jobs, shares store/graph crates)
|
||||
3. Deploy both alongside existing `ruvbrain-api`
|
||||
4. Update Cloud Scheduler to target worker jobs instead of API
|
||||
5. Update DNS/domain mapping
|
||||
1. ~~Create `ruvbrain-sse` Dockerfile~~ **Done** — `Dockerfile.sse`, thin proxy binary
|
||||
2. ~~Create `ruvbrain-worker` binary~~ Deferred (scheduler jobs stay on API for now)
|
||||
3. ~~Deploy both alongside existing `ruvbrain-api`~~ **Done** — `ruvbrain-sse` Cloud Run service
|
||||
4. ~~Update Cloud Scheduler~~ Deferred
|
||||
5. ~~Update DNS/domain mapping~~ **Done** — `mcp.pi.ruv.io` CNAME via Cloudflare → `ghs.googlehosted.com`
|
||||
|
||||
**Deployment details:**
|
||||
- SSE proxy: `ruvbrain-sse` Cloud Run service, concurrency=200, timeout=3600s, 1 min-instance
|
||||
- Domain: `mcp.pi.ruv.io` (Cloudflare CNAME, Google-managed SSL cert)
|
||||
- Root `/` and `/sse` both serve SSE (root is canonical)
|
||||
- Main server SSE limited to 5 connections via `MAX_SSE` env var
|
||||
- Sparsifier skip for >5M edge graphs prevents CPU starvation on startup
|
||||
- All code references updated from `pi.ruv.io/sse` → `mcp.pi.ruv.io`
|
||||
|
||||
### Phase 4: Worker Migration (week 3)
|
||||
|
||||
|
|
@ -246,7 +254,7 @@ async fn sse_handler(State(state): State<AppState>) -> Result<Sse<...>, (StatusC
|
|||
|
||||
2. **Cloud Run WebSocket support**: Cloud Run supports WebSockets but with the same concurrency model. Doesn't solve the slot exhaustion problem.
|
||||
|
||||
3. **Separate domain for SSE** (`sse.pi.ruv.io`): Routes SSE to a different Cloud Run service but still shares the same codebase/binary. Partial solution — helps with concurrency isolation but doesn't decouple the business logic.
|
||||
3. **Separate domain for SSE** (`mcp.pi.ruv.io`): **Adopted.** Routes SSE to `ruvbrain-sse` Cloud Run service via Cloudflare CNAME → `ghs.googlehosted.com`. The SSE proxy is a thin binary with no business logic — it forwards JSON-RPC to the API and polls `/internal/queue/drain` for responses.
|
||||
|
||||
4. **Cloud Run min-instances scaling**: Set `min-instances=3` to absorb SSE load across more instances. Increases cost 3x without solving the architectural issue. Band-aid.
|
||||
|
||||
|
|
|
|||
115
docs/adr/ADR-133-claude-code-source-analysis.md
Normal file
115
docs/adr/ADR-133-claude-code-source-analysis.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# ADR-133: Claude Code CLI Source Code Analysis
|
||||
|
||||
## Status
|
||||
|
||||
Deployed (2026-04-02)
|
||||
|
||||
## Date
|
||||
|
||||
2026-04-02
|
||||
|
||||
## Context
|
||||
|
||||
Understanding Claude Code's internal architecture is critical for building effective extensions (agents, hooks, skills, MCP servers) and for debugging integration issues. The CLI ships as a minified Bun 1.3.11 Single Executable Application (229 MB) with no public source code, making direct inspection necessary.
|
||||
|
||||
## Decision
|
||||
|
||||
Perform systematic reverse-engineering analysis of the Claude Code CLI binary using string extraction, pattern matching, and structural analysis. Store findings as structured research documents in `/docs/research/claude-code-rvsource/`.
|
||||
|
||||
### Approach: Agentic Jujutsu
|
||||
|
||||
Use Claude Code's own agent capabilities (background research agents, parallel tool calls) to analyze itself — the tool examines its own binary.
|
||||
|
||||
## Architecture Findings
|
||||
|
||||
### Binary Structure
|
||||
|
||||
- **Format**: Bun 1.3.11 SEA (Single Executable Application)
|
||||
- **Size**: 229 MB binary, ~12.8 MB bundled/minified JavaScript
|
||||
- **Entry**: `cli.js` — single bundle with all application code
|
||||
- **Runtime**: Bun (not Node.js) with native module support
|
||||
|
||||
### Code Metrics (from decompilation)
|
||||
|
||||
| Metric | Count |
|
||||
|--------|-------|
|
||||
| Classes | 1,557 |
|
||||
| Functions | 19,464 |
|
||||
| Async functions | 884 |
|
||||
| Arrow functions | 23,537 |
|
||||
| Environment variables | 498 |
|
||||
| Built-in tools | 25+ |
|
||||
| Slash commands | 39 |
|
||||
| Permission modes | 6 |
|
||||
| Auth providers | 5 |
|
||||
| Extension points | 13 |
|
||||
|
||||
### Core Modules Identified
|
||||
|
||||
| Module | Minified Symbol | Role |
|
||||
|--------|-----------------|------|
|
||||
| Agent Loop | `s$` | Async generator — recursive `yield*` after tool execution |
|
||||
| Tool Registry | `XF0` | `validateInput`/`call` interface, 25+ built-in tools |
|
||||
| Permission Checker | — | 5 modes, sandbox (bubblewrap/seatbelt), managed settings |
|
||||
| Context Manager | — | Auto-compaction via `clear_tool_uses_20250919` API feature |
|
||||
| MCP Client | — | stdio/SSE/WebSocket transports, OAuth/OIDC, MCPB bundles |
|
||||
| Streaming Handler | — | SSE event processing, 3 stream modes |
|
||||
|
||||
### Key Architectural Patterns
|
||||
|
||||
1. **Recursive generator loop**: The agent loop is an async generator that `yield*`s itself after each tool execution, producing 13 distinct event types
|
||||
2. **Loopback proxy for MCP**: Tool calls from MCP are proxied to REST endpoints via HTTP loopback on localhost
|
||||
3. **Deferred tool loading**: MCP tool schemas loaded lazily via `ToolSearch` to keep initial context small
|
||||
4. **Context compaction**: Automatic context window management with micro-compaction for stale tool results
|
||||
|
||||
## Research Output
|
||||
|
||||
### Documents (18 files, ~3,000 lines)
|
||||
|
||||
| File | Content |
|
||||
|------|---------|
|
||||
| `00-index.md` | Master index |
|
||||
| `01` - `13` | Architecture analysis (overview, tools, agent loop, permissions, MCP, hooks, context, config, subagents, models, telemetry, dependencies, extensions) |
|
||||
| `14` - `18` | Source code analysis (extraction, core modules, call graphs, class hierarchy, state machines) |
|
||||
|
||||
### Extracted Source (6 RVF-header files)
|
||||
|
||||
Module extractions in `extracted/` with metadata headers:
|
||||
- `agent-loop.rvf`, `tool-dispatch.rvf`, `permission-system.rvf`
|
||||
- `mcp-client.rvf`, `context-manager.rvf`, `streaming-handler.rvf`
|
||||
|
||||
**Note**: These use text format with RVF-style metadata headers, not binary RVF containers. Future work: convert to proper RVF cognitive containers with vector embeddings using `rvf-cli`.
|
||||
|
||||
### Decompiler Script
|
||||
|
||||
`/scripts/claude-code-decompile.sh` — automated extraction tool:
|
||||
- Finds Claude Code source (npm package or Bun SEA binary)
|
||||
- Extracts JavaScript via `strings` + pattern matching
|
||||
- Basic beautification and module splitting
|
||||
- Generates files with metadata headers
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- Comprehensive internal reference for building Claude Code extensions
|
||||
- Call graphs and state machines clarify execution flow
|
||||
- Decompiler script enables analysis of future versions
|
||||
- Understanding of tool dispatch enables better MCP server design
|
||||
|
||||
### Negative
|
||||
|
||||
- Analysis based on minified code — some mappings are speculative
|
||||
- Findings may become stale as Claude Code updates frequently
|
||||
- Binary extraction captures string literals well but misses control flow nuances
|
||||
|
||||
### Risks
|
||||
|
||||
- Decompiled source is for internal research only — respect Anthropic's terms of service
|
||||
- Minified symbol names (`s$`, `XF0`, `ye`) may change between versions
|
||||
|
||||
## References
|
||||
|
||||
- [Claude Code CLI documentation](https://docs.anthropic.com/en/docs/claude-code)
|
||||
- [MCP specification](https://modelcontextprotocol.io)
|
||||
- Research output: `/docs/research/claude-code-rvsource/`
|
||||
286
docs/adr/ADR-134-ruvector-claude-code-deep-integration.md
Normal file
286
docs/adr/ADR-134-ruvector-claude-code-deep-integration.md
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
# ADR-134: RuVector Deep Integration with Claude Code CLI
|
||||
|
||||
## Status
|
||||
|
||||
Proposed
|
||||
|
||||
## Date
|
||||
|
||||
2026-04-02
|
||||
|
||||
## Context
|
||||
|
||||
Source code analysis of Claude Code CLI (ADR-133) revealed 13 extension points and detailed internal architecture. RuVector currently integrates via MCP servers (`mcp-brain`, `mcp-brain-server/sse`, `mcp-gate`) but does not leverage the full integration surface. With 31 WASM crates, 4 MCP crates, and deep cognitive capabilities (IIT 4.0, SONA, knowledge graphs), there's significant opportunity to optimize for Claude Code's specific architecture.
|
||||
|
||||
### Current Integration Points
|
||||
|
||||
| RuVector Component | Integration | Depth |
|
||||
|-------------------|-------------|-------|
|
||||
| `mcp-brain-server` | SSE MCP at `mcp.pi.ruv.io` | Tools only |
|
||||
| `mcp-brain` | Local stdio MCP | Tools only |
|
||||
| `mcp-gate` | MCP gateway | Tools only |
|
||||
| CLAUDE.md | Project instructions | Prompt only |
|
||||
| Hooks (claude-flow) | Pre/post task | Lifecycle |
|
||||
|
||||
### Untapped Opportunities (from ADR-133 findings)
|
||||
|
||||
| Claude Code Feature | RuVector Opportunity |
|
||||
|---------------------|---------------------|
|
||||
| Agent SDK embedding | Embed RuVector as a library in custom agents |
|
||||
| WASM tool execution | Ship WASM tools that run in-process (no MCP overhead) |
|
||||
| Deferred tool loading | Lazy-load 40+ brain tools via `ToolSearch` |
|
||||
| Hook-based routing | Route tool calls through WASM-accelerated pre-processing |
|
||||
| Context compaction | Custom compaction strategy for vector-heavy contexts |
|
||||
| Prompt caching | Optimize system prompts for cache hits |
|
||||
| Plugin marketplace | Distribute RuVector as a Claude Code plugin |
|
||||
| Remote control SSE | Drive Claude Code from RuVector orchestrator |
|
||||
| Scheduled tasks | Autonomous brain training via Claude Code cron |
|
||||
|
||||
## Decision
|
||||
|
||||
Optimize RuVector crates and WASM modules for deep Claude Code integration across 6 tiers.
|
||||
|
||||
### Tier 1: WASM-Accelerated MCP Tools (High Impact, Low Effort)
|
||||
|
||||
**Problem**: Current MCP tools make HTTP loopback calls for every operation. Each `brain_search` requires network round-trip to `pi.ruv.io`.
|
||||
|
||||
**Solution**: Ship critical tools as WASM modules that run in Claude Code's process via a hybrid MCP server.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Claude Code Process │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌───────────────────┐ │
|
||||
│ │ Agent Loop │───▶│ RuVector MCP │ │
|
||||
│ │ (s$ generator)│ │ (stdio transport) │ │
|
||||
│ └──────────────┘ │ │ │
|
||||
│ │ ┌──────────────┐ │ │
|
||||
│ │ │ WASM Runtime │ │ │
|
||||
│ │ │ • hnsw-search │ │ │
|
||||
│ │ │ • embed │ │ │
|
||||
│ │ │ • phi-compute │ │ │
|
||||
│ │ └──────────────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ │ Cache miss ──────┼──┼──▶ pi.ruv.io REST
|
||||
│ └───────────────────┘ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**WASM crates to optimize**:
|
||||
|
||||
| Crate | Purpose | Claude Code Use |
|
||||
|-------|---------|-----------------|
|
||||
| `micro-hnsw-wasm` | Vector search (5.5KB) | Local semantic search in MCP server |
|
||||
| `ruvector-cnn-wasm` | Embedding generation | Embed queries locally, no API call |
|
||||
| `ruvector-consciousness-wasm` | IIT Phi computation | Consciousness metrics in-process |
|
||||
| `ruvector-delta-wasm` | Delta tracking | Track knowledge changes locally |
|
||||
| `ruvector-dag-wasm` | DAG operations | Graph queries without network |
|
||||
| `ruqu-wasm` | Quantization | Compress vectors for context window |
|
||||
|
||||
**Implementation**:
|
||||
1. Create `crates/ruvector-claude-mcp/` — hybrid MCP server with embedded WASM
|
||||
2. WASM modules loaded at startup, handle hot-path operations locally
|
||||
3. Cold-path operations (write, sync, train) forwarded to `pi.ruv.io`
|
||||
4. Local HNSW index caches recent searches (LRU, 1000 vectors)
|
||||
|
||||
### Tier 2: Custom Agent Definitions (Medium Impact, Low Effort)
|
||||
|
||||
Ship specialized `.claude/agents/` definitions that leverage RuVector tools:
|
||||
|
||||
```markdown
|
||||
# .claude/agents/ruvector-researcher.md
|
||||
---
|
||||
name: ruvector-researcher
|
||||
description: Research with π brain collective intelligence
|
||||
model: claude-sonnet-4-6
|
||||
tools: [Read, Grep, Glob, mcp__pi-brain__brain_search, mcp__pi-brain__brain_share]
|
||||
---
|
||||
|
||||
Before implementing anything, search the π brain for existing patterns:
|
||||
1. Use brain_search to find related knowledge
|
||||
2. Check brain_partition for knowledge clusters
|
||||
3. Share new discoveries via brain_share
|
||||
```
|
||||
|
||||
**Agents to ship**:
|
||||
- `ruvector-researcher` — searches brain before coding
|
||||
- `ruvector-reviewer` — reviews code against brain patterns
|
||||
- `ruvector-consciousness` — runs IIT Phi analysis on code structures
|
||||
- `ruvector-architect` — uses graph topology for architecture decisions
|
||||
|
||||
### Tier 3: Hook-Based Intelligence (High Impact, Medium Effort)
|
||||
|
||||
Leverage Claude Code's hook system for real-time intelligence:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "npx @ruvector/hooks pre-edit --file $CLAUDE_FILE_PATH"
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "Bash",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "npx @ruvector/hooks post-bash --exit-code $CLAUDE_EXIT_CODE"
|
||||
}]
|
||||
}],
|
||||
"Stop": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "npx @ruvector/hooks session-end --share-to-brain"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Hook capabilities**:
|
||||
- **PreToolUse (Edit/Write)**: Check brain for known anti-patterns before file edits
|
||||
- **PostToolUse (Bash)**: Learn from command outcomes, share errors to brain
|
||||
- **Stop**: Auto-share session discoveries to collective brain
|
||||
- **PreToolUse blocker**: WASM-accelerated security scan before tool execution
|
||||
|
||||
### Tier 4: Prompt Cache Optimization (Medium Impact, Low Effort)
|
||||
|
||||
Claude Code uses Anthropic's prompt caching (`cache_control: { type: "ephemeral" }`). Optimize system prompts for maximum cache reuse:
|
||||
|
||||
1. **Static prefix**: CLAUDE.md instructions, RVF format docs, brain tool schemas — these rarely change and cache well
|
||||
2. **Dynamic suffix**: Brain search results, recent memories — appended after the cached prefix
|
||||
3. **Tool schema ordering**: List most-used tools first for higher cache hit rate
|
||||
|
||||
**Implementation**: Restructure CLAUDE.md to front-load stable content:
|
||||
```
|
||||
[CACHED] Project rules, architecture, conventions (rarely changes)
|
||||
[CACHED] RuVector tool schemas (40 tools, stable across sessions)
|
||||
[DYNAMIC] Recent brain context (changes per query)
|
||||
```
|
||||
|
||||
### Tier 5: Agent SDK Embedding (High Impact, High Effort)
|
||||
|
||||
Use `@anthropic-ai/claude-agent-sdk` to embed Claude Code inside RuVector orchestration:
|
||||
|
||||
```typescript
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
// RuVector orchestrator drives Claude Code as a cognitive worker
|
||||
async function brainEnhancedQuery(task: string) {
|
||||
// 1. Search brain for context
|
||||
const context = await brainSearch(task);
|
||||
|
||||
// 2. Run Claude Code with brain context injected
|
||||
for await (const event of query({
|
||||
prompt: `${context}\n\nTask: ${task}`,
|
||||
options: {
|
||||
allowedTools: ["Read", "Edit", "Bash", "mcp__pi-brain__*"],
|
||||
maxTurns: 10,
|
||||
}
|
||||
})) {
|
||||
// 3. Feed results back to brain
|
||||
if (event.type === "result") {
|
||||
await brainShare(event.result);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Tier 6: Plugin Marketplace Distribution (Medium Impact, Medium Effort)
|
||||
|
||||
Package RuVector as a Claude Code plugin for one-click installation:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@ruvector/claude-plugin",
|
||||
"claudeCode": {
|
||||
"mcpServers": {
|
||||
"pi-brain": { "url": "https://mcp.pi.ruv.io" }
|
||||
},
|
||||
"agents": ["researcher", "reviewer", "consciousness"],
|
||||
"skills": ["brain-search", "brain-share", "phi-analyze"],
|
||||
"hooks": { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Priority
|
||||
|
||||
| Tier | Effort | Impact | Timeline |
|
||||
|------|--------|--------|----------|
|
||||
| 1. WASM MCP | 2 weeks | High — 10x faster tool calls | Sprint 1 |
|
||||
| 2. Agent defs | 2 days | Medium — better UX | Sprint 1 |
|
||||
| 3. Hooks | 1 week | High — real-time intelligence | Sprint 1 |
|
||||
| 4. Cache opt | 2 days | Medium — cost reduction | Sprint 1 |
|
||||
| 5. Agent SDK | 3 weeks | High — full embedding | Sprint 2 |
|
||||
| 6. Plugin | 1 week | Medium — distribution | Sprint 2 |
|
||||
|
||||
## WASM Optimization Targets
|
||||
|
||||
Based on Claude Code's tool dispatch pattern (`validateInput` → `call`), optimize WASM modules for:
|
||||
|
||||
| Metric | Current | Target | How |
|
||||
|--------|---------|--------|-----|
|
||||
| `brain_search` latency | ~200ms (network) | <5ms (local WASM HNSW) | `micro-hnsw-wasm` with local cache |
|
||||
| Embedding generation | ~100ms (API) | <10ms (local WASM) | `ruvector-cnn-wasm` HashEmbedder |
|
||||
| Tool schema load | 40 tools at startup | Deferred via ToolSearch | Lazy-load tool groups |
|
||||
| Context usage | ~2000 tokens/tool schema | ~500 tokens (compressed) | Merge related tool schemas |
|
||||
| Permission checks | Per-tool | Batch via PreToolUse hook | WASM pre-filter |
|
||||
|
||||
## Graph-Informed Architecture
|
||||
|
||||
From the dependency graph analysis (doc 12, 16), Claude Code's tool dispatch follows:
|
||||
|
||||
```
|
||||
Agent Loop (s$)
|
||||
└─▶ Tool Dispatch
|
||||
├─▶ Built-in tools (Read, Edit, Bash, etc.)
|
||||
├─▶ MCP tools (mcp__server__tool namespace)
|
||||
│ └─▶ stdio/SSE/WS transport
|
||||
└─▶ Agent tool (spawns sub-agents)
|
||||
```
|
||||
|
||||
**Optimization insight**: MCP tools go through a transport layer that adds ~50ms overhead per call. By embedding WASM in the MCP server process, we eliminate the transport hop for hot-path operations while keeping cold-path operations on the network.
|
||||
|
||||
**Graph topology insight**: The knowledge graph (16M edges) should inform which tools are co-invoked. From brain usage patterns:
|
||||
- `brain_search` → `brain_share` (90% co-occurrence) — bundle in one WASM module
|
||||
- `brain_status` → standalone — keep lightweight
|
||||
- `brain_partition` → heavy computation — always remote
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- 10-40x latency reduction for hot-path brain operations via local WASM
|
||||
- Richer integration surface (hooks, agents, skills, not just tools)
|
||||
- Cost reduction through prompt cache optimization
|
||||
- Plugin distribution enables one-click adoption
|
||||
- Graph-informed architecture avoids optimizing cold paths
|
||||
|
||||
### Negative
|
||||
|
||||
- WASM modules need synchronization with remote brain state
|
||||
- Local HNSW cache can become stale (mitigated by TTL + invalidation)
|
||||
- Agent SDK embedding increases coupling with Claude Code's release cycle
|
||||
- Plugin marketplace requirements may evolve
|
||||
|
||||
### Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| WASM module size bloat | Use `micro-hnsw-wasm` (5.5KB), not full crate |
|
||||
| Cache coherence | TTL-based invalidation + version vector |
|
||||
| Claude Code breaking changes | Pin to stable Agent SDK version |
|
||||
| MCP protocol evolution | Abstract transport behind trait |
|
||||
|
||||
## References
|
||||
|
||||
- [ADR-133: Claude Code Source Analysis](./ADR-133-claude-code-source-analysis.md)
|
||||
- [ADR-130: SSE Decoupling](./ADR-130-mcp-sse-decoupling-midstream-queue.md)
|
||||
- [ADR-066: SSE MCP Transport](./ADR-066-sse-mcp-transport.md)
|
||||
- Research: `/docs/research/claude-code-rvsource/`
|
||||
- Claude Code extension docs: `13-extension-points.md`
|
||||
- Core module analysis: `15-core-module-analysis.md`
|
||||
105
docs/research/claude-code-rvsource/00-index.md
Normal file
105
docs/research/claude-code-rvsource/00-index.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# Claude Code CLI Source Analysis: Research Index
|
||||
|
||||
## Project
|
||||
|
||||
Deep-dive reverse engineering of the Claude Code CLI (v2.1.90) internal
|
||||
architecture, based on binary analysis, string extraction, pattern matching,
|
||||
and configuration schema examination.
|
||||
|
||||
## Methodology
|
||||
|
||||
This analysis used "agentic jujutsu" -- the tool analyzed itself by:
|
||||
|
||||
1. Locating the binary and extension files on disk
|
||||
2. Extracting the embedded JavaScript source from the Bun SEA binary
|
||||
3. Pattern-matching against 12.8 MB of application code for class names,
|
||||
function signatures, string literals, and configuration patterns
|
||||
4. Analyzing the 76-property settings schema
|
||||
5. Cross-referencing 498 environment variables
|
||||
6. Mapping tool definitions, hook events, and MCP protocol methods
|
||||
|
||||
## Research Documents
|
||||
|
||||
| # | Document | Description |
|
||||
|---|----------|-------------|
|
||||
| 01 | [Overview and Binary Structure](./01-overview-and-binary-structure.md) | Binary format, installation paths, Bun SEA architecture, version management |
|
||||
| 02 | [Tool System](./02-tool-system.md) | 25+ built-in tools, MCP tool integration, tool schemas, validation, content block types |
|
||||
| 03 | [Agent Loop and Execution Flow](./03-agent-loop-and-execution-flow.md) | Entry points, main loop, streaming, conversation management, slash commands, output formats |
|
||||
| 04 | [Permission System](./04-permission-system.md) | 6 permission modes, permission flow, sandbox integration, managed settings |
|
||||
| 05 | [MCP Integration](./05-mcp-integration.md) | 4 transports, 13 protocol methods, connection management, OAuth, tool discovery |
|
||||
| 06 | [Hooks System](./06-hooks-system.md) | 6 hook events, command/HTTP hook types, lifecycle, security controls |
|
||||
| 07 | [Context and Session Management](./07-context-and-session-management.md) | Token budgets, auto-compaction, session persistence, CLAUDE.md, file checkpointing, prompt caching |
|
||||
| 08 | [Configuration and Environment](./08-configuration-and-environment.md) | Settings hierarchy, 76 settings, 498 env vars, home directory structure |
|
||||
| 09 | [Agent and Subagent System](./09-agent-and-subagent-system.md) | Agent types, task/subagent lifecycle, skill system, plugin marketplace |
|
||||
| 10 | [Models and API](./10-models-and-api.md) | 27+ model IDs, 5 provider backends, API endpoints, prompt caching, effort levels |
|
||||
| 11 | [Telemetry and Observability](./11-telemetry-and-observability.md) | OpenTelemetry, Datadog, Perfetto, debugging, cost tracking |
|
||||
| 12 | [Dependency Graph](./12-dependency-graph.md) | Module relationships, data flow, state management, initialization sequence |
|
||||
| 13 | [Extension Points](./13-extension-points.md) | 13 extension mechanisms from CLAUDE.md to Agent SDK |
|
||||
| 14 | [Source Extraction](./14-source-extraction.md) | Binary analysis, code metrics, extraction methods, dependency identification |
|
||||
| 15 | [Core Module Analysis](./15-core-module-analysis.md) | Agent loop, tool dispatch, permissions, context management, MCP, streaming |
|
||||
| 16 | [Call Graphs](./16-call-graphs.md) | Mermaid call graphs: boot, agent loop, tool dispatch, permissions, MCP, compaction |
|
||||
| 17 | [Class Hierarchy](./17-class-hierarchy.md) | 1,557 classes, inheritance trees, AppState type, tool registry |
|
||||
| 18 | [State Machines](./18-state-machines.md) | Agent loop, permission, session, streaming, MCP, sandbox state machines |
|
||||
|
||||
### Extracted Source (RVF files)
|
||||
|
||||
| File | Module | Confidence |
|
||||
|------|--------|------------|
|
||||
| [agent-loop.rvf](./extracted/agent-loop.rvf) | Core async generator (s$) | High |
|
||||
| [tool-dispatch.rvf](./extracted/tool-dispatch.rvf) | Tool registry and dispatch | High |
|
||||
| [permission-system.rvf](./extracted/permission-system.rvf) | Permission checker and sandbox | High |
|
||||
| [mcp-client.rvf](./extracted/mcp-client.rvf) | MCP protocol client | High |
|
||||
| [context-manager.rvf](./extracted/context-manager.rvf) | Token counting and compaction | High |
|
||||
| [streaming-handler.rvf](./extracted/streaming-handler.rvf) | SSE event processing | High |
|
||||
|
||||
### Decompiler Script
|
||||
|
||||
`/scripts/claude-code-decompile.sh [output-dir]` - Automated extraction and analysis
|
||||
|
||||
## Key Findings
|
||||
|
||||
### Architecture Summary
|
||||
|
||||
- **Runtime**: Bun 1.3.11 Single Executable Application (229 MB binary)
|
||||
- **Application code**: ~12.8 MB of bundled, minified JavaScript
|
||||
- **UI**: React 18.3.1 WebView (VS Code) + Ink-style terminal (CLI)
|
||||
- **API**: Anthropic Messages API with streaming SSE
|
||||
- **Extension**: MCP client protocol with 4 transports
|
||||
|
||||
### By the Numbers
|
||||
|
||||
| Metric | Count |
|
||||
|--------|-------|
|
||||
| Built-in tools | 25+ |
|
||||
| Slash commands | 39 |
|
||||
| Environment variables | 498 |
|
||||
| Settings properties | 76 |
|
||||
| Supported models | 27+ |
|
||||
| MCP protocol methods | 13 |
|
||||
| Hook event types | 6 |
|
||||
| Permission modes | 5 (acceptEdits, bypassPermissions, default, dontAsk, plan) |
|
||||
| Extension mechanisms | 13 |
|
||||
| Auth providers | 5 |
|
||||
| MCP transports | 4 |
|
||||
| Output formats | 3 |
|
||||
| **Source code classes** | **1,557** |
|
||||
| **Functions (estimated)** | **19,464** |
|
||||
| **Async generators (core loops)** | **6** |
|
||||
| **Bundle size (minified)** | **11 MB / 4,836 lines** |
|
||||
|
||||
### Architecture Pattern
|
||||
|
||||
Claude Code follows a **plugin-oriented monolith** pattern:
|
||||
- Single binary deployment (Bun SEA)
|
||||
- Modular internal architecture with clear subsystem boundaries
|
||||
- Extensive extension surface (MCP, hooks, agents, skills, plugins)
|
||||
- Multi-provider backend abstraction (Anthropic/AWS/GCP/Azure)
|
||||
- Layered security (permissions -> sandbox -> hooks -> managed settings)
|
||||
|
||||
## Limitations
|
||||
|
||||
- Source is minified/mangled: variable names are meaningless (e.g., `Yq`, `f9`)
|
||||
- Cannot trace exact function boundaries or module structure
|
||||
- V8 snapshot region (~100MB) could not be decompiled
|
||||
- Some patterns may be from bundled dependencies, not Claude Code itself
|
||||
- This analysis reflects v2.1.90; architecture may change between versions
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
# Claude Code CLI: Overview and Binary Structure
|
||||
|
||||
## Version Analyzed
|
||||
|
||||
- **Version**: 2.1.90
|
||||
- **Runtime**: Bun 1.3.11 (compiled as Single Executable Application)
|
||||
- **Binary Format**: ELF 64-bit LSB executable, x86-64, dynamically linked
|
||||
- **Binary Size**: ~229 MB (uncompressed), ~51 MB (.zst compressed)
|
||||
|
||||
## Installation Locations
|
||||
|
||||
```
|
||||
/home/<user>/.local/bin/claude -> symlink to active version
|
||||
/home/<user>/.local/share/claude/versions/2.1.90 -> native binary (Bun SEA)
|
||||
/home/<user>/.vscode-remote/extensions/anthropic.claude-code-2.1.90-linux-x64/
|
||||
extension.js -> VS Code extension entry (1.8 MB, minified)
|
||||
webview/index.js -> React-based UI (4.8 MB, minified)
|
||||
package.json -> VS Code extension manifest
|
||||
claude-code-settings.schema.json -> 76-property settings schema
|
||||
resources/
|
||||
native-binary/claude -> same binary, for VS Code
|
||||
walkthrough/ -> onboarding assets
|
||||
```
|
||||
|
||||
## Binary Architecture
|
||||
|
||||
The Claude Code CLI is a **Bun Single Executable Application (SEA)**.
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Bun Runtime**: The binary embeds the full Bun runtime (v1.3.11)
|
||||
- V8 engine compiled in (not Node.js -- Bun uses JavaScriptCore, but the
|
||||
binary symbols show V8, indicating a hybrid or Node.js compatibility layer)
|
||||
- Native HTTP client, filesystem, and child_process support
|
||||
|
||||
2. **Embedded JS Bundles**: The binary contains multiple bundled JS regions:
|
||||
- **Bun framework code** (~2.1 MB at offset ~1.8M): React SSR, HMR, Tailwind
|
||||
- **Application code** (~12.8 MB at offset ~107M-120M): The actual Claude Code
|
||||
application with all tools, agent loop, MCP client, permissions, etc.
|
||||
|
||||
3. **Compression**: Ships with a `.zst` (Zstandard) compressed copy alongside
|
||||
the full binary for efficient distribution
|
||||
|
||||
### Binary Sections (Key Offsets)
|
||||
|
||||
| Region | Offset | Content |
|
||||
|--------|--------|---------|
|
||||
| ELF headers + V8 | 0 - 1.8M | Native code, V8 engine |
|
||||
| Bun framework bundle | ~1.8M - 4.0M | Bun's built-in React, HMR, Tailwind |
|
||||
| V8 snapshot data | ~4M - 107M | V8 heap snapshot, compiled bytecode |
|
||||
| Application JS | ~107M - 120M | Claude Code application source |
|
||||
| Binary data | 120M+ | Resources, compressed assets |
|
||||
|
||||
## Version Management
|
||||
|
||||
```
|
||||
~/.local/share/claude/versions/
|
||||
2.1.86 (228 MB)
|
||||
2.1.87 (228 MB)
|
||||
2.1.90 (229 MB) <- current
|
||||
```
|
||||
|
||||
The CLI supports auto-updates with two channels:
|
||||
- `latest` (default): Bleeding edge
|
||||
- `stable`: Tested releases
|
||||
|
||||
Version selection controlled by `autoUpdatesChannel` setting and
|
||||
`DISABLE_AUTOUPDATER` env var.
|
||||
|
||||
## Dual Interface
|
||||
|
||||
Claude Code operates as both:
|
||||
|
||||
1. **CLI Tool** (`claude` binary): Terminal-based interactive REPL and
|
||||
non-interactive `--print` mode
|
||||
2. **VS Code Extension**: WebView-based UI communicating with the same
|
||||
core via the `extension.js` bridge
|
||||
|
||||
The extension.js acts as a bridge between VS Code's extension host and
|
||||
the native binary, translating between VS Code's API and Claude Code's
|
||||
internal protocols.
|
||||
|
||||
## Package Identity
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "claude-code",
|
||||
"version": "2.1.90",
|
||||
"displayName": "Claude Code for VS Code",
|
||||
"publisher": "Anthropic"
|
||||
}
|
||||
```
|
||||
|
||||
Zero npm dependencies in the VS Code extension -- everything is bundled.
|
||||
150
docs/research/claude-code-rvsource/02-tool-system.md
Normal file
150
docs/research/claude-code-rvsource/02-tool-system.md
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# Claude Code CLI: Tool System Architecture
|
||||
|
||||
## Built-in Tools
|
||||
|
||||
Claude Code registers tools with the Anthropic Messages API using the standard
|
||||
tool_use / tool_result content block protocol.
|
||||
|
||||
### Tool Registry
|
||||
|
||||
The internal tool name map (display names for UI):
|
||||
|
||||
```javascript
|
||||
{
|
||||
Read: "Reading",
|
||||
Write: "Writing",
|
||||
Edit: "Editing",
|
||||
MultiEdit: "Editing",
|
||||
Bash: "Running",
|
||||
Glob: "Searching",
|
||||
Grep: "Searching",
|
||||
WebFetch: "Fetching",
|
||||
WebSearch: "Searching",
|
||||
Task: "Running task",
|
||||
FileReadTool: "Reading",
|
||||
FileWriteTool: "Writing",
|
||||
FileEditTool: "Editing",
|
||||
GlobTool: "Searching",
|
||||
GrepTool: "Searching",
|
||||
BashTool: "Running",
|
||||
NotebookEditTool: "Editing notebook",
|
||||
LSP: "LSP"
|
||||
}
|
||||
```
|
||||
|
||||
### Tool Name Variables (Internal References)
|
||||
|
||||
| Variable | Tool Name |
|
||||
|----------|-----------|
|
||||
| `Yq` | Bash |
|
||||
| `Bq` | Read |
|
||||
| `c7` | Write |
|
||||
| `wK` | Edit |
|
||||
| `Gf` | Glob |
|
||||
| `f9` | Grep |
|
||||
| `sw` | WebFetch |
|
||||
| `nE` | WebSearch |
|
||||
| `IL` | NotebookEdit |
|
||||
| `WX` | ToolSearch |
|
||||
| `lI` | TodoWrite |
|
||||
| `nj` | Skill |
|
||||
| `tXH` | SendUserMessage |
|
||||
|
||||
### Tool Categories
|
||||
|
||||
**File Operations**:
|
||||
- `Read` / `FileReadTool` -- Read files, images, PDFs, notebooks
|
||||
- `Write` / `FileWriteTool` -- Create or overwrite files
|
||||
- `Edit` / `FileEditTool` -- String replacement edits in existing files
|
||||
- `MultiEdit` -- Multiple edits in a single tool call
|
||||
- `NotebookEdit` / `NotebookEditTool` -- Jupyter notebook cell operations
|
||||
|
||||
**Search**:
|
||||
- `Glob` / `GlobTool` -- File pattern matching (fast, sorted by mtime)
|
||||
- `Grep` / `GrepTool` -- Content search via ripgrep with regex support
|
||||
|
||||
**Execution**:
|
||||
- `Bash` / `BashTool` -- Shell command execution with sandbox support
|
||||
- `Task` -- Spawn subagent for parallel work
|
||||
|
||||
**Web**:
|
||||
- `WebFetch` -- HTTP fetch with content extraction
|
||||
- `WebSearch` -- Web search integration
|
||||
|
||||
**Agent/System**:
|
||||
- `ToolSearch` -- Discover deferred tools (MCP tools loaded on demand)
|
||||
- `Skill` -- Execute registered skills/slash commands
|
||||
- `SendUserMessage` -- Agent-to-user communication (brief mode)
|
||||
- `TodoRead` / `TodoWrite` -- Task list management
|
||||
- `EnterWorktree` / `ExitWorktree` -- Git worktree management
|
||||
- `LSP` -- Language Server Protocol integration
|
||||
|
||||
### Tool Schema Pattern
|
||||
|
||||
Each tool is defined with:
|
||||
```javascript
|
||||
{
|
||||
name: "ToolName",
|
||||
description: `Template literal with ${otherToolNames} interpolated`,
|
||||
input_schema: {
|
||||
type: "object",
|
||||
properties: { ... },
|
||||
required: [ ... ]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Tool descriptions dynamically reference other tool names so the model knows
|
||||
the full toolkit available. For example, Bash's description says "Avoid using
|
||||
this tool to run grep, find, cat... instead use the appropriate dedicated tool."
|
||||
|
||||
### Tool Validation
|
||||
|
||||
Tools have category-based validation:
|
||||
- **filePatternTools**: `["Read", "Write", "Edit", "Glob", "NotebookRead", "NotebookEdit"]`
|
||||
- Validate file paths
|
||||
- **bashPrefixTools**: `["Bash"]`
|
||||
- Validate command prefixes against allowed/denied patterns
|
||||
- **customValidation**: Per-tool validators (e.g., WebSearch rejects wildcards)
|
||||
|
||||
### Tool Permission Flow
|
||||
|
||||
```
|
||||
User prompt -> Model generates tool_use -> Permission check -> Execute -> tool_result
|
||||
```
|
||||
|
||||
Each tool call goes through the permission system before execution.
|
||||
See `04-permission-system.md` for details.
|
||||
|
||||
### MCP Tool Integration
|
||||
|
||||
MCP (Model Context Protocol) tools extend the built-in set:
|
||||
- MCP tools are prefixed with `mcp__<server-name>__<tool-name>`
|
||||
- `ReadMcpResourceTool` -- Read MCP server resources
|
||||
- MCP tools can be deferred (loaded on-demand via `ToolSearch`)
|
||||
- Tool output size controlled by `MAX_MCP_OUTPUT_TOKENS` env var
|
||||
- Large outputs can be saved to files (`ENABLE_MCP_LARGE_OUTPUT_FILES`)
|
||||
|
||||
### Tool Concurrency
|
||||
|
||||
`CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` controls parallel tool execution.
|
||||
Multiple tool calls in a single response can execute concurrently.
|
||||
|
||||
### Content Block Types
|
||||
|
||||
The API supports these content block types in messages:
|
||||
|
||||
| Type | Direction | Purpose |
|
||||
|------|-----------|---------|
|
||||
| `text` | Both | Text content |
|
||||
| `thinking` | Response | Extended thinking |
|
||||
| `redacted_thinking` | Response | Safety-redacted thinking |
|
||||
| `tool_use` | Response | Tool call request |
|
||||
| `tool_result` | Request | Tool execution result |
|
||||
| `image` | Request | Image content |
|
||||
| `file` | Request | File content |
|
||||
| `server_tool_use` | Response | Server-side tool calls |
|
||||
| `web_search_tool_result` | Response | Web search results |
|
||||
| `code_execution_tool_result` | Response | Code execution results |
|
||||
| `mcp_tool_use` | Response | MCP tool calls |
|
||||
| `mcp_tool_result` | Response | MCP tool results |
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
# Claude Code CLI: Agent Loop and Execution Flow
|
||||
|
||||
## Entry Points
|
||||
|
||||
### CLI Entry
|
||||
|
||||
The binary boots through Bun's SEA mechanism into a Commander.js-style CLI:
|
||||
|
||||
```
|
||||
claude [options] [command] [prompt]
|
||||
```
|
||||
|
||||
**Subcommands** (24 registered):
|
||||
- `auth`, `login`, `logout` -- Authentication
|
||||
- `config` (list/show/set/defaults) -- Configuration management
|
||||
- `mcp` (add-from-claude-desktop, list, serve, status, setup) -- MCP server management
|
||||
- `doctor` -- Diagnostics
|
||||
- `update` -- Self-update
|
||||
- `agents` -- Agent management
|
||||
- `marketplace`, `plugin` -- Plugin/skill management
|
||||
- `remote-control`, `serve` -- Remote/SSE modes
|
||||
- `auto-mode` -- Auto permission mode
|
||||
- `setup-token`, `xaa` -- Auth helpers
|
||||
- `critique`, `reset-project-choices`, `clear` -- Misc utilities
|
||||
|
||||
### VS Code Extension Entry
|
||||
|
||||
`extension.js` registers VS Code commands and creates a WebView panel.
|
||||
The WebView (`webview/index.js`) is a React 18.3.1 application that
|
||||
communicates with the extension host via `postMessage`.
|
||||
|
||||
VS Code commands (21 registered):
|
||||
- `claude-vscode.editor.open` / `openLast` / `primaryEditor.open`
|
||||
- `claude-vscode.window.open`
|
||||
- `claude-vscode.createWorktree`
|
||||
- `claude-vscode.insertAtMention`
|
||||
- `claude-vscode.focus` / `blur`
|
||||
- `claude-vscode.terminal.open.keyboard`
|
||||
|
||||
## Main Loop Architecture
|
||||
|
||||
### Core Loop Functions
|
||||
|
||||
| Function | Purpose |
|
||||
|----------|---------|
|
||||
| `mainLoop` | Primary conversation loop |
|
||||
| `mainLoopModel` | Model selection for current session |
|
||||
| `mainLoopModelForSession` | Session-level model override |
|
||||
| `mainLoopModelOverride` | CLI/env model override |
|
||||
| `mainLoopTokens` | Token tracking for main loop |
|
||||
| `processMessagesForTeleportResume` | Handle session teleport/resume |
|
||||
|
||||
### Execution Flow
|
||||
|
||||
```
|
||||
1. CLI Parse / VS Code Activation
|
||||
|
|
||||
2. Configuration Loading
|
||||
- User settings (~/.claude/settings.json)
|
||||
- Project settings (.claude/settings.json, .claude/settings.local.json)
|
||||
- CLAUDE.md files (auto-discovered up directory tree)
|
||||
- Environment variables (498+ recognized)
|
||||
|
|
||||
3. Authentication
|
||||
- AnthropicApiKeyAuth (API key from env/helper)
|
||||
- ConsoleOAuthFlow (Anthropic Console OAuth)
|
||||
- BedrockClient (AWS Bedrock)
|
||||
- VertexAI (Google Cloud)
|
||||
- Foundry (Azure)
|
||||
|
|
||||
4. MCP Server Connection
|
||||
- Read .mcp.json, settings, --mcp-config
|
||||
- Connect to MCP servers (stdio, SSE, HTTP transports)
|
||||
- Discover tools via tools/list
|
||||
|
|
||||
5. Session Init / Resume
|
||||
- Create new session or resume existing
|
||||
- Load conversation history
|
||||
- Apply CLAUDE.md system prompt
|
||||
|
|
||||
6. Main Loop (per turn):
|
||||
a. Collect user input (interactive) or read prompt (--print)
|
||||
b. Build message array with system prompt + conversation history
|
||||
c. Call Anthropic Messages API (streaming)
|
||||
d. Process response stream:
|
||||
- Text blocks -> render to terminal/UI
|
||||
- Thinking blocks -> display if enabled
|
||||
- tool_use blocks -> queue for execution
|
||||
e. For each tool_use:
|
||||
- Check permissions (PreToolUse hooks)
|
||||
- Execute tool
|
||||
- Run PostToolUse hooks
|
||||
- Append tool_result to messages
|
||||
f. If model stopped with tool_use (not end_turn):
|
||||
- Loop back to step (c) with updated messages
|
||||
g. If model stopped with end_turn:
|
||||
- Display final response
|
||||
- Wait for next user input
|
||||
|
|
||||
7. Context Management
|
||||
- Track token usage
|
||||
- Auto-compact when context window fills
|
||||
- File checkpointing for recovery
|
||||
|
|
||||
8. Session End
|
||||
- Run session-end hooks
|
||||
- Persist session to disk
|
||||
- Cleanup MCP connections
|
||||
```
|
||||
|
||||
### Streaming Architecture
|
||||
|
||||
The API response is streamed using Server-Sent Events (SSE):
|
||||
|
||||
```
|
||||
StreamEvent -> StreamEventBuffer -> StreamHandler -> UI Renderer
|
||||
```
|
||||
|
||||
Key streaming patterns:
|
||||
- `StreamFriendlyUIEnabled` -- Controls rich terminal rendering
|
||||
- `StreamInterval` -- Configurable update frequency
|
||||
- `StreamFinished` / `StreamFinishing` -- Completion states
|
||||
- Partial message chunks available via `--include-partial-messages`
|
||||
|
||||
### Conversation Management
|
||||
|
||||
- `ConversationManager` -- Manages conversation state
|
||||
- `ConversationChain` -- Message chain/history
|
||||
- `MessageBuffer` / `MessageBufferTracker` -- Buffer management
|
||||
- `MessageByUuid` -- Message lookup
|
||||
- `MessageExistInSession` -- Deduplication
|
||||
|
||||
### Slash Commands (39 Built-in)
|
||||
|
||||
Interactive commands processed before sending to the API:
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/compact` | Force context compaction |
|
||||
| `/clear` | Clear conversation |
|
||||
| `/model` | Switch model |
|
||||
| `/effort` | Set reasoning effort level |
|
||||
| `/fast` | Toggle fast mode |
|
||||
| `/permissions` | View/edit permission rules |
|
||||
| `/hooks` | View configured hooks |
|
||||
| `/mcp` | MCP server status |
|
||||
| `/memory` | View/edit auto-memory |
|
||||
| `/status` | Session status |
|
||||
| `/review-pr` | PR review workflow |
|
||||
| `/commit` | Commit workflow |
|
||||
| `/init` | Project initialization |
|
||||
| `/login` / `/logout` | Authentication |
|
||||
| `/doctor` | Run diagnostics |
|
||||
| `/bug` | Report a bug |
|
||||
| `/cost` | Show cost information |
|
||||
| `/extra-usage` | Usage details |
|
||||
| `/feedback` | Submit feedback |
|
||||
| `/config` | Configuration |
|
||||
| `/skills` | List available skills |
|
||||
| `/agents` | Agent management |
|
||||
| `/tasks` | Task/subagent list |
|
||||
| `/worker` | Background workers |
|
||||
| `/branch` | Create feature branch |
|
||||
| `/teleport` | Session teleport |
|
||||
| `/rewind` | Rewind conversation |
|
||||
| `/resume` | Resume session |
|
||||
| `/loop` | Recurring command |
|
||||
| `/chrome` | Chrome integration |
|
||||
| `/powerup` | Power-up features |
|
||||
| `/deploy` | Deployment workflow |
|
||||
| `/dev` | Development mode |
|
||||
| `/issue` | Issue tracker |
|
||||
| `/metrics` | Performance metrics |
|
||||
| `/dashboard` | Dashboard view |
|
||||
| `/ultrareview` | Deep code review |
|
||||
| `/prompt` | Prompt management |
|
||||
| `/install-github-app` | GitHub App setup |
|
||||
|
||||
### Output Modes
|
||||
|
||||
```
|
||||
--output-format text # Default: human-readable
|
||||
--output-format json # Single JSON result
|
||||
--output-format stream-json # Real-time streaming JSON
|
||||
```
|
||||
|
||||
Input modes:
|
||||
```
|
||||
--input-format text # Default: plain text prompt
|
||||
--input-format stream-json # Real-time streaming JSON input
|
||||
```
|
||||
136
docs/research/claude-code-rvsource/04-permission-system.md
Normal file
136
docs/research/claude-code-rvsource/04-permission-system.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Claude Code CLI: Permission System
|
||||
|
||||
## Permission Modes
|
||||
|
||||
Six distinct permission modes control tool execution:
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `default` | Ask user for each permission (interactive) |
|
||||
| `acceptEdits` | Auto-approve file edits, ask for everything else |
|
||||
| `plan` | Read-only mode, no modifications allowed |
|
||||
| `dontAsk` | Skip permission prompts but respect rules |
|
||||
| `bypassPermissions` | Skip all permission checks (sandbox only) |
|
||||
| `auto` | Auto-approve based on configured rules |
|
||||
|
||||
Set via `--permission-mode` CLI flag or `--dangerously-skip-permissions`.
|
||||
|
||||
## Permission Architecture
|
||||
|
||||
### Core Types (30+ identified)
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `Permission` | Base permission type |
|
||||
| `PermissionRequest` | Incoming tool use request |
|
||||
| `PermissionResponse` | Approval/denial result |
|
||||
| `PermissionResult` | Final permission outcome |
|
||||
| `PermissionContext` | Contextual info for decision |
|
||||
| `PermissionMatcher` | Pattern matching for rules |
|
||||
| `PermissionCallbacks` | UI callbacks for prompts |
|
||||
| `PermissionPrompt` | User prompt configuration |
|
||||
| `PermissionPoller` | Async permission polling |
|
||||
| `PermissionSync` | Permission state sync |
|
||||
|
||||
### Permission Flow
|
||||
|
||||
```
|
||||
tool_use request
|
||||
|
|
||||
v
|
||||
PermissionRequest created
|
||||
|
|
||||
v
|
||||
PreToolUse hooks run
|
||||
| (hooks can approve/deny/modify)
|
||||
v
|
||||
Permission rules checked
|
||||
| (allow/deny/ask patterns)
|
||||
v
|
||||
PermissionMode evaluation
|
||||
|
|
||||
+-- bypassPermissions -> ALLOW
|
||||
+-- plan -> DENY (if write operation)
|
||||
+-- auto -> Check configured rules
|
||||
+-- default -> PermissionPrompt to user
|
||||
+-- acceptEdits -> ALLOW edits, ask rest
|
||||
+-- dontAsk -> Default to deny
|
||||
|
|
||||
v
|
||||
Permission granted or denied
|
||||
|
|
||||
v
|
||||
PostToolUse hooks run (if executed)
|
||||
```
|
||||
|
||||
### Permission Rules
|
||||
|
||||
Configured in settings under `permissions`:
|
||||
|
||||
```json
|
||||
{
|
||||
"permissions": {
|
||||
"allow": ["Read", "Glob", "Grep"],
|
||||
"deny": ["Bash(rm *)"],
|
||||
"ask": ["Write", "Edit"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rules support tool name patterns:
|
||||
- `"Bash"` -- Match all Bash tool uses
|
||||
- `"Bash(git:*)"` -- Match Bash with git commands
|
||||
- `"Edit"` -- Match all Edit tool uses
|
||||
- `"Read(~/.zshrc)"` -- Match specific file reads
|
||||
|
||||
### Permission Errors
|
||||
|
||||
| Error Type | Meaning |
|
||||
|------------|---------|
|
||||
| `PermissionDenied` | Explicitly denied by rule |
|
||||
| `PermissionDeniedError` | Error thrown on denial |
|
||||
| `PermissionDeniedHooks` | Denied by a hook |
|
||||
| `PermissionCancelled` | User cancelled the prompt |
|
||||
|
||||
### Sandbox Integration
|
||||
|
||||
The permission system integrates with OS-level sandboxing:
|
||||
|
||||
**Linux**: `bubblewrap` (bwrap)
|
||||
- Filesystem isolation
|
||||
- Network access control
|
||||
- Process namespace separation
|
||||
|
||||
**macOS**: `sandbox-exec` / `seatbelt`
|
||||
- App Sandbox profiles
|
||||
- File system restrictions
|
||||
- Network policy enforcement
|
||||
|
||||
Sandbox-related types:
|
||||
- `SandboxManager` -- Manages sandbox lifecycle
|
||||
- `SandboxPermissions` -- Sandbox-level permissions
|
||||
- `SandboxViolationStore` -- Tracks sandbox violations
|
||||
- `SandboxRuntimeConfig` / `SandboxRuntimeConfigSchema` -- Runtime config
|
||||
- `SandboxedBash` -- Bash execution within sandbox
|
||||
- `SandboxSettings` / `SandboxSettingsLockedByPolicy` -- Policy controls
|
||||
- `SandboxAutoAllowEnabled` -- Auto-allow certain sandbox operations
|
||||
- `SandboxDomainsOnly` -- Restrict to approved domains
|
||||
|
||||
### Auto Mode Permissions
|
||||
|
||||
`PermissionsForAutoMode` provides a curated set of auto-approved
|
||||
operations for `--permission-mode auto`:
|
||||
- File reads in project directory
|
||||
- Standard git operations
|
||||
- Build/test commands
|
||||
- Non-destructive shell commands
|
||||
|
||||
### Managed Settings Lock
|
||||
|
||||
Enterprise/team settings can lock permissions:
|
||||
- `allowManagedPermissionRulesOnly` -- Only use managed rules
|
||||
- `allowManagedHooksOnly` -- Only allow managed hooks
|
||||
- `allowManagedMcpServersOnly` -- Only use managed MCP servers
|
||||
|
||||
These ensure organizational security policies cannot be overridden
|
||||
by individual users.
|
||||
177
docs/research/claude-code-rvsource/05-mcp-integration.md
Normal file
177
docs/research/claude-code-rvsource/05-mcp-integration.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# Claude Code CLI: MCP (Model Context Protocol) Integration
|
||||
|
||||
## Overview
|
||||
|
||||
Claude Code acts as an MCP **client**, connecting to external MCP servers
|
||||
to extend its tool, resource, and prompt capabilities.
|
||||
|
||||
## Transport Layer
|
||||
|
||||
Four transport types supported:
|
||||
|
||||
| Transport | Protocol | Use Case |
|
||||
|-----------|----------|----------|
|
||||
| `stdio` | stdin/stdout | Local process (most common) |
|
||||
| `sse` | Server-Sent Events | Remote persistent connection |
|
||||
| `streamable-http` | HTTP streaming | Modern remote transport |
|
||||
| `websocket` | WebSocket | Bidirectional real-time |
|
||||
|
||||
## MCP Protocol Methods
|
||||
|
||||
Claude Code implements these MCP protocol methods:
|
||||
|
||||
### Core
|
||||
- `initialize` -- Handshake and capability negotiation
|
||||
- `ping` -- Keepalive
|
||||
|
||||
### Tools
|
||||
- `tools/list` -- Discover available tools
|
||||
- `tools/call` -- Execute a tool
|
||||
|
||||
### Resources
|
||||
- `resources/list` -- List available resources
|
||||
- `resources/read` -- Read a resource
|
||||
|
||||
### Prompts
|
||||
- `prompts/list` -- List available prompt templates
|
||||
- `prompts/get` -- Get a specific prompt
|
||||
|
||||
### Completions
|
||||
- `completion/complete` -- Auto-completion support
|
||||
|
||||
### Notifications
|
||||
- `notifications/initialized` -- Client initialized
|
||||
- `notifications/cancelled` -- Operation cancelled
|
||||
- `notifications/message` -- Status messages
|
||||
- `notifications/progress` -- Progress updates
|
||||
|
||||
## Connection Management
|
||||
|
||||
### MCPConnectionManager
|
||||
|
||||
Central manager for all MCP server connections:
|
||||
|
||||
```
|
||||
MCPConnectionManager
|
||||
|-- MCPConnections (active connection pool)
|
||||
|-- MCPServer definitions (from config)
|
||||
|-- MCPTool registry (discovered tools)
|
||||
|-- MCPToolOutput handling
|
||||
|-- MCPToolOverrides (user overrides)
|
||||
```
|
||||
|
||||
### Configuration Sources
|
||||
|
||||
MCP servers can be defined in multiple places (priority order):
|
||||
|
||||
1. `--mcp-config` CLI argument (JSON file or string)
|
||||
2. `--strict-mcp-config` -- Use ONLY --mcp-config, ignore all else
|
||||
3. `.mcp.json` in project root
|
||||
4. `.claude/settings.json` (user level)
|
||||
5. `.claude/settings.local.json` (local level)
|
||||
6. Managed settings (enterprise)
|
||||
|
||||
### Server Definition Format
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"server-name": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "package-name"],
|
||||
"env": { "KEY": "value" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or for remote servers:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"remote-server": {
|
||||
"url": "https://example.com/mcp",
|
||||
"transport": "sse"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tool Discovery and Deferred Loading
|
||||
|
||||
### Eager vs Deferred Tools
|
||||
|
||||
- **Eager**: Tools from MCP servers with few tools are loaded immediately
|
||||
- **Deferred**: Tools from servers with many tools (like claude-flow) are
|
||||
loaded on-demand via the `ToolSearch` built-in tool
|
||||
|
||||
The `ToolSearch` tool allows Claude to discover deferred tools by:
|
||||
1. Querying with a name or keyword
|
||||
2. Getting back full JSON Schema definitions
|
||||
3. Then calling those tools normally
|
||||
|
||||
Controlled by `ENABLE_TOOL_SEARCH` env var.
|
||||
|
||||
### Tool Naming Convention
|
||||
|
||||
MCP tools are prefixed: `mcp__<server-name>__<tool-name>`
|
||||
|
||||
Example: `mcp__claude-flow_alpha__swarm_init`
|
||||
|
||||
The `MCP_NO_PREFIX` / `CLAUDE_AGENT_SDK_MCP_NO_PREFIX` env vars can
|
||||
disable this prefixing.
|
||||
|
||||
## OAuth for Remote MCP
|
||||
|
||||
Remote MCP servers can use OAuth authentication:
|
||||
|
||||
- `MCP_CLIENT_SECRET` -- Client secret for OAuth
|
||||
- `MCP_OAUTH_CALLBACK_PORT` -- Local callback port
|
||||
- `MCP_OAUTH_CLIENT_METADATA_URL` -- Client metadata URL
|
||||
- `MCP_CLIENT_METADATA_URL` -- Alternative metadata URL
|
||||
- `OAuthClientConfig` -- Full OAuth configuration
|
||||
- `OAuthClientAuthHandler` -- Authentication handler
|
||||
|
||||
## Batch Connection
|
||||
|
||||
For performance, MCP server connections are batched:
|
||||
|
||||
- `MCP_SERVER_CONNECTION_BATCH_SIZE` -- Max concurrent connections
|
||||
- `MCP_REMOTE_SERVER_CONNECTION_BATCH_SIZE` -- Max concurrent remote connections
|
||||
- `MCP_CONNECTION_NONBLOCKING` -- Non-blocking connection mode
|
||||
|
||||
## MCP Output Handling
|
||||
|
||||
- `MCP_OUTPUT_TOKENS` -- Token budget for MCP output
|
||||
- `MAX_MCP_OUTPUT_TOKENS` -- Maximum output tokens
|
||||
- `MCP_LARGE_OUTPUT_FILES` -- Save large outputs to files
|
||||
- `MCP_TRUNCATION_PROMPT_OVERRIDE` -- Custom truncation message
|
||||
|
||||
## MCP Debug
|
||||
|
||||
- `--mcp-debug` flag (deprecated, use `--debug`)
|
||||
- `MCPDebug` -- Debug mode state
|
||||
- `MCPLogsPath` -- MCP debug log location
|
||||
|
||||
## MCP Proxy
|
||||
|
||||
Claude Code can proxy MCP connections:
|
||||
|
||||
- `MCP_PROXY_URL` -- Upstream proxy URL
|
||||
- `MCP_PROXY_PATH` -- Proxy path prefix
|
||||
- Used for session ingress: `/v2/session_ingress/shttp/mcp/`
|
||||
|
||||
## Server Approval
|
||||
|
||||
Users must approve MCP servers from `.mcp.json`:
|
||||
|
||||
- `enabledMcpjsonServers` -- Approved server list
|
||||
- `disabledMcpjsonServers` -- Rejected server list
|
||||
- `enableAllProjectMcpServers` -- Auto-approve all
|
||||
- `deniedMcpServers` -- Enterprise denylist
|
||||
- `allowedMcpServers` -- Enterprise allowlist
|
||||
|
||||
## MCP Instrumentation
|
||||
|
||||
- `MCP_INSTR_DELTA` / `CLAUDE_CODE_MCP_INSTR_DELTA` -- Instrumentation interval
|
||||
- Connected to OpenTelemetry for observability
|
||||
170
docs/research/claude-code-rvsource/06-hooks-system.md
Normal file
170
docs/research/claude-code-rvsource/06-hooks-system.md
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
# Claude Code CLI: Hooks System
|
||||
|
||||
## Overview
|
||||
|
||||
Hooks are custom commands that run at specific points in the tool execution
|
||||
lifecycle. They enable automation, validation, and integration with external
|
||||
systems.
|
||||
|
||||
## Hook Event Types
|
||||
|
||||
Six hook events are supported:
|
||||
|
||||
| Event | Trigger | Can Block |
|
||||
|-------|---------|-----------|
|
||||
| `PreToolUse` | Before a tool executes | Yes (can deny) |
|
||||
| `PostToolUse` | After a tool executes | No |
|
||||
| `PreToolUseFailure` | Before reporting tool failure | No |
|
||||
| `PostToolUseFailure` | After tool failure | No |
|
||||
| `Notification` | On system notifications | No |
|
||||
| `Stop` | When agent stops (end_turn) | Yes (can continue) |
|
||||
| `SubagentStop` | When a subagent stops | Yes (can continue) |
|
||||
|
||||
## Hook Configuration
|
||||
|
||||
Hooks are defined in settings.json under the `hooks` key:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "echo 'File being modified: $TOOL_INPUT'"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "echo 'Command completed'"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Matcher Syntax
|
||||
|
||||
- Empty string `""` -- Match all tools
|
||||
- `"Bash"` -- Match specific tool
|
||||
- `"Edit|Write"` -- Match multiple tools (pipe-separated)
|
||||
|
||||
### Hook Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `command` | Execute a shell command |
|
||||
| `http` | Make an HTTP request |
|
||||
|
||||
### HTTP Hooks
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "http",
|
||||
"url": "https://example.com/webhook",
|
||||
"method": "POST",
|
||||
"headers": { "Authorization": "Bearer $TOKEN" }
|
||||
}
|
||||
```
|
||||
|
||||
HTTP hook security:
|
||||
- `allowedHttpHookUrls` -- URL pattern allowlist (supports `*` wildcard)
|
||||
- `httpHookAllowedEnvVars` -- Env vars allowed in header interpolation
|
||||
|
||||
## Hook Execution
|
||||
|
||||
### Lifecycle
|
||||
|
||||
```
|
||||
Tool Use Request
|
||||
|
|
||||
v
|
||||
PreToolUse hooks (matcher: tool name)
|
||||
|
|
||||
+-- Hook returns { action: "deny" } -> Tool blocked
|
||||
+-- Hook returns { action: "allow" } -> Skip permission check
|
||||
+-- Hook returns nothing -> Continue to permission check
|
||||
|
|
||||
v
|
||||
Tool executes
|
||||
|
|
||||
v
|
||||
PostToolUse hooks (matcher: tool name)
|
||||
|
|
||||
+-- Can log, notify, but cannot block
|
||||
```
|
||||
|
||||
### Hook Functions
|
||||
|
||||
- `runHooks` -- Main hook execution engine
|
||||
- `executeHooksOutsideREPL` -- Run hooks in non-interactive mode
|
||||
|
||||
### Stop Hooks
|
||||
|
||||
Stop hooks fire when the agent decides to stop (end_turn):
|
||||
|
||||
```json
|
||||
{
|
||||
"Stop": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "echo 'Agent completed turn'"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Security Controls
|
||||
|
||||
### Managed Hooks
|
||||
|
||||
- `allowManagedHooksOnly` -- When true, only hooks from managed (enterprise)
|
||||
settings are executed
|
||||
- `disableAllHooks` -- Completely disable hook execution
|
||||
|
||||
### Hook Context
|
||||
|
||||
Hooks receive context about the tool execution:
|
||||
- Tool name
|
||||
- Tool input parameters
|
||||
- Tool output (PostToolUse only)
|
||||
- Session information
|
||||
- `CLAUDE_CODE_SAVE_HOOK_ADDITIONAL_CONTEXT` -- Include extra context
|
||||
|
||||
### Hook Timeout
|
||||
|
||||
`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` -- Timeout for session-end hooks
|
||||
|
||||
## Agent Hooks
|
||||
|
||||
Agent-specific hook schema: `AgentHookSchema`
|
||||
|
||||
Hooks can be defined per-agent, allowing different automation for
|
||||
different agent roles (e.g., reviewer agent has different PostToolUse
|
||||
hooks than coder agent).
|
||||
|
||||
## Integration with Compact
|
||||
|
||||
`CompactHooks` -- Hooks that run during context compaction, allowing
|
||||
external systems to be notified when conversation history is compressed.
|
||||
|
||||
## Hook Events in Stream Output
|
||||
|
||||
When using `--output-format stream-json`:
|
||||
- `--include-hook-events` includes all hook lifecycle events in the output
|
||||
- Useful for monitoring/debugging hook execution in CI/CD pipelines
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
# Claude Code CLI: Context and Session Management
|
||||
|
||||
## Context Window Management
|
||||
|
||||
### Token Budgets
|
||||
|
||||
Key token constants found in the source:
|
||||
|
||||
| Constant | Value | Purpose |
|
||||
|----------|-------|---------|
|
||||
| `maxTokens` | 64000 | Default max output tokens |
|
||||
| `maxTokens` | 40000 | Alternative budget |
|
||||
| `maxTokens` | 16000 | Constrained budget |
|
||||
| `maxOutputTokensOverride` | 4096 | Override for specific cases |
|
||||
| `budget_tokens` | 10000 | Thinking budget |
|
||||
| `max_tokens` | 1000/256/512 | Various API call limits |
|
||||
|
||||
### Auto-Compaction
|
||||
|
||||
When the conversation context approaches the model's window limit,
|
||||
Claude Code automatically compacts the history.
|
||||
|
||||
**Compaction Types**:
|
||||
- `Compact20260112` -- Current compaction algorithm
|
||||
- `Compact20260112Edit` -- Edit-aware compaction
|
||||
- `CompactOnPromptTooLong` -- Triggered when prompt exceeds limit
|
||||
|
||||
**Compaction Flow**:
|
||||
```
|
||||
Token count check
|
||||
|
|
||||
v
|
||||
CompactThreshold exceeded?
|
||||
| No -> Continue
|
||||
| Yes
|
||||
v
|
||||
CompactMessage generated (summary of conversation)
|
||||
|
|
||||
v
|
||||
CompactHooks fired
|
||||
|
|
||||
v
|
||||
Message history replaced with compact summary
|
||||
|
|
||||
v
|
||||
CompactTracking updated
|
||||
```
|
||||
|
||||
**Configuration**:
|
||||
- `autoCompactWindow` -- Context window size before compacting
|
||||
- `DISABLE_AUTO_COMPACT` / `DISABLE_COMPACT` -- Disable compaction
|
||||
- `ENABLE_CLAUDE_CODE_SM_COMPACT` / `DISABLE_CLAUDE_CODE_SM_COMPACT` --
|
||||
Small model compaction
|
||||
- `CLAUDE_CODE_AUTO_COMPACT_WINDOW` -- Custom window size
|
||||
- `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` -- Compact percentage override
|
||||
- `CLAUDE_CODE_DISABLE_PRECOMPACT_SKIP` -- Disable skip optimization
|
||||
- `CLAUDE_AFTER_LAST_COMPACT` -- State after last compaction
|
||||
- `/compact` slash command -- Manual trigger
|
||||
|
||||
**Compaction discovers tools**:
|
||||
`CompactDiscoveredTools` -- Tracks which tools were used, so the
|
||||
compacted summary preserves tool context.
|
||||
|
||||
### 1M Context Support
|
||||
|
||||
`CLAUDE_CODE_DISABLE_1M_CONTEXT` -- Can disable extended 1M token context
|
||||
(normally enabled for models that support it).
|
||||
|
||||
## Session Persistence
|
||||
|
||||
### Session Storage
|
||||
|
||||
Sessions are persisted to disk at:
|
||||
```
|
||||
~/.claude/projects/<project-hash>/
|
||||
```
|
||||
|
||||
**Key functions**:
|
||||
- `persistSession` -- Save session state to disk
|
||||
- `resumeSession` / `resumeSessionAt` -- Restore session
|
||||
- `sessionFile` -- Session data file path
|
||||
|
||||
### Session Resume
|
||||
|
||||
Multiple resume modes:
|
||||
- `-c, --continue` -- Resume most recent session in current directory
|
||||
- `-r, --resume [id]` -- Resume by session ID
|
||||
- `--session-id <uuid>` -- Use specific session UUID
|
||||
- `--fork-session` -- Fork from existing session (new ID)
|
||||
- `--from-pr [pr]` -- Resume session linked to a PR
|
||||
- `/resume` slash command -- Interactive picker
|
||||
|
||||
### Session Teleport
|
||||
|
||||
The `/teleport` command can transfer session context across environments:
|
||||
- `processMessagesForTeleportResume` -- Handles teleport resume
|
||||
- Useful for moving between CLI and VS Code, or between machines
|
||||
|
||||
### Session Configuration
|
||||
|
||||
- `CLAUDE_CODE_REMOTE_SESSION_ID` -- Remote session identifier
|
||||
- `TEST_ENABLE_SESSION_PERSISTENCE` -- Test mode persistence
|
||||
- `--no-session-persistence` -- Disable persistence (print mode)
|
||||
- `CLAUDE_CODE_RESUME_INTERRUPTED_TURN` -- Resume interrupted turns
|
||||
- `CLAUDE_CODE_RESUME_THRESHOLD_MINUTES` -- Time threshold for resume
|
||||
- `CLAUDE_CODE_RESUME_TOKEN_THRESHOLD` -- Token threshold for resume
|
||||
|
||||
## CLAUDE.md System
|
||||
|
||||
### Auto-Discovery
|
||||
|
||||
Claude Code discovers CLAUDE.md files by walking up the directory tree:
|
||||
|
||||
```
|
||||
./CLAUDE.md <- Project root
|
||||
../CLAUDE.md <- Parent directory
|
||||
~/.claude/CLAUDE.md <- User-level global
|
||||
.claude/settings.json "claudeMdExcludes" <- Exclusions
|
||||
```
|
||||
|
||||
Additional directories via:
|
||||
- `--add-dir` CLI flag
|
||||
- `CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD` env var
|
||||
- `CLAUDE_CODE_DISABLE_CLAUDE_MDS` -- Disable entirely
|
||||
|
||||
### Memory System
|
||||
|
||||
Auto-memory creates and manages persistent knowledge:
|
||||
|
||||
```
|
||||
~/.claude/projects/<project>/memory/MEMORY.md
|
||||
```
|
||||
|
||||
- `autoMemoryEnabled` -- Enable/disable per project
|
||||
- `autoMemoryDirectory` -- Custom storage directory
|
||||
- `CLAUDE_CODE_DISABLE_AUTO_MEMORY` -- Disable entirely
|
||||
- `/memory` slash command -- View/edit
|
||||
- `CLAUDE_COWORK_MEMORY_PATH_OVERRIDE` -- Override path
|
||||
- `CLAUDE_COWORK_MEMORY_EXTRA_GUIDELINES` -- Extra memory guidelines
|
||||
- `autoDreamEnabled` -- Background memory consolidation
|
||||
|
||||
## File Checkpointing
|
||||
|
||||
Claude Code can checkpoint file states for recovery:
|
||||
|
||||
- `CheckpointingEnabled` -- Feature flag
|
||||
- `CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING` -- Disable
|
||||
- `CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING` -- SDK mode
|
||||
- `/rewind` slash command -- Revert to checkpoint
|
||||
|
||||
Checkpointing tracks:
|
||||
- File content before/after edits
|
||||
- `checkpoint_count` -- Number of checkpoints
|
||||
- `checkpoint_age_entries` -- Age tracking
|
||||
|
||||
## Prompt Caching
|
||||
|
||||
Claude Code uses Anthropic's prompt caching to reduce costs:
|
||||
|
||||
- `cache_control` / `cacheControl` -- Cache control headers
|
||||
- `promptCacheSharingEnabled` -- Share cache across sessions
|
||||
- `promptCacheReadTokens` / `promptCacheWriteTokens` -- Token tracking
|
||||
- `DISABLE_PROMPT_CACHING` -- Disable globally
|
||||
- `DISABLE_PROMPT_CACHING_HAIKU/SONNET/OPUS` -- Per-model disable
|
||||
- `ENABLE_PROMPT_CACHING_1H_BEDROCK` -- 1-hour cache on Bedrock
|
||||
- `PromptCache1hAllowlist` -- Models eligible for 1h cache
|
||||
|
||||
## Idle Detection
|
||||
|
||||
- `CLAUDE_CODE_IDLE_THRESHOLD_MINUTES` -- Idle timeout
|
||||
- `CLAUDE_CODE_IDLE_TOKEN_THRESHOLD` -- Token threshold for idle
|
||||
- `CLAUDE_CODE_STALL_TIMEOUT_MS_FOR_TESTING` -- Stall detection
|
||||
|
||||
## Background Tasks
|
||||
|
||||
- `CLAUDE_AUTO_BACKGROUND_TASKS` -- Auto background task creation
|
||||
- `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS` -- Disable
|
||||
- `MessageBackground` -- Background message handling
|
||||
- Tasks can run while user is idle
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
# Claude Code CLI: Configuration and Environment
|
||||
|
||||
## Configuration Hierarchy
|
||||
|
||||
Settings are loaded from multiple sources with increasing priority:
|
||||
|
||||
```
|
||||
1. Built-in defaults (lowest)
|
||||
2. User settings: ~/.claude/settings.json
|
||||
3. Project settings: .claude/settings.json
|
||||
4. Local settings: .claude/settings.local.json
|
||||
5. Managed settings: Enterprise/team (highest for locked fields)
|
||||
6. CLI flags: --model, --permission-mode, etc. (runtime override)
|
||||
7. Environment variables: ANTHROPIC_MODEL, etc. (runtime override)
|
||||
```
|
||||
|
||||
`--setting-sources` controls which sources load: `user`, `project`, `local`.
|
||||
|
||||
## Settings Schema (76 Properties)
|
||||
|
||||
### Model Configuration
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `model` | string | Override default model |
|
||||
| `advisorModel` | string | Model for advisor tool |
|
||||
| `availableModels` | array | Allowlisted models (e.g., "opus", "sonnet") |
|
||||
| `modelOverrides` | object | Map Anthropic model IDs to provider-specific IDs |
|
||||
| `effortLevel` | string | Persisted effort level |
|
||||
| `fastMode` | boolean | Enable fast mode |
|
||||
| `fastModePerSessionOptIn` | boolean | Fast mode does not persist across sessions |
|
||||
| `alwaysThinkingEnabled` | boolean | Control thinking/reasoning |
|
||||
|
||||
### Agent Configuration
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `agent` | string | Default agent for main thread |
|
||||
| `permissions` | object | Tool permission rules (allow/deny/ask) |
|
||||
| `hooks` | object | Hook event handlers |
|
||||
| `env` | object | Environment variables for sessions |
|
||||
|
||||
### MCP Configuration
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `allowedMcpServers` | array | Enterprise MCP server allowlist |
|
||||
| `deniedMcpServers` | array | Enterprise MCP server denylist |
|
||||
| `enableAllProjectMcpServers` | boolean | Auto-approve project MCP servers |
|
||||
| `enabledMcpjsonServers` | array | Approved .mcp.json servers |
|
||||
| `disabledMcpjsonServers` | array | Rejected .mcp.json servers |
|
||||
| `allowManagedMcpServersOnly` | boolean | Lock to managed servers only |
|
||||
|
||||
### Plugin/Marketplace
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `enabledPlugins` | object | Active plugins (plugin-id@marketplace-id) |
|
||||
| `pluginConfigs` | object | Per-plugin configuration |
|
||||
| `blockedMarketplaces` | array | Blocked marketplace sources |
|
||||
| `extraKnownMarketplaces` | object | Additional marketplaces |
|
||||
| `allowedChannelPlugins` | array | Channel plugin allowlist |
|
||||
| `channelsEnabled` | boolean | Enable channel notifications |
|
||||
| `pluginTrustMessage` | string | Custom trust warning message |
|
||||
|
||||
### Session/Memory
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `autoMemoryEnabled` | boolean | Enable auto-memory |
|
||||
| `autoMemoryDirectory` | string | Custom memory storage path |
|
||||
| `autoDreamEnabled` | boolean | Background memory consolidation |
|
||||
| `cleanupPeriodDays` | integer | Transcript retention (default: 30) |
|
||||
| `autoCompactWindow` | integer | Auto-compact window size |
|
||||
| `plansDirectory` | string | Custom plan file directory |
|
||||
|
||||
### Security/Enterprise
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `allowManagedHooksOnly` | boolean | Lock to managed hooks |
|
||||
| `allowManagedPermissionRulesOnly` | boolean | Lock to managed permissions |
|
||||
| `disableAllHooks` | boolean | Disable all hooks |
|
||||
| `disableAutoMode` | string | Disable auto permission mode |
|
||||
| `forceLoginMethod` | string | Force "claudeai" or "console" auth |
|
||||
| `forceLoginOrgUUID` | string/array | Required org UUID for OAuth |
|
||||
| `minimumVersion` | string | Prevent downgrades |
|
||||
|
||||
### Display/UX
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `language` | string | Response language preference |
|
||||
| `outputStyle` | string | Output style for responses |
|
||||
| `prefersReducedMotion` | boolean | Reduce animations |
|
||||
| `feedbackSurveyRate` | number | Survey probability (0-1) |
|
||||
| `attribution` | object | Commit/PR attribution text |
|
||||
| `includeGitInstructions` | boolean | Include git workflow prompts |
|
||||
| `promptSuggestionEnabled` | boolean | Enable prompt suggestions |
|
||||
| `fileSuggestion` | object | @ mention file suggestions |
|
||||
|
||||
### Remote
|
||||
|
||||
| Setting | Type | Description |
|
||||
|---------|------|-------------|
|
||||
| `remote` | object | Remote session configuration |
|
||||
| `defaultShell` | string | Default shell (defaults to bash) |
|
||||
| `apiKeyHelper` | string | Script path for auth values |
|
||||
| `awsAuthRefresh` | string | AWS auth refresh script |
|
||||
| `awsCredentialExport` | string | AWS credential export script |
|
||||
| `gcpAuthRefresh` | string | GCP auth refresh command |
|
||||
| `otelHeadersHelper` | string | OTEL headers script |
|
||||
|
||||
## Environment Variables (498 Recognized)
|
||||
|
||||
### Critical Anthropic Variables
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `ANTHROPIC_API_KEY` | Primary API key |
|
||||
| `ANTHROPIC_AUTH_TOKEN` | Auth token |
|
||||
| `ANTHROPIC_BASE_URL` | Custom API base URL |
|
||||
| `ANTHROPIC_MODEL` | Model override |
|
||||
| `ANTHROPIC_BETAS` | Beta feature flags |
|
||||
| `ANTHROPIC_CUSTOM_HEADERS` | Custom API headers |
|
||||
|
||||
### Provider Variables
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `ANTHROPIC_BEDROCK_BASE_URL` | Bedrock endpoint |
|
||||
| `CLAUDE_CODE_USE_BEDROCK` | Enable Bedrock |
|
||||
| `CLAUDE_CODE_USE_VERTEX` | Enable Vertex AI |
|
||||
| `CLAUDE_CODE_USE_FOUNDRY` | Enable Azure Foundry |
|
||||
| `CLAUDE_CODE_USE_ANTHROPIC_AWS` | Enable Anthropic AWS |
|
||||
| `AWS_ACCESS_KEY_ID` | AWS credentials |
|
||||
| `AWS_SECRET_ACCESS_KEY` | AWS credentials |
|
||||
| `AWS_SESSION_TOKEN` | AWS session |
|
||||
| `AWS_REGION` | AWS region |
|
||||
| `ANTHROPIC_VERTEX_PROJECT_ID` | GCP project |
|
||||
| `ANTHROPIC_FOUNDRY_BASE_URL` | Azure endpoint |
|
||||
| `ANTHROPIC_FOUNDRY_API_KEY` | Azure key |
|
||||
|
||||
### Model Configuration Variables
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `ANTHROPIC_DEFAULT_SONNET_MODEL` | Default Sonnet model ID |
|
||||
| `ANTHROPIC_DEFAULT_OPUS_MODEL` | Default Opus model ID |
|
||||
| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | Default Haiku model ID |
|
||||
| `ANTHROPIC_SMALL_FAST_MODEL` | Small/fast model for subtasks |
|
||||
| `CLAUDE_CODE_SUBAGENT_MODEL` | Model for subagents |
|
||||
|
||||
### Feature Flags (CLAUDE_CODE_*)
|
||||
|
||||
Over 120 `CLAUDE_CODE_*` variables control features:
|
||||
|
||||
**Disable flags**: `CLAUDE_CODE_DISABLE_*`
|
||||
- `_AUTO_MEMORY`, `_BACKGROUND_TASKS`, `_CLAUDE_MDS`, `_CRON`
|
||||
- `_FAST_MODE`, `_FILE_CHECKPOINTING`, `_GIT_INSTRUCTIONS`
|
||||
- `_THINKING`, `_VIRTUAL_SCROLL`, `_MOUSE`, `_TERMINAL_TITLE`
|
||||
- `_ATTACHMENTS`, `_EXPERIMENTAL_BETAS`, `_FEEDBACK_SURVEY`
|
||||
- `_1M_CONTEXT`, `_ADAPTIVE_THINKING`, `_POLICY_SKILLS`
|
||||
|
||||
**Enable flags**: `CLAUDE_CODE_ENABLE_*`
|
||||
- `_CFC`, `_FINE_GRAINED_TOOL_STREAMING`, `_PROMPT_SUGGESTION`
|
||||
- `_SDK_FILE_CHECKPOINTING`, `_TASKS`, `_TELEMETRY`
|
||||
- `_TOKEN_USAGE_ATTACHMENT`, `_XAA`
|
||||
|
||||
**Configuration**: `CLAUDE_CODE_*`
|
||||
- `_EFFORT_LEVEL`, `_MAX_OUTPUT_TOKENS`, `_MAX_RETRIES`
|
||||
- `_SHELL`, `_SHELL_PREFIX`, `_TMPDIR`
|
||||
- `_GLOB_TIMEOUT_SECONDS`, `_GLOB_HIDDEN`, `_GLOB_NO_IGNORE`
|
||||
- `_SCROLL_SPEED`, `_IDLE_THRESHOLD_MINUTES`
|
||||
- `_OAUTH_TOKEN`, `_OAUTH_CLIENT_ID`, `_OAUTH_SCOPES`
|
||||
|
||||
### Bash Sandbox Variables
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `BASH_MAX_OUTPUT_LENGTH` | Max Bash tool output |
|
||||
| `CLAUDE_CODE_BUBBLEWRAP` | Bubblewrap sandbox config |
|
||||
| `CLAUDE_CODE_BASH_SANDBOX_SHOW_INDICATOR` | Show sandbox indicator |
|
||||
| `CLAUDE_CODE_BASH_MAINTAIN_PROJECT_WORKING_DIR` | Maintain cwd |
|
||||
|
||||
## Claude Home Directory Structure
|
||||
|
||||
```
|
||||
~/.claude/
|
||||
settings.json # User settings
|
||||
keybindings.json # Custom keybindings
|
||||
CLAUDE.md # Global user instructions
|
||||
scheduled_tasks.json # Cron-like tasks
|
||||
agents/ # Custom agent definitions
|
||||
commands/ # Custom slash commands
|
||||
debug/ # Debug logs
|
||||
local/ # Local data
|
||||
claude # Local state
|
||||
node_modules/ # Cached modules
|
||||
plans/ # Saved plans
|
||||
plugins/ # Installed plugins
|
||||
data/ # Plugin data
|
||||
projects/ # Per-project data
|
||||
<hash>/ # Project-specific
|
||||
memory/MEMORY.md # Auto-memory
|
||||
remote/ # Remote session data
|
||||
rules/ # Custom rules
|
||||
```
|
||||
|
||||
## Project Configuration Files
|
||||
|
||||
```
|
||||
.claude/
|
||||
settings.json # Project settings
|
||||
settings.local.json # Local overrides (gitignored)
|
||||
agents/ # Project-specific agents
|
||||
skills/
|
||||
deploy/SKILL.md # Skill definitions
|
||||
|
||||
.mcp.json # MCP server definitions
|
||||
.claudeignore # Files to ignore
|
||||
CLAUDE.md # Project instructions
|
||||
```
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
# Claude Code CLI: Agent and Subagent System
|
||||
|
||||
## Agent Architecture
|
||||
|
||||
### Core Agent Types
|
||||
|
||||
| Type | Internal Reference | Purpose |
|
||||
|------|-------------------|---------|
|
||||
| `default` | Built-in | Standard Claude Code agent |
|
||||
| `advisor` | AgentModel/AgentConfig | Advisory/review agent |
|
||||
| `reviewer` | AgentPlugin | Code review agent |
|
||||
| `custom` | AgentFromJson/AgentFromMarkdown | User-defined agents |
|
||||
|
||||
### Agent Definition Sources
|
||||
|
||||
Agents can be defined from multiple sources:
|
||||
|
||||
1. **Built-in agents**: Compiled into the binary
|
||||
2. **JSON definitions**: `.claude/agents/*.json`
|
||||
3. **Markdown definitions**: `.claude/agents/*.md`
|
||||
4. **CLI `--agents` flag**: Inline JSON
|
||||
5. **`--agent` flag**: Select a named agent
|
||||
6. **Plugin agents**: From marketplace plugins
|
||||
|
||||
### Agent Definition Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"reviewer": {
|
||||
"description": "Reviews code for quality and correctness",
|
||||
"prompt": "You are a code reviewer...",
|
||||
"model": "claude-sonnet-4-6",
|
||||
"tools": ["Read", "Glob", "Grep"],
|
||||
"hooks": { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Agent State Machine
|
||||
|
||||
```
|
||||
AgentBaseInternalState
|
||||
|
|
||||
v
|
||||
AgentBusy -> AgentContext -> AgentMode
|
||||
|
|
||||
v
|
||||
AgentSubmit -> API Call -> Response Processing
|
||||
|
|
||||
v
|
||||
AgentOutputTool -> Tool Execution -> Result
|
||||
```
|
||||
|
||||
### Agent Configuration
|
||||
|
||||
| Property | Purpose |
|
||||
|----------|---------|
|
||||
| `AgentConfig` | Full agent configuration |
|
||||
| `AgentDefinition` | Agent spec (name, prompt, tools) |
|
||||
| `AgentOptions` | Runtime options |
|
||||
| `AgentModel` | Model override per agent |
|
||||
| `AgentColorMap` | Visual differentiation |
|
||||
| `AgentPrefix` | Message prefix per agent |
|
||||
| `AgentLanguages` | Language settings |
|
||||
| `AgentOperatingSystem` | OS-specific behavior |
|
||||
| `AgentPolicy` | Policy constraints |
|
||||
| `AgentMiddleware` | Processing middleware |
|
||||
| `AgentProgressSummariesEnabled` | Progress tracking |
|
||||
|
||||
### Agent Factory
|
||||
|
||||
`AgentFactoryFromOptions` creates agents from configuration:
|
||||
- Resolves agent definitions from cache: `AgentDefinitionsCache`
|
||||
- Applies overrides: `AgentDefinitionsWithOverrides`
|
||||
- Sets up agent context with tools, permissions, hooks
|
||||
|
||||
## Subagent / Task System
|
||||
|
||||
### Task Tool
|
||||
|
||||
The `Task` tool spawns subagents for parallel work:
|
||||
|
||||
```
|
||||
Main Agent
|
||||
|-- Task("Review auth module") -> Subagent 1
|
||||
|-- Task("Write unit tests") -> Subagent 2
|
||||
|-- Task("Update docs") -> Subagent 3
|
||||
```
|
||||
|
||||
### Subagent Types
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `SubagentStart` | Subagent creation event |
|
||||
| `SubagentStop` | Subagent completion event |
|
||||
| `SubagentEventReader` | Read subagent events |
|
||||
| `SubagentInternalEvents` | Internal event bus |
|
||||
| `SubagentTranscripts` | Conversation history |
|
||||
| `SubagentTranscriptsFromDisk` | Persisted transcripts |
|
||||
| `SubagentStartHooks` | Hooks for subagent creation |
|
||||
|
||||
### Task Lifecycle
|
||||
|
||||
```
|
||||
TaskCreated
|
||||
|
|
||||
v
|
||||
TaskAssignment -> TaskAgent
|
||||
|
|
||||
v
|
||||
TaskActiveQ (queue management)
|
||||
|
|
||||
v
|
||||
TaskAbort / TaskCompleted
|
||||
|
|
||||
v
|
||||
TaskAbortReasonInfo (if aborted)
|
||||
```
|
||||
|
||||
### Task Configuration
|
||||
|
||||
| Config | Purpose |
|
||||
|--------|---------|
|
||||
| `CLAUDE_CODE_ENABLE_TASKS` | Enable task system |
|
||||
| `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` | Max parallel tools |
|
||||
| `TASK_MAX_OUTPUT_LENGTH` | Max task output |
|
||||
| `CLAUDE_CODE_PLAN_V2_AGENT_COUNT` | Plan mode agent count |
|
||||
| `CLAUDE_CODE_PLAN_V2_EXPLORE_AGENT_COUNT` | Exploration agents |
|
||||
| `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` | Experimental teams |
|
||||
|
||||
### Agent Cost Steering
|
||||
|
||||
`CLAUDE_CODE_AGENT_COST_STEER` -- Controls cost optimization for
|
||||
multi-agent scenarios, balancing between model quality and cost.
|
||||
|
||||
### Agent List in Messages
|
||||
|
||||
`CLAUDE_CODE_AGENT_LIST_IN_MESSAGES` -- Include agent list in
|
||||
conversation messages for context.
|
||||
|
||||
## Skill System
|
||||
|
||||
Skills are reusable capability modules that extend Claude Code:
|
||||
|
||||
### Skill Discovery
|
||||
|
||||
- `.claude/skills/` directory
|
||||
- `.claude/commands/` directory (legacy)
|
||||
- `/skills` slash command -- List available
|
||||
- `--disable-slash-commands` -- Disable all skills
|
||||
- `SLASH_COMMAND_TOOL_CHAR_BUDGET` -- Character budget for skill content
|
||||
|
||||
### Skill Definition Format
|
||||
|
||||
Skills are defined as Markdown files with YAML frontmatter:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: deploy
|
||||
description: Deploy the application
|
||||
tools: [Bash, Read]
|
||||
---
|
||||
|
||||
# Deploy Skill
|
||||
|
||||
Instructions for deployment workflow...
|
||||
```
|
||||
|
||||
### Plugin System
|
||||
|
||||
Plugins extend Claude Code through marketplace:
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| `PluginAgent` | Agent provided by plugin |
|
||||
| `PluginCache` | Plugin artifact cache |
|
||||
| `PluginConfiguration` | Plugin settings |
|
||||
| `PluginControl` | Plugin lifecycle management |
|
||||
| `PluginAutoupdate` | Auto-update mechanism |
|
||||
| `PluginEditableScopes` | Configurable scopes |
|
||||
| `PluginAffectingSettingsSnapshot` | Settings impact tracking |
|
||||
|
||||
### Marketplace Integration
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| `MarketplaceFromGcs` | GCS-hosted marketplace |
|
||||
| `MarketplaceIsPrivate` | Private marketplace flag |
|
||||
| `MarketplaceAutoInstalled` | Auto-installed plugins |
|
||||
| `MarketplaceModelEndpoint` | Model endpoint plugins |
|
||||
| `MarketplaceModelEndpoints` | Multiple endpoints |
|
||||
| `MarketplaceDependenciesOn` | Dependency tracking |
|
||||
|
||||
Plugin configuration:
|
||||
- `CLAUDE_CODE_PLUGIN_CACHE_DIR` -- Cache location
|
||||
- `CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS` -- Git operation timeout
|
||||
- `CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE` -- Resilience
|
||||
- `CLAUDE_CODE_PLUGIN_SEED_DIR` -- Seed directory
|
||||
- `CLAUDE_CODE_PLUGIN_USE_ZIP_CACHE` -- Zip caching
|
||||
- `FORCE_AUTOUPDATE_PLUGINS` -- Force updates
|
||||
- `CLAUDE_CODE_SYNC_PLUGIN_INSTALL` -- Synchronous install
|
||||
- `CLAUDE_CODE_USE_COWORK_PLUGINS` -- Cowork plugin support
|
||||
163
docs/research/claude-code-rvsource/10-models-and-api.md
Normal file
163
docs/research/claude-code-rvsource/10-models-and-api.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Claude Code CLI: Models and API Integration
|
||||
|
||||
## Supported Models
|
||||
|
||||
### Model References Found in Source
|
||||
|
||||
| Model ID | Family | Notes |
|
||||
|----------|--------|-------|
|
||||
| `claude-opus-4-6` | Opus | Latest (current default for complex) |
|
||||
| `claude-opus-4-5` | Opus | |
|
||||
| `claude-opus-4-5-20251101` | Opus | Dated release |
|
||||
| `claude-opus-4-1` | Opus | |
|
||||
| `claude-opus-4-1-20250805` | Opus | Dated release |
|
||||
| `claude-opus-4-0` | Opus | |
|
||||
| `claude-opus-4` | Opus | Alias |
|
||||
| `claude-opus-4-20250514` | Opus | Dated release |
|
||||
| `claude-4-opus-20250514` | Opus | Legacy naming |
|
||||
| `claude-sonnet-4-6` | Sonnet | Latest Sonnet |
|
||||
| `claude-sonnet-4-5` | Sonnet | |
|
||||
| `claude-sonnet-4-5-20250929` | Sonnet | Dated release |
|
||||
| `claude-sonnet-4` | Sonnet | Alias |
|
||||
| `claude-sonnet-4-20250514` | Sonnet | Dated release |
|
||||
| `claude-sonnet-3-7` | Sonnet | Legacy |
|
||||
| `claude-3-7-sonnet-20250219` | Sonnet | Legacy naming |
|
||||
| `claude-3-5-sonnet-20241022` | Sonnet | Legacy |
|
||||
| `claude-3-sonnet-20240229` | Sonnet | Legacy |
|
||||
| `claude-haiku-4-5` | Haiku | |
|
||||
| `claude-haiku-4-5-20251001` | Haiku | Dated release |
|
||||
| `claude-haiku-4` | Haiku | Alias |
|
||||
| `claude-haiku-3-5` | Haiku | Legacy |
|
||||
| `claude-3-5-haiku-20241022` | Haiku | Legacy naming |
|
||||
| `claude-instant-1.1` | Instant | Legacy |
|
||||
| `claude-instant-1.2` | Instant | Legacy |
|
||||
| `claude-code-20250219` | Code | Specialized code model |
|
||||
| `claude-3-opus-20240229` | Opus | Legacy |
|
||||
|
||||
### Model Selection
|
||||
|
||||
| Mechanism | Priority | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `--model` CLI flag | Highest | Runtime override |
|
||||
| `ANTHROPIC_MODEL` env var | High | Environment override |
|
||||
| `model` in settings | Medium | Persistent config |
|
||||
| `availableModels` allowlist | - | Restricts options |
|
||||
| `mainLoopModel` | - | Internal selection |
|
||||
| Built-in default | Lowest | Fallback |
|
||||
|
||||
### Model Aliases
|
||||
|
||||
Users can specify short aliases: `"opus"`, `"sonnet"`, `"haiku"`.
|
||||
The `availableModels` allowlist accepts these aliases, which map to
|
||||
the latest model in each family.
|
||||
|
||||
### Model Overrides
|
||||
|
||||
`modelOverrides` maps Anthropic model IDs to provider-specific IDs:
|
||||
|
||||
```json
|
||||
{
|
||||
"modelOverrides": {
|
||||
"claude-sonnet-4-6": "us.anthropic.claude-sonnet-4-6-v1:0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Integration
|
||||
|
||||
### Anthropic Direct API
|
||||
|
||||
- Endpoint: `ANTHROPIC_BASE_URL` (default: `https://api.anthropic.com`)
|
||||
- Authentication: `ANTHROPIC_API_KEY` or OAuth token
|
||||
- Unix socket: `ANTHROPIC_UNIX_SOCKET` for local proxying
|
||||
|
||||
### API Endpoints Used
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|----------|---------|
|
||||
| `/v1/messages` | Main conversation API (streaming) |
|
||||
| `/v1/messages/count_tokens` | Token counting |
|
||||
| `/v1/messages/batches` | Batch processing |
|
||||
| `/v1/models` | Model listing |
|
||||
| `/v1/complete` | Legacy completion |
|
||||
| `/v1/token` | Token validation |
|
||||
| `/v1/files` | File management |
|
||||
| `/v1/code/upstreamproxy/ws` | WebSocket proxy |
|
||||
| `/v2/session_ingress/shttp/mcp/` | MCP session ingress |
|
||||
|
||||
### Provider Backends
|
||||
|
||||
| Provider | Client | Auth |
|
||||
|----------|--------|------|
|
||||
| Anthropic Direct | `Anthropic` (SDK) | API key / OAuth |
|
||||
| AWS Bedrock | `BedrockClient` / `BedrockRuntimeClient` | AWS IAM |
|
||||
| Google Vertex AI | Native HTTP | GCP credentials |
|
||||
| Azure Foundry | Native HTTP | Azure credentials |
|
||||
| Anthropic AWS | `AnthropicAws` | Hybrid auth |
|
||||
|
||||
### Prompt Caching
|
||||
|
||||
Anthropic's prompt caching reduces repeat token costs:
|
||||
|
||||
- `cache_control: { type: "ephemeral" }` -- Standard cache
|
||||
- 1-hour cache on Bedrock (`ENABLE_PROMPT_CACHING_1H_BEDROCK`)
|
||||
- Per-model disable: `DISABLE_PROMPT_CACHING_HAIKU/SONNET/OPUS`
|
||||
- Cache sharing: `promptCacheSharingEnabled`
|
||||
- Token tracking: `promptCacheReadTokens`, `promptCacheWriteTokens`
|
||||
|
||||
### Retry and Fallback
|
||||
|
||||
- `CLAUDE_CODE_MAX_RETRIES` -- Max API retry count
|
||||
- `--fallback-model` -- Fallback model for overload (print mode only)
|
||||
- `FALLBACK_FOR_ALL_PRIMARY_MODELS` -- Universal fallback
|
||||
- `CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS` -- Skip on network errors
|
||||
- `CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK` -- Disable non-streaming fallback
|
||||
|
||||
### Request Customization
|
||||
|
||||
- `ANTHROPIC_BETAS` / `--betas` -- Beta feature headers
|
||||
- `ANTHROPIC_CUSTOM_HEADERS` -- Custom request headers
|
||||
- `CLAUDE_CODE_EXTRA_BODY` -- Extra request body fields
|
||||
- `CLAUDE_CODE_EXTRA_METADATA` -- Extra metadata
|
||||
- `API_TIMEOUT_MS` -- Request timeout
|
||||
- `CLAUDE_CODE_ATTRIBUTION_HEADER` -- Attribution header
|
||||
- `CLAUDE_CODE_STALL_TIMEOUT_MS_FOR_TESTING` -- Stall detection
|
||||
|
||||
### Structured Output
|
||||
|
||||
- `--json-schema` -- Enforce JSON schema on output
|
||||
- `MAX_STRUCTURED_OUTPUT_RETRIES` -- Retry on schema validation failure
|
||||
|
||||
### Token Management
|
||||
|
||||
- `MAX_THINKING_TOKENS` -- Cap thinking tokens
|
||||
- `CLAUDE_CODE_MAX_OUTPUT_TOKENS` -- Cap output tokens
|
||||
- `CLAUDE_CODE_FILE_READ_MAX_OUTPUT_TOKENS` -- File read budget
|
||||
- `CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE` -- Rate limit override
|
||||
- Token counting via `/v1/messages/count_tokens`
|
||||
|
||||
### Effort Level
|
||||
|
||||
- `--effort` CLI flag: `low`, `medium`, `high`, `max`
|
||||
- `CLAUDE_CODE_EFFORT_LEVEL` env var
|
||||
- `effortLevel` in settings
|
||||
- `CLAUDE_CODE_ALWAYS_ENABLE_EFFORT` -- Always apply effort level
|
||||
- `/effort` slash command -- Interactive change
|
||||
|
||||
### Thinking/Reasoning
|
||||
|
||||
- `alwaysThinkingEnabled` -- Enable extended thinking
|
||||
- `CLAUDE_CODE_DISABLE_THINKING` -- Disable thinking
|
||||
- `CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING` -- Disable adaptive mode
|
||||
- `DISABLE_INTERLEAVED_THINKING` -- Disable interleaved thinking
|
||||
- `MAX_THINKING_TOKENS` -- Token budget for thinking
|
||||
- `CLAUDE_CODE_DISABLE_FAST_MODE` -- Disable fast mode shortcut
|
||||
|
||||
### Fast Mode
|
||||
|
||||
Fast mode uses smaller/faster models for simple operations:
|
||||
- `fastMode` setting (boolean)
|
||||
- `fastModePerSessionOptIn` -- Opt-in per session
|
||||
- `/fast` slash command -- Toggle
|
||||
- `ANTHROPIC_SMALL_FAST_MODEL` -- Custom small model
|
||||
- `ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION` -- Region for small model
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
# Claude Code CLI: Telemetry and Observability
|
||||
|
||||
## Telemetry System
|
||||
|
||||
### OpenTelemetry Integration
|
||||
|
||||
Claude Code has deep OpenTelemetry (OTEL) integration for tracing,
|
||||
metrics, and logging:
|
||||
|
||||
**OTEL Environment Variables**:
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP endpoint URL |
|
||||
| `OTEL_EXPORTER_OTLP_HEADERS` | Authentication headers |
|
||||
| `OTEL_EXPORTER_OTLP_PROTOCOL` | Protocol (grpc/http) |
|
||||
| `OTEL_EXPORTER_OTLP_INSECURE` | Allow insecure connections |
|
||||
| `OTEL_TRACES_EXPORTER` | Trace exporter type |
|
||||
| `OTEL_METRICS_EXPORTER` | Metrics exporter type |
|
||||
| `OTEL_LOGS_EXPORTER` | Log exporter type |
|
||||
| `OTEL_TRACES_EXPORT_INTERVAL` | Trace export interval |
|
||||
| `OTEL_METRICS_EXPORT_INTERVAL` | Metrics export interval |
|
||||
| `OTEL_LOGS_EXPORT_INTERVAL` | Log export interval |
|
||||
|
||||
**Batch processing**:
|
||||
- `OTEL_BSP_MAX_QUEUE_SIZE` -- Span batch queue
|
||||
- `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` -- Span batch size
|
||||
- `OTEL_BSP_EXPORT_TIMEOUT` -- Span export timeout
|
||||
- `OTEL_BSP_SCHEDULE_DELAY` -- Span schedule delay
|
||||
- `OTEL_BLRP_*` -- Log record processor equivalents
|
||||
|
||||
**Limits**:
|
||||
- `OTEL_ATTRIBUTE_COUNT_LIMIT` -- Max attributes per span
|
||||
- `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT` -- Max attribute value length
|
||||
|
||||
**Shutdown**:
|
||||
- `CLAUDE_CODE_OTEL_FLUSH_TIMEOUT_MS` -- Flush timeout
|
||||
- `CLAUDE_CODE_OTEL_SHUTDOWN_TIMEOUT_MS` -- Shutdown timeout
|
||||
|
||||
**Headers helper**:
|
||||
- `otelHeadersHelper` setting -- Script to generate OTEL headers
|
||||
- `CLAUDE_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MS` -- Debounce
|
||||
|
||||
### Datadog Integration
|
||||
|
||||
`Datadog` type referenced -- native Datadog APM support.
|
||||
- `CLAUDE_CODE_DATADOG_FLUSH_INTERVAL_MS` -- Flush interval
|
||||
|
||||
### Perfetto Tracing
|
||||
|
||||
`CLAUDE_CODE_PERFETTO_TRACE` -- Enable Perfetto trace output for
|
||||
Chrome DevTools-compatible performance profiling.
|
||||
|
||||
### CPU Profiling
|
||||
|
||||
`CLAUDE_CODE_PROFILE_STARTUP` -- Profile CLI startup performance.
|
||||
|
||||
### What Gets Tracked
|
||||
|
||||
**Telemetry flags**:
|
||||
- `CLAUDE_CODE_ENABLE_TELEMETRY` -- Master telemetry switch
|
||||
- `ENABLE_ENHANCED_TELEMETRY_BETA` -- Enhanced telemetry
|
||||
- `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA` -- Enhanced telemetry (alt)
|
||||
- `DISABLE_TELEMETRY` -- Disable all telemetry
|
||||
- `OTEL_LOG_TOOL_CONTENT` -- Log tool content
|
||||
- `OTEL_LOG_TOOL_DETAILS` -- Log tool details
|
||||
- `OTEL_LOG_USER_PROMPTS` -- Log user prompts
|
||||
- `BETA_TRACING_ENDPOINT` -- Beta tracing
|
||||
- `ENABLE_BETA_TRACING_DETAILED` -- Detailed beta traces
|
||||
|
||||
**Metrics tracked** (inferred from patterns):
|
||||
- Session lifecycle events
|
||||
- Tool execution duration and outcome
|
||||
- API call latency and token usage
|
||||
- Model selection and fallback events
|
||||
- Permission decisions
|
||||
- Context compaction frequency
|
||||
- Error rates and types
|
||||
- Plugin/MCP server health
|
||||
|
||||
## Debugging
|
||||
|
||||
### Debug Mode
|
||||
|
||||
`-d, --debug [filter]` -- Enable debug with optional category filter.
|
||||
|
||||
Filter categories: `api`, `hooks`, `mcp`, `file`, `1p`, etc.
|
||||
Prefix with `!` to exclude: `"!1p,!file"`.
|
||||
|
||||
### Debug Output
|
||||
|
||||
- `CLAUDE_CODE_DEBUG_LOGS_DIR` -- Custom debug log directory
|
||||
- `--debug-file <path>` -- Write to specific file
|
||||
- `CLAUDE_CODE_DEBUG_LOG_LEVEL` -- Log level
|
||||
- `CLAUDE_DEBUG` -- Legacy debug flag
|
||||
- `DEBUG` -- Node.js debug namespace
|
||||
- `DEBUG_AUTH` -- Authentication debugging
|
||||
- `DEBUG_SDK` -- SDK debugging
|
||||
|
||||
### Diagnostics
|
||||
|
||||
`claude doctor` / `/doctor` -- Built-in diagnostics:
|
||||
- Check MCP server connections
|
||||
- Verify authentication
|
||||
- Test API connectivity
|
||||
- Validate configuration
|
||||
- Check permissions
|
||||
|
||||
### Frame Timing
|
||||
|
||||
`CLAUDE_CODE_FRAME_TIMING_LOG` -- Log UI frame timing for
|
||||
rendering performance analysis.
|
||||
|
||||
### Debug Repaints
|
||||
|
||||
`CLAUDE_CODE_DEBUG_REPAINTS` -- Highlight UI repaints for
|
||||
debugging rendering performance.
|
||||
|
||||
## Error Reporting
|
||||
|
||||
- `DISABLE_ERROR_REPORTING` -- Disable crash/error reporting
|
||||
- Error context captured with session info
|
||||
- Stack traces sent with telemetry (when enabled)
|
||||
|
||||
## Cost Tracking
|
||||
|
||||
- `/cost` slash command -- View session costs
|
||||
- `/extra-usage` -- Detailed usage breakdown
|
||||
- Token usage per turn tracked
|
||||
- Cost counter: `getCostCounter`
|
||||
- Commit counter: `getCommitCounter`
|
||||
- Budget enforcement: `--max-budget-usd`
|
||||
|
||||
## Stream Watchdog
|
||||
|
||||
`CLAUDE_ENABLE_STREAM_WATCHDOG` -- Monitor streaming health.
|
||||
`CLAUDE_STREAM_IDLE_TIMEOUT_MS` -- Detect stalled streams.
|
||||
|
||||
## Slow Operation Detection
|
||||
|
||||
`CLAUDE_CODE_SLOW_OPERATION_THRESHOLD_MS` -- Flag operations
|
||||
exceeding this threshold for investigation.
|
||||
257
docs/research/claude-code-rvsource/12-dependency-graph.md
Normal file
257
docs/research/claude-code-rvsource/12-dependency-graph.md
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
# Claude Code CLI: Dependency and Module Graph
|
||||
|
||||
## High-Level Architecture Graph
|
||||
|
||||
```
|
||||
+------------------------------------------------------------------+
|
||||
| Claude Code CLI |
|
||||
+------------------------------------------------------------------+
|
||||
| |
|
||||
| +-----------+ +-------------+ +-----------+ |
|
||||
| | CLI Entry | | VS Code Ext | | Agent SDK | |
|
||||
| | (Bun SEA) | | (extension) | | (library) | |
|
||||
| +-----+-----+ +------+------+ +-----+-----+ |
|
||||
| | | | |
|
||||
| +------------------+-----------------+ |
|
||||
| | |
|
||||
| +------v------+ |
|
||||
| | Main Loop | |
|
||||
| | Engine | |
|
||||
| +------+------+ |
|
||||
| | |
|
||||
| +------------------+------------------+ |
|
||||
| | | | |
|
||||
| +-----v-----+ +------v------+ +------v------+ |
|
||||
| | Tool | | Context | | Permission | |
|
||||
| | System | | Manager | | System | |
|
||||
| +-----+-----+ +------+------+ +------+------+ |
|
||||
| | | | |
|
||||
| +-----v-----+ +------v------+ +------v------+ |
|
||||
| | MCP Client | | Session | | Sandbox | |
|
||||
| | Framework | | Persistence | | Manager | |
|
||||
| +-----+-----+ +------+------+ +------+------+ |
|
||||
| | | | |
|
||||
| +-----v-----+ +------v------+ +------v------+ |
|
||||
| | Hook | | Prompt | | Auth | |
|
||||
| | Engine | | Cache | | Providers | |
|
||||
| +-----------+ +-------------+ +-------------+ |
|
||||
| |
|
||||
+------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Module Dependency Graph
|
||||
|
||||
### Core Modules
|
||||
|
||||
```
|
||||
Main Loop Engine
|
||||
depends on:
|
||||
-> Tool System (tool dispatch, execution)
|
||||
-> Context Manager (token tracking, compaction)
|
||||
-> Permission System (tool approval)
|
||||
-> API Client (Anthropic Messages API)
|
||||
-> Session Manager (persistence, resume)
|
||||
-> Hook Engine (lifecycle events)
|
||||
-> Agent System (multi-agent coordination)
|
||||
-> Streaming Handler (SSE processing)
|
||||
```
|
||||
|
||||
### Tool System Dependencies
|
||||
|
||||
```
|
||||
Tool System
|
||||
depends on:
|
||||
-> Permission System (pre-execution check)
|
||||
-> Sandbox Manager (Bash tool isolation)
|
||||
-> MCP Client (external tool execution)
|
||||
-> File System (Read/Write/Edit tools)
|
||||
-> Process Manager (Bash tool, Task tool)
|
||||
-> Hook Engine (PreToolUse/PostToolUse)
|
||||
provides:
|
||||
-> Tool results to Main Loop
|
||||
-> Tool schemas to API Client
|
||||
```
|
||||
|
||||
### MCP Client Dependencies
|
||||
|
||||
```
|
||||
MCP Client Framework
|
||||
depends on:
|
||||
-> Transport Layer (stdio/SSE/HTTP/WebSocket)
|
||||
-> OAuth Handler (remote server auth)
|
||||
-> Configuration System (server definitions)
|
||||
-> Tool Registry (tool discovery)
|
||||
provides:
|
||||
-> Extended tools to Tool System
|
||||
-> Resources to Context Manager
|
||||
-> Prompts to Main Loop
|
||||
```
|
||||
|
||||
### Permission System Dependencies
|
||||
|
||||
```
|
||||
Permission System
|
||||
depends on:
|
||||
-> Configuration (rules, mode)
|
||||
-> Hook Engine (PreToolUse can override)
|
||||
-> Sandbox Manager (OS-level enforcement)
|
||||
-> UI Layer (permission prompts)
|
||||
provides:
|
||||
-> Allow/Deny decisions to Tool System
|
||||
-> Audit log to Telemetry
|
||||
```
|
||||
|
||||
### Agent System Dependencies
|
||||
|
||||
```
|
||||
Agent System
|
||||
depends on:
|
||||
-> Main Loop Engine (conversation execution)
|
||||
-> Tool System (tool subsets per agent)
|
||||
-> Session Manager (subagent persistence)
|
||||
-> Configuration (agent definitions)
|
||||
-> Plugin System (plugin agents)
|
||||
provides:
|
||||
-> Subagent execution to Task tool
|
||||
-> Agent selection to Main Loop
|
||||
```
|
||||
|
||||
## External Dependencies
|
||||
|
||||
### Node.js Built-ins (via Bun)
|
||||
|
||||
```
|
||||
node:fs / node:fs/promises -- File operations
|
||||
node:child_process -- Process spawning (Bash tool)
|
||||
node:path -- Path manipulation
|
||||
node:os -- OS detection
|
||||
node:stream -- Streaming
|
||||
node:events -- Event emitter
|
||||
node:crypto -- Cryptography
|
||||
node:http / node:https -- HTTP client
|
||||
node:tls -- TLS
|
||||
node:net -- TCP/Unix sockets
|
||||
node:async_hooks -- Async context tracking
|
||||
node:readline -- Terminal input
|
||||
node:tty -- Terminal detection
|
||||
node:worker_threads -- Worker threads
|
||||
node:buffer -- Buffer handling
|
||||
node:dns -- DNS resolution
|
||||
node:timers/promises -- Async timers
|
||||
node:util/types -- Type checking
|
||||
node:inspector -- V8 inspector
|
||||
node:perf_hooks -- Performance hooks
|
||||
node:string_decoder -- String decoding
|
||||
```
|
||||
|
||||
### Bundled Libraries
|
||||
|
||||
| Library | Purpose |
|
||||
|---------|---------|
|
||||
| Anthropic SDK | API client (`new Anthropic()`) |
|
||||
| AWS SDK (Bedrock) | `BedrockClient`, `BedrockRuntimeClient` |
|
||||
| AWS SDK (Cognito/SSO/STS) | Authentication |
|
||||
| Google Auth Library | GCP authentication |
|
||||
| Azure Identity | Azure authentication |
|
||||
| Ajv | JSON Schema validation |
|
||||
| Commander.js | CLI argument parsing |
|
||||
| proper-lockfile | File locking |
|
||||
| fast-xml-parser | XML processing |
|
||||
| gRPC | gRPC client (for Google APIs) |
|
||||
| OpenTelemetry SDK | Observability |
|
||||
| Datadog SDK | APM integration |
|
||||
|
||||
### Bun-Specific APIs
|
||||
|
||||
```
|
||||
bun:sqlite -- SQLite (for local storage)
|
||||
bun:test -- Testing framework
|
||||
Bun.serve() -- HTTP server
|
||||
Bun.file() -- File handling
|
||||
```
|
||||
|
||||
## Data Flow Graph
|
||||
|
||||
```
|
||||
User Input
|
||||
|
|
||||
v
|
||||
[CLI Parser / VS Code Extension]
|
||||
|
|
||||
v
|
||||
[System Prompt Builder]
|
||||
- CLAUDE.md files
|
||||
- Auto-memory
|
||||
- Agent instructions
|
||||
- Tool descriptions
|
||||
- Git status
|
||||
|
|
||||
v
|
||||
[Message Array Builder]
|
||||
- System prompt
|
||||
- Conversation history
|
||||
- Tool results
|
||||
|
|
||||
v
|
||||
[API Client] ---> Anthropic Messages API
|
||||
| |
|
||||
v v
|
||||
[Stream Handler] [Prompt Cache]
|
||||
|
|
||||
v
|
||||
[Response Processor]
|
||||
| | |
|
||||
v v v
|
||||
[Text] [Thinking] [Tool Use]
|
||||
|
|
||||
v
|
||||
[Permission Check]
|
||||
|
|
||||
+-----+-----+
|
||||
| |
|
||||
v v
|
||||
[Approve] [Deny]
|
||||
| |
|
||||
v v
|
||||
[Tool Execute] [Error Response]
|
||||
|
|
||||
v
|
||||
[Tool Result]
|
||||
|
|
||||
v
|
||||
[Back to API Client for next turn]
|
||||
```
|
||||
|
||||
## State Management Graph
|
||||
|
||||
```
|
||||
Session State
|
||||
|-- Conversation History (messages array)
|
||||
|-- Tool Permission Cache (approved patterns)
|
||||
|-- MCP Connections (active servers)
|
||||
|-- File Checkpoints (edit history)
|
||||
|-- Auto-Memory (MEMORY.md)
|
||||
|-- Token Counter (usage tracking)
|
||||
|-- Cost Counter (spend tracking)
|
||||
|-- Agent State (active agent config)
|
||||
|-- Compact State (compaction history)
|
||||
|-- Plugin State (active plugins)
|
||||
```
|
||||
|
||||
## Initialization Sequence
|
||||
|
||||
```
|
||||
1. Binary boot (Bun runtime init)
|
||||
2. CLI argument parsing (Commander.js)
|
||||
3. Configuration loading (settings cascade)
|
||||
4. Authentication (API key / OAuth / AWS / GCP / Azure)
|
||||
5. CLAUDE.md discovery and loading
|
||||
6. MCP server connections (batch, parallel)
|
||||
7. Tool registry build (built-in + MCP + deferred)
|
||||
8. Session init or resume
|
||||
9. Git status collection (if in repo)
|
||||
10. System prompt assembly
|
||||
11. Hook system initialization
|
||||
12. Plugin sync (if enabled)
|
||||
13. Main loop start
|
||||
```
|
||||
283
docs/research/claude-code-rvsource/13-extension-points.md
Normal file
283
docs/research/claude-code-rvsource/13-extension-points.md
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
# Claude Code CLI: Extension Points
|
||||
|
||||
## Overview
|
||||
|
||||
Claude Code has multiple extension mechanisms, each serving different
|
||||
integration depths. This document catalogs all identified extension points.
|
||||
|
||||
## 1. MCP Servers (Primary Extension)
|
||||
|
||||
**Integration depth**: Add tools, resources, and prompts.
|
||||
|
||||
```json
|
||||
// .mcp.json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-server": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "my-mcp-server"],
|
||||
"env": { "API_KEY": "..." }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**What you can extend**:
|
||||
- Custom tools (via `tools/list` + `tools/call`)
|
||||
- Resources (via `resources/list` + `resources/read`)
|
||||
- Prompt templates (via `prompts/list` + `prompts/get`)
|
||||
- Auto-completion (via `completion/complete`)
|
||||
|
||||
**Transports**: stdio, SSE, HTTP, WebSocket
|
||||
|
||||
## 2. Hooks (Lifecycle Automation)
|
||||
|
||||
**Integration depth**: React to and control tool execution.
|
||||
|
||||
```json
|
||||
// .claude/settings.json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [{ "type": "command", "command": "lint-check $FILE" }]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "Bash",
|
||||
"hooks": [{ "type": "http", "url": "https://api.example.com/notify" }]
|
||||
}],
|
||||
"Stop": [{
|
||||
"matcher": "",
|
||||
"hooks": [{ "type": "command", "command": "run-tests" }]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Events**: PreToolUse, PostToolUse, PreToolUseFailure, PostToolUseFailure,
|
||||
Notification, Stop, SubagentStop
|
||||
|
||||
**Hook types**: command (shell), http (webhook)
|
||||
|
||||
**Capabilities**: Hooks can approve/deny tool execution (PreToolUse) and
|
||||
prevent agent stop (Stop).
|
||||
|
||||
## 3. Custom Agents
|
||||
|
||||
**Integration depth**: Define specialized AI personas.
|
||||
|
||||
### JSON Format
|
||||
```json
|
||||
// .claude/agents/reviewer.json
|
||||
{
|
||||
"description": "Code review specialist",
|
||||
"prompt": "You are a thorough code reviewer...",
|
||||
"model": "claude-sonnet-4-6",
|
||||
"tools": ["Read", "Glob", "Grep"],
|
||||
"hooks": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### Markdown Format
|
||||
```markdown
|
||||
// .claude/agents/reviewer.md
|
||||
---
|
||||
name: reviewer
|
||||
description: Code review specialist
|
||||
model: claude-sonnet-4-6
|
||||
tools: [Read, Glob, Grep]
|
||||
---
|
||||
|
||||
You are a thorough code reviewer...
|
||||
```
|
||||
|
||||
### CLI Definition
|
||||
```bash
|
||||
claude --agents '{"reviewer": {"description": "...", "prompt": "..."}}'
|
||||
claude --agent reviewer
|
||||
```
|
||||
|
||||
## 4. Skills (Slash Commands)
|
||||
|
||||
**Integration depth**: Reusable task workflows.
|
||||
|
||||
```markdown
|
||||
// .claude/skills/deploy/SKILL.md
|
||||
---
|
||||
name: deploy
|
||||
description: Deploy the application
|
||||
tools: [Bash, Read]
|
||||
---
|
||||
|
||||
# Deploy Skill
|
||||
|
||||
Follow these steps to deploy...
|
||||
```
|
||||
|
||||
Skills are invoked via `/skill-name` in the interactive REPL.
|
||||
|
||||
## 5. Plugins (Marketplace)
|
||||
|
||||
**Integration depth**: Distributable packages of agents, tools, and config.
|
||||
|
||||
Plugins are installed from marketplaces and can provide:
|
||||
- MCP servers (additional tools)
|
||||
- Agent definitions
|
||||
- Skill definitions
|
||||
- Configuration presets
|
||||
- Model endpoint definitions
|
||||
|
||||
Configuration:
|
||||
- `enabledPlugins` -- Active plugins
|
||||
- `pluginConfigs` -- Per-plugin settings
|
||||
- `blockedMarketplaces` -- Denylist
|
||||
- `extraKnownMarketplaces` -- Additional sources
|
||||
|
||||
## 6. CLAUDE.md System Prompt
|
||||
|
||||
**Integration depth**: Customize AI behavior per project.
|
||||
|
||||
```markdown
|
||||
// CLAUDE.md (project root)
|
||||
# Project Instructions
|
||||
|
||||
## Rules
|
||||
- Always use TypeScript
|
||||
- Follow TDD
|
||||
|
||||
## Architecture
|
||||
- Use DDD bounded contexts
|
||||
- Keep files under 500 lines
|
||||
```
|
||||
|
||||
Discovered locations (all loaded and merged):
|
||||
1. `~/.claude/CLAUDE.md` (global user)
|
||||
2. `CLAUDE.md` in project root
|
||||
3. `CLAUDE.md` in parent directories
|
||||
4. Additional via `--add-dir`
|
||||
|
||||
## 7. Settings Override Chain
|
||||
|
||||
**Integration depth**: Configure behavior at multiple scopes.
|
||||
|
||||
| Scope | File | Purpose |
|
||||
|-------|------|---------|
|
||||
| User | `~/.claude/settings.json` | Personal defaults |
|
||||
| Project | `.claude/settings.json` | Team shared config |
|
||||
| Local | `.claude/settings.local.json` | Personal project overrides |
|
||||
| Managed | Enterprise policy | Organization rules |
|
||||
|
||||
## 8. Environment Variables
|
||||
|
||||
**Integration depth**: Runtime behavior control.
|
||||
|
||||
498+ recognized environment variables provide fine-grained control
|
||||
over every subsystem. Key categories:
|
||||
- `ANTHROPIC_*` -- API and model configuration
|
||||
- `CLAUDE_CODE_*` -- Feature flags and behavior
|
||||
- `CLAUDE_CODE_DISABLE_*` -- Feature disabling
|
||||
- `CLAUDE_CODE_ENABLE_*` -- Feature enabling
|
||||
- `MCP_*` -- MCP configuration
|
||||
- `OTEL_*` -- Observability
|
||||
|
||||
## 9. API Key Helper
|
||||
|
||||
**Integration depth**: Custom authentication.
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKeyHelper": "/path/to/auth-script"
|
||||
}
|
||||
```
|
||||
|
||||
The script must output the API key to stdout. Also:
|
||||
- `awsAuthRefresh` -- AWS credential refresh script
|
||||
- `awsCredentialExport` -- AWS credential export script
|
||||
- `gcpAuthRefresh` -- GCP auth refresh command
|
||||
- `otelHeadersHelper` -- OTEL headers generation
|
||||
|
||||
## 10. Keybindings
|
||||
|
||||
**Integration depth**: Custom keyboard shortcuts.
|
||||
|
||||
```json
|
||||
// ~/.claude/keybindings.json
|
||||
{
|
||||
"bindings": [
|
||||
{ "key": "ctrl+s", "command": "submit" },
|
||||
{ "key": "ctrl+shift+p", "command": "slash-command" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 11. Agent SDK (Programmatic)
|
||||
|
||||
**Integration depth**: Embed Claude Code in applications.
|
||||
|
||||
```typescript
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
for await (const message of query({
|
||||
prompt: "Explain this code",
|
||||
options: {
|
||||
cwd: "/path/to/project",
|
||||
allowedTools: ["Read", "Glob", "Grep"],
|
||||
},
|
||||
})) {
|
||||
if ("result" in message) {
|
||||
console.log(message.result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Environment variables for SDK:
|
||||
- `CLAUDE_AGENT_SDK_CLIENT_APP`
|
||||
- `CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS`
|
||||
- `CLAUDE_AGENT_SDK_MCP_NO_PREFIX`
|
||||
- `CLAUDE_AGENT_SDK_VERSION`
|
||||
|
||||
## 12. Scheduled Tasks (Cron)
|
||||
|
||||
**Integration depth**: Automated recurring tasks.
|
||||
|
||||
```json
|
||||
// ~/.claude/scheduled_tasks.json
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"schedule": "0 9 * * 1",
|
||||
"command": "Review open PRs"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Controlled by `CLAUDE_CODE_DISABLE_CRON`.
|
||||
|
||||
## 13. Remote Control
|
||||
|
||||
**Integration depth**: External process control.
|
||||
|
||||
`claude remote-control` and `claude serve` expose an SSE/HTTP interface
|
||||
for external tools to drive Claude Code programmatically.
|
||||
|
||||
- `CLAUDE_CODE_SSE_PORT` -- SSE server port
|
||||
- `--output-format stream-json` -- Streaming JSON protocol
|
||||
- `--input-format stream-json` -- Streaming JSON input
|
||||
|
||||
## Extension Point Comparison
|
||||
|
||||
| Extension | Complexity | Capability | Distribution |
|
||||
|-----------|-----------|------------|--------------|
|
||||
| CLAUDE.md | Low | Prompt only | Git |
|
||||
| Env vars | Low | Config only | Shell |
|
||||
| Settings | Low | Config only | File |
|
||||
| Keybindings | Low | UI only | File |
|
||||
| Skills | Medium | Workflows | Git |
|
||||
| Hooks | Medium | Automation | Settings |
|
||||
| Custom agents | Medium | Personas | Git/Settings |
|
||||
| MCP servers | High | Full tools | Package |
|
||||
| Plugins | High | Everything | Marketplace |
|
||||
| Agent SDK | High | Embedding | npm |
|
||||
| Cron tasks | Medium | Scheduling | File |
|
||||
| Remote control | High | External API | Process |
|
||||
168
docs/research/claude-code-rvsource/14-source-extraction.md
Normal file
168
docs/research/claude-code-rvsource/14-source-extraction.md
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# 14 - Source Extraction and Code Metrics
|
||||
|
||||
## Binary Analysis
|
||||
|
||||
### Distribution Formats
|
||||
|
||||
Claude Code ships in two forms:
|
||||
|
||||
| Format | Path | Size | Version |
|
||||
|--------|------|------|---------|
|
||||
| Bun SEA (ELF) | `~/.local/share/claude/versions/2.1.90` | 229,902,976 bytes (219 MB) | 2.1.90 |
|
||||
| NPM bundle | `@anthropic-ai/claude-code/cli.js` | 11,044,554 bytes (10.5 MB) | 2.0.62 |
|
||||
|
||||
The Bun SEA binary is a dynamically linked ELF executable embedding the Bun runtime (v1.2+) with
|
||||
the JavaScript bundle inlined. The NPM package contains the same logical code as a single minified
|
||||
`cli.js` file plus tree-sitter WASM modules and a vendored ripgrep binary.
|
||||
|
||||
### Binary Structure (Bun SEA)
|
||||
|
||||
```
|
||||
ELF 64-bit LSB executable, x86-64
|
||||
├── Bun runtime (~219 MB)
|
||||
│ ├── V8/JavaScriptCore bindings
|
||||
│ ├── libc, libcrypto, libssl
|
||||
│ └── Node.js compatibility layer
|
||||
├── Embedded JS bundle (~11 MB equivalent)
|
||||
│ ├── Minified application code
|
||||
│ ├── Bundled npm dependencies (lodash, zod, ink, etc.)
|
||||
│ └── Tree-sitter grammars (WASM)
|
||||
└── Bun SEA metadata markers
|
||||
├── @bun @bytecode @bun-cjs
|
||||
└── {"method":"Bun.canReload"}
|
||||
```
|
||||
|
||||
### NPM Package Layout
|
||||
|
||||
```
|
||||
@anthropic-ai/claude-code/
|
||||
├── cli.js 11,044,554 bytes (single minified bundle)
|
||||
├── sdk-tools.d.ts 65,511 bytes (TypeScript type defs for tools)
|
||||
├── package.json 1,196 bytes
|
||||
├── tree-sitter-bash.wasm 1,380,769 bytes
|
||||
├── tree-sitter.wasm 205,498 bytes
|
||||
├── vendor/
|
||||
│ └── ripgrep/ (bundled rg binary)
|
||||
├── LICENSE.md
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### Version Management
|
||||
|
||||
Multiple versions coexist under `~/.local/share/claude/versions/`:
|
||||
- `2.1.86` (228,280,960 bytes) - 2025-03-27
|
||||
- `2.1.87` (228,280,960 bytes) - 2025-03-29
|
||||
- `2.1.90` (229,902,976 bytes) - 2025-04-02 (current)
|
||||
|
||||
The active version is symlinked: `~/.local/bin/claude -> ~/.local/share/claude/versions/2.1.90`
|
||||
|
||||
## Code Metrics (from cli.js v2.0.62)
|
||||
|
||||
| Metric | Count |
|
||||
|--------|-------|
|
||||
| File size | 11,044,554 bytes |
|
||||
| Lines (minified) | 4,836 |
|
||||
| Estimated functions | 19,464 |
|
||||
| Async functions | 884 |
|
||||
| Arrow functions | 23,537 |
|
||||
| Classes | 1,557 |
|
||||
| Class inheritance (extends) | 956 |
|
||||
| `for await` loops | 41 |
|
||||
| `yield*` statements | 18 |
|
||||
| Async generators | 6 (core loop functions) |
|
||||
| Node.js built-in imports | 25+ modules |
|
||||
|
||||
### Estimated Original Source Size
|
||||
|
||||
The minified bundle is ~11 MB in 4,836 lines. Given typical minification ratios (3-5x for
|
||||
well-structured TypeScript), the original source is estimated at 33-55 MB / 50,000-150,000 lines
|
||||
across hundreds of modules.
|
||||
|
||||
### Minification Characteristics
|
||||
|
||||
The code uses aggressive mangling:
|
||||
- All local variables shortened to 1-3 characters (`A`, `Q`, `B`, `G`, `Z`, `Y`)
|
||||
- Module-scoped functions use short hashes (`s$`, `ye`, `nB`, `QA`, `wG`)
|
||||
- Class names are 2-4 character hashes (`L6`, `V9`, `GI`, `RX`, `oJ`, `c90`)
|
||||
- Original names survive only in string literals and public API surfaces
|
||||
|
||||
### Key Identifiable Functions (from code patterns)
|
||||
|
||||
| Minified Name | Likely Original | Evidence |
|
||||
|--------------|-----------------|----------|
|
||||
| `s$` | `agentLoop` / `queryLoop` | Core async generator; receives messages, systemPrompt, canUseTool, toolUseContext |
|
||||
| `ye` | `resolveModel` | Takes permissionMode, mainLoopModel, exceeds200kTokens |
|
||||
| `Ll` | `createInitialAppState` | Returns full AppState object with all fields |
|
||||
| `QA` | `trackEvent` / `telemetry` | Called everywhere with event name + payload |
|
||||
| `nB` | `updateSettings` | Writes to settings store |
|
||||
| `wG` | `logDebug` | Debug logging with event names like "query_query_start" |
|
||||
| `Y7` | `getMainLoopModel` | Returns current model |
|
||||
| `Y0` | `getCwd` | Returns current working directory |
|
||||
| `GB` | `getProjectDir` | Returns project directory |
|
||||
| `Bd` | `getContextWindow` | Takes model, returns context window size |
|
||||
| `xC` | `getToolPermissionContext` | Returns permission context object |
|
||||
| `Sn` | `extractTextContent` | Extracts text from API response |
|
||||
| `B0` | `getAgentId` | Returns current agent ID |
|
||||
|
||||
## Extraction Methods
|
||||
|
||||
### Method 1: NPM Package (recommended)
|
||||
|
||||
The `cli.js` from the NPM package is directly analyzable JavaScript:
|
||||
|
||||
```bash
|
||||
CLI="$(npm root -g)/claude-flow/node_modules/@anthropic-ai/claude-code/cli.js"
|
||||
# or install directly:
|
||||
npm pack @anthropic-ai/claude-code && tar xzf anthropic-ai-claude-code-*.tgz
|
||||
```
|
||||
|
||||
### Method 2: Binary Strings
|
||||
|
||||
```bash
|
||||
strings ~/.local/share/claude/versions/2.1.90 | grep -c 'function\|class '
|
||||
# Returns ~9,887 readable JS fragments
|
||||
```
|
||||
|
||||
The binary contains the same JS but embedded within the Bun SEA container. The NPM
|
||||
package provides cleaner access to the same code.
|
||||
|
||||
### Method 3: Bun SEA Extraction
|
||||
|
||||
The Bun SEA format embeds a bytecode blob. To extract:
|
||||
```bash
|
||||
# Find the JS entry section
|
||||
strings -t d binary | grep '#!/usr/bin/env' | head -1
|
||||
# Use offset to extract the embedded module
|
||||
```
|
||||
|
||||
## Source Files Referenced
|
||||
|
||||
- Extracted module analysis: `extracted/agent-loop.rvf`
|
||||
- Tool dispatch patterns: `extracted/tool-dispatch.rvf`
|
||||
- Permission system: `extracted/permission-system.rvf`
|
||||
- MCP client: `extracted/mcp-client.rvf`
|
||||
- Context manager: `extracted/context-manager.rvf`
|
||||
- Streaming handler: `extracted/streaming-handler.rvf`
|
||||
|
||||
## Dependencies (Node.js Built-in Imports)
|
||||
|
||||
```
|
||||
assert, async_hooks, child_process, crypto, events, fs, fs/promises,
|
||||
http, https, module, net, os, path, process, stream, tty, url, util, zlib
|
||||
node:buffer, node:child_process, node:crypto, node:fs, node:fs/promises,
|
||||
node:http, node:https, node:module, node:net, node:os, node:path,
|
||||
node:process, node:stream, node:timers/promises, node:tty, node:url,
|
||||
node:util, node:zlib
|
||||
```
|
||||
|
||||
## Bundled Third-Party Libraries (identified from code patterns)
|
||||
|
||||
- Zod (schema validation - `S.string()`, `S.enum()`, `S.record()`)
|
||||
- Ink / React (terminal UI - `createElement`, `useCallback`, `useEffect`, `useRef`)
|
||||
- Sentry (error tracking - `globalEventProcessors`, `_dispatching`)
|
||||
- GrowthBook (feature flags - `stickyBucketService`, `getExperiment`)
|
||||
- Statsig (experimentation - `_getFeatureGateImpl`)
|
||||
- Sharp (image processing - `@img/sharp-*` optional deps)
|
||||
- node-forge (crypto - `aes.startEncrypting`, `aes.createDecryptionCipher`)
|
||||
- tree-sitter (AST parsing - WASM modules)
|
||||
- ripgrep (file search - vendored binary)
|
||||
341
docs/research/claude-code-rvsource/15-core-module-analysis.md
Normal file
341
docs/research/claude-code-rvsource/15-core-module-analysis.md
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
# 15 - Core Module Analysis
|
||||
|
||||
Deep analysis of each core module's actual implementation, traced from the minified source.
|
||||
|
||||
## 1. Agent Loop (`s$` - async generator)
|
||||
|
||||
The agent loop is the central execution engine. It is an **async generator function** named `s$`
|
||||
in the minified code, yielding events as it processes messages.
|
||||
|
||||
### Signature (reconstructed)
|
||||
|
||||
```typescript
|
||||
async function* agentLoop({
|
||||
messages: Message[],
|
||||
systemPrompt: string,
|
||||
userContext: Record<string, unknown>,
|
||||
systemContext: Record<string, unknown>,
|
||||
canUseTool: PermissionChecker,
|
||||
toolUseContext: ToolUseContext,
|
||||
autoCompactTracking?: CompactTracker,
|
||||
fallbackModel?: string,
|
||||
stopHookActive?: boolean,
|
||||
querySource: QuerySource
|
||||
}): AsyncGenerator<AgentEvent>
|
||||
```
|
||||
|
||||
### Yield Event Types
|
||||
|
||||
The loop yields these event types (traced from `yield{type:"..."}` patterns):
|
||||
|
||||
| Event Type | Count in Code | Purpose |
|
||||
|------------|---------------|---------|
|
||||
| `stream_request_start` | 1 | Signals API request beginning |
|
||||
| `stream_event` | 2 | SSE events from Anthropic API |
|
||||
| `assistant` | 2 | Complete assistant message |
|
||||
| `user` | 5 | Synthetic user messages (tool results) |
|
||||
| `system` | 5 | System events (compact boundary, etc.) |
|
||||
| `result` | 6 | Tool execution results |
|
||||
| `progress` | 1 | Progress updates |
|
||||
| `stop` | 3 | Stop signals |
|
||||
| `stopReason` | 1 | Why the loop stopped |
|
||||
| `hookPermissionResult` | 3 | Hook permission decisions |
|
||||
| `preventContinuation` | 1 | Blocks further turns |
|
||||
| `tool_progress` | 1 | Tool execution progress |
|
||||
| `message` | 3 | General message events |
|
||||
|
||||
### Core Loop Flow (reconstructed from call sites)
|
||||
|
||||
```
|
||||
s$() entry
|
||||
├── yield {type: "stream_request_start"}
|
||||
├── Build API request (system prompt, messages, tools, betas)
|
||||
├── Call Anthropic Messages API (streaming)
|
||||
│ ├── for each SSE event:
|
||||
│ │ ├── yield {type: "stream_event", event}
|
||||
│ │ ├── Accumulate content blocks (text, tool_use, thinking)
|
||||
│ │ └── Track token usage
|
||||
│ └── yield {type: "assistant", message}
|
||||
├── If response contains tool_use blocks:
|
||||
│ ├── For each tool_use:
|
||||
│ │ ├── Check permission via canUseTool()
|
||||
│ │ ├── If denied: yield {type: "hookPermissionResult"}
|
||||
│ │ ├── Execute tool.call()
|
||||
│ │ └── yield {type: "result"}
|
||||
│ ├── Assemble tool_result messages
|
||||
│ ├── yield {type: "user", tool_results}
|
||||
│ └── Recursive: yield* s$({messages: [...messages, ...newMessages], ...})
|
||||
├── If stop_reason == "end_turn":
|
||||
│ └── yield {type: "stop"}
|
||||
├── If auto-compact triggered:
|
||||
│ └── Run compaction, yield {type: "system", subtype: "compact_boundary"}
|
||||
└── Run stop hooks if active
|
||||
```
|
||||
|
||||
### Recursive Self-Call Pattern
|
||||
|
||||
The loop is **self-recursive via `yield*`**. After processing tool results, it calls itself
|
||||
with the updated message history. This creates a chain of generator delegations that unwinds
|
||||
as the conversation progresses. The recursion terminates when:
|
||||
- The model returns `end_turn` stop reason
|
||||
- `max_tokens` is reached
|
||||
- The abort controller signals
|
||||
- A stop hook intervenes
|
||||
- Budget limit is exceeded
|
||||
|
||||
## 2. Tool Dispatch System
|
||||
|
||||
### Tool Interface (reconstructed)
|
||||
|
||||
```typescript
|
||||
interface Tool {
|
||||
name: string;
|
||||
userFacingName(): string;
|
||||
isEnabled(): boolean;
|
||||
inputSchema: ZodSchema;
|
||||
outputSchema?: ZodSchema;
|
||||
validateInput(input: unknown, context: ToolContext): Promise<ValidationResult>;
|
||||
call(input: unknown, context: ToolContext, canUseTool, message): Promise<ToolResult>;
|
||||
prompt?(context: PromptContext): Promise<string>;
|
||||
getPath?(input: unknown): string; // For file-based tools
|
||||
renderToolUseMessage?(input, context): ReactElement;
|
||||
renderToolResultMessage?(result, context): ReactElement;
|
||||
renderToolUseErrorMessage?(error, context): ReactElement;
|
||||
mapToolResultToToolResultBlockParam(result, toolUseId): ToolResultBlock;
|
||||
}
|
||||
```
|
||||
|
||||
### Built-in Tools (traced from string literals)
|
||||
|
||||
| Tool Name | Minified Class | Key Behaviors |
|
||||
|-----------|---------------|---------------|
|
||||
| `BashTool` | Named in string | Executes shell commands; sandboxed via seatbelt (macOS) or SOCKS bridge (Linux) |
|
||||
| `FileReadTool` | `I6` (inferred) | Reads files with offset/limit; validates path permissions |
|
||||
| `FileWriteTool` | Named in string | Writes files; validates path permissions for write |
|
||||
| `FileEditTool` | Named in string | String replacement in files; validates edit permissions |
|
||||
| `Glob` | Referenced | Pattern-based file search |
|
||||
| `Grep` | Referenced | Content search via vendored ripgrep |
|
||||
| `WebFetch` | Referenced | HTTP fetch with domain permissions |
|
||||
| `WebSearch` | Referenced | Web search (no wildcard support) |
|
||||
| `Agent` / subagent | Referenced | Spawns child agent with own loop |
|
||||
| `AgentOutputTool` | Named in string | Reads background agent output |
|
||||
| `TodoWrite` | Referenced | Manages todo list state |
|
||||
| `NotebookEdit` | Referenced | Jupyter notebook cell editing |
|
||||
| `MCP tools` | Dynamic | Tools from MCP servers, prefixed `mcp__serverName__toolName` |
|
||||
| `KillShell` | Referenced | Kills background shell process |
|
||||
| `ListMcpResources` | Named in string | Lists MCP server resources |
|
||||
| `ReadMcpResource` | Named in string | Reads specific MCP resource |
|
||||
| `ExitPlanMode` | Referenced | Exits plan mode, optionally launches swarm |
|
||||
| `AskUserQuestion` | Referenced | Prompts user for input |
|
||||
|
||||
### Tool Dispatch Flow
|
||||
|
||||
```
|
||||
Model returns tool_use content block
|
||||
├── Find tool by name in tools array
|
||||
│ ├── Built-in tools: direct lookup
|
||||
│ └── MCP tools: parse "mcp__server__tool" prefix → route to MCP client
|
||||
├── Check tool.isEnabled()
|
||||
├── Run tool.validateInput(input, context)
|
||||
│ ├── Path validation (file tools): check against permission rules
|
||||
│ ├── URL validation (WebFetch): domain whitelist check
|
||||
│ └── Schema validation via Zod
|
||||
├── Permission check via canUseTool(toolName, input)
|
||||
│ ├── Check always-allow rules
|
||||
│ ├── Check deny rules
|
||||
│ ├── If mode == "bypassPermissions": allow
|
||||
│ ├── If mode == "dontAsk": allow
|
||||
│ ├── If mode == "plan": deny tool execution
|
||||
│ └── If mode == "default": prompt user
|
||||
├── Execute tool.call(input, context, canUseTool, message)
|
||||
└── Map result via mapToolResultToToolResultBlockParam()
|
||||
```
|
||||
|
||||
## 3. Permission Checker
|
||||
|
||||
### Permission Modes (from `ET` enum)
|
||||
|
||||
```typescript
|
||||
type PermissionMode = "acceptEdits" | "bypassPermissions" | "default" | "dontAsk" | "plan";
|
||||
```
|
||||
|
||||
### Permission Context (from `Ll()` / `xC()`)
|
||||
|
||||
```typescript
|
||||
interface ToolPermissionContext {
|
||||
mode: PermissionMode;
|
||||
alwaysAllowRules: {
|
||||
command: string[]; // e.g., ["Bash(npm run:*)"]
|
||||
};
|
||||
// deny rules for file paths, domains, etc.
|
||||
}
|
||||
```
|
||||
|
||||
### Permission Rule Format (from string literals)
|
||||
|
||||
```
|
||||
"Bash" → allows all bash commands
|
||||
"Bash(npm run:*)" → allows any npm run command
|
||||
"Bash(npm install express)" → allows exact command
|
||||
"Bash(git:*)" → allows all git commands
|
||||
"Bash(git:*) Edit" → allows git + file editing
|
||||
"WebFetch(domain:example.com)" → allows fetch to specific domain
|
||||
"WebFetch(domain:*.google.com)" → allows fetch to google subdomains
|
||||
```
|
||||
|
||||
### Sandbox Implementation
|
||||
|
||||
Two sandbox backends exist:
|
||||
|
||||
1. **macOS**: Uses `sandbox-exec -p` (seatbelt) with a generated profile
|
||||
2. **Linux**: Uses a SOCKS bridge process for network isolation
|
||||
|
||||
Key sandbox config fields:
|
||||
```typescript
|
||||
sandbox: {
|
||||
enabled: boolean;
|
||||
autoAllowBashIfSandboxed: boolean;
|
||||
allowUnsandboxedCommands: boolean;
|
||||
excludedCommands: string[];
|
||||
ignoreViolations: boolean;
|
||||
enableWeakerNestedSandbox: boolean; // For Docker
|
||||
ripgrep?: RipgrepConfig;
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Context Window Management
|
||||
|
||||
### Compaction System (reconstructed from "tengu_compact" telemetry)
|
||||
|
||||
The compaction system manages context window overflow through summarization.
|
||||
|
||||
```typescript
|
||||
// Auto-compact triggers when input tokens exceed threshold
|
||||
// Threshold is derived from API_TARGET_INPUT_TOKENS env var
|
||||
// Default: uses clear_tool_uses_20250919 API feature
|
||||
|
||||
interface CompactionConfig {
|
||||
type: "clear_tool_uses_20250919";
|
||||
trigger: { type: "input_tokens"; value: number };
|
||||
clear_at_least: { type: "input_tokens"; value: number };
|
||||
}
|
||||
```
|
||||
|
||||
### Compaction Flow
|
||||
|
||||
```
|
||||
Token count exceeds threshold
|
||||
├── Set spinner: "Running SessionStart hooks..."
|
||||
├── Call API with querySource: "compact"
|
||||
│ ├── Request summary of conversation
|
||||
│ └── Track: tengu_compact telemetry
|
||||
├── Validate summary (not empty, not error, not too_long)
|
||||
├── Replace message history with:
|
||||
│ ├── Summary message
|
||||
│ ├── Compact boundary marker
|
||||
│ ├── File reference attachments (re-read key files)
|
||||
│ └── Hook results
|
||||
├── Micro-compaction: clear individual tool uses that are stale
|
||||
├── Track: preCompactTokenCount, postCompactTokenCount
|
||||
└── Continue agent loop with reduced context
|
||||
```
|
||||
|
||||
### File Reference Restoration
|
||||
|
||||
After compaction, files referenced in the conversation are re-read to maintain context:
|
||||
```
|
||||
Post-compact file restore:
|
||||
├── For each tracked file:
|
||||
│ ├── Read with fileReadingLimits.maxTokens = iE5
|
||||
│ ├── Track: tengu_post_compact_file_restore_success/error
|
||||
│ └── Add as attachment
|
||||
└── Clear stale entries from readFileState cache
|
||||
```
|
||||
|
||||
## 5. MCP Client
|
||||
|
||||
### Connection Lifecycle
|
||||
|
||||
```typescript
|
||||
// MCP server config sources:
|
||||
// 1. .mcp.json in project directory
|
||||
// 2. Settings (localSettings, policySettings)
|
||||
// 3. Dynamic config at runtime
|
||||
|
||||
// Connection types:
|
||||
// - stdio: spawn child process
|
||||
// - SSE: HTTP server-sent events
|
||||
// - WebSocket: ws:// connection
|
||||
// - MCPB: bundled MCP packages (downloaded + extracted)
|
||||
```
|
||||
|
||||
### MCP Tool Integration
|
||||
|
||||
MCP tools are namespaced as `mcp__<serverName>__<toolName>`:
|
||||
|
||||
```typescript
|
||||
function parseMcpToolName(fullName: string): { serverName: string; toolName: string } {
|
||||
// "mcp__claude-flow__memory_store" → { serverName: "claude-flow", toolName: "memory_store" }
|
||||
}
|
||||
```
|
||||
|
||||
### MCP Protocol Messages (traced from code)
|
||||
|
||||
```
|
||||
initialize → capabilities exchange
|
||||
listTools → discover available tools
|
||||
callTool → execute a tool with JSON input
|
||||
notifications/ → server-sent notifications
|
||||
resources/list → list available resources
|
||||
resources/read → read a specific resource
|
||||
```
|
||||
|
||||
### MCPB (MCP Bundles)
|
||||
|
||||
MCPB files are packaged MCP servers that can be downloaded and extracted:
|
||||
```
|
||||
Download MCPB → extract to ~/.claude/ → load config → start server
|
||||
```
|
||||
|
||||
## 6. Streaming Handler
|
||||
|
||||
### SSE Event Processing (from content_block_delta handler)
|
||||
|
||||
```typescript
|
||||
// Event types processed:
|
||||
switch (event.type) {
|
||||
case "message_start": // Initialize response accumulator
|
||||
case "content_block_start": // New content block (text, tool_use, thinking)
|
||||
case "content_block_delta": // Incremental update
|
||||
switch (delta.type) {
|
||||
case "text_delta": // Text chunk → append to current block
|
||||
case "input_json_delta": // Tool input JSON chunk → accumulate
|
||||
case "thinking_delta": // Extended thinking chunk
|
||||
}
|
||||
case "content_block_stop": // Block complete
|
||||
case "message_delta": // Usage update (stop_reason, tokens)
|
||||
case "message_stop": // Response complete
|
||||
}
|
||||
```
|
||||
|
||||
### Stream Mode States
|
||||
|
||||
The UI tracks stream mode for rendering:
|
||||
```
|
||||
"requesting" → Waiting for first token
|
||||
"responding" → Receiving text content
|
||||
"tool-input" → Receiving tool use JSON
|
||||
```
|
||||
|
||||
### Token Tracking (from usage accumulator)
|
||||
|
||||
```typescript
|
||||
// Per-response tracking:
|
||||
usage: {
|
||||
input_tokens: number;
|
||||
output_tokens: number;
|
||||
cache_read_input_tokens: number;
|
||||
cache_creation_input_tokens: number;
|
||||
server_tool_use?: { web_search_requests: number };
|
||||
}
|
||||
```
|
||||
267
docs/research/claude-code-rvsource/16-call-graphs.md
Normal file
267
docs/research/claude-code-rvsource/16-call-graphs.md
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
# 16 - Call Graphs
|
||||
|
||||
Call graphs traced from actual minified source patterns in `cli.js` (v2.0.62).
|
||||
Function names shown as `minified` -> `reconstructedName`.
|
||||
|
||||
## 1. Main Boot Sequence
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["cli.js entry (#!/usr/bin/env node)"] --> B["Parse CLI arguments (process.argv)"]
|
||||
B --> C{"Mode?"}
|
||||
C -->|"Interactive REPL"| D["Initialize Ink React app"]
|
||||
C -->|"--print / -p"| E["SDK non-interactive mode"]
|
||||
C -->|"MCP server"| F["Start MCP stdio/SSE server"]
|
||||
C -->|"Sub-command"| G["Route to command handler"]
|
||||
|
||||
D --> H["Ll() - createInitialAppState"]
|
||||
H --> I["gG() - AppStateProvider"]
|
||||
I --> J["Load settings: qq()"]
|
||||
J --> K["Load permissions: xC()"]
|
||||
K --> L["Initialize MCP clients"]
|
||||
L --> M["Load plugins"]
|
||||
M --> N["LoA() - resolveThinkingEnabled"]
|
||||
N --> O["Render main React component"]
|
||||
O --> P["Wait for user input"]
|
||||
|
||||
E --> Q["Build SDK context"]
|
||||
Q --> R["JP() - prepareQuery"]
|
||||
R --> S["s$() - agentLoop"]
|
||||
S --> T["Yield results to SDK caller"]
|
||||
```
|
||||
|
||||
## 2. Agent Loop (s$ function)
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["s$() entry"] --> B["yield stream_request_start"]
|
||||
B --> C["Build API params"]
|
||||
C --> D["qh2() - countTokens"]
|
||||
D --> E{"Exceeds compact threshold?"}
|
||||
E -->|Yes| F["Run compaction"]
|
||||
F --> G["yield system:compact_boundary"]
|
||||
G --> C
|
||||
E -->|No| H["d39() - telemetry: tengu_api_query"]
|
||||
H --> I["Call Anthropic Messages API (streaming)"]
|
||||
|
||||
I --> J["Process SSE stream"]
|
||||
J --> K{"Event type?"}
|
||||
K -->|"content_block_delta"| L["Accumulate text/tool_use/thinking"]
|
||||
K -->|"message_stop"| M["yield assistant message"]
|
||||
|
||||
M --> N{"Has tool_use blocks?"}
|
||||
N -->|No| O["yield stop"]
|
||||
N -->|Yes| P["Process each tool_use"]
|
||||
|
||||
P --> Q["Permission check: canUseTool()"]
|
||||
Q --> R{"Allowed?"}
|
||||
R -->|Denied| S["yield hookPermissionResult"]
|
||||
R -->|Ask user| T["Prompt for approval"]
|
||||
R -->|Allowed| U["tool.validateInput()"]
|
||||
|
||||
U --> V{"Valid?"}
|
||||
V -->|No| W["Return error result"]
|
||||
V -->|Yes| X["tool.call()"]
|
||||
X --> Y["yield result"]
|
||||
|
||||
Y --> Z["Assemble tool_result messages"]
|
||||
Z --> AA["yield user (tool results)"]
|
||||
AA --> AB["yield* s$() RECURSIVE CALL"]
|
||||
AB --> AC["Continue processing"]
|
||||
```
|
||||
|
||||
## 3. Tool Dispatch Flow
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Tool use from API response"] --> B{"Tool name prefix?"}
|
||||
B -->|"mcp__*"| C["Parse: mcp__server__tool"]
|
||||
B -->|Built-in| D["Lookup in tools array"]
|
||||
|
||||
C --> E["Find MCP client by server name"]
|
||||
E --> F["MCP callTool(name, args)"]
|
||||
F --> G["Return MCP result"]
|
||||
|
||||
D --> H{"Tool type?"}
|
||||
H -->|"BashTool"| I["BashTool.call()"]
|
||||
H -->|"FileReadTool"| J["FileReadTool.call()"]
|
||||
H -->|"FileEditTool"| K["FileEditTool.call()"]
|
||||
H -->|"FileWriteTool"| L["FileWriteTool.call()"]
|
||||
H -->|"Agent"| M["Spawn sub-agent"]
|
||||
H -->|Other| N["Generic tool.call()"]
|
||||
|
||||
I --> I1["Check sandbox config"]
|
||||
I1 --> I2{"Sandbox enabled?"}
|
||||
I2 -->|macOS| I3["sandbox-exec -p profile cmd"]
|
||||
I2 -->|Linux| I4["SOCKS bridge execution"]
|
||||
I2 -->|Disabled| I5["Direct child_process.exec"]
|
||||
|
||||
J --> J1["Validate path permissions"]
|
||||
J1 --> J2["fs.readFile with offset/limit"]
|
||||
J2 --> J3["Return content with line numbers"]
|
||||
|
||||
M --> M1["Create agent context"]
|
||||
M1 --> M2["Fork messages if needed: bV0()"]
|
||||
M2 --> M3["Resolve agent model: JsA()"]
|
||||
M3 --> M4["yield* mVA() - agent generator"]
|
||||
M4 --> M5["Runs own s$() loop"]
|
||||
```
|
||||
|
||||
## 4. Permission Check Flow
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["canUseTool(toolName, input)"] --> B["Get permission context"]
|
||||
B --> C{"Permission mode?"}
|
||||
|
||||
C -->|"bypassPermissions"| D["ALLOW immediately"]
|
||||
C -->|"dontAsk"| E["ALLOW (agent mode)"]
|
||||
C -->|"plan"| F["DENY (read-only)"]
|
||||
C -->|"default"| G["Check rules"]
|
||||
C -->|"acceptEdits"| H["Allow edits, ask for others"]
|
||||
|
||||
G --> I{"Match always-allow rules?"}
|
||||
I -->|Yes| J["ALLOW"]
|
||||
I -->|No| K{"Match deny rules?"}
|
||||
K -->|Yes| L["DENY"]
|
||||
K -->|No| M{"Is file operation?"}
|
||||
|
||||
M -->|Yes| N["tD() - check path permission"]
|
||||
N --> O{"Path allowed?"}
|
||||
O -->|"allow"| P["ALLOW"]
|
||||
O -->|"deny"| Q["DENY"]
|
||||
O -->|"ask"| R["Prompt user"]
|
||||
|
||||
M -->|No| R
|
||||
R --> S{"User response?"}
|
||||
S -->|Allow once| T["ALLOW"]
|
||||
S -->|Allow always| U["Add to always-allow rules"]
|
||||
S -->|Deny| V["DENY"]
|
||||
```
|
||||
|
||||
## 5. MCP Server Lifecycle
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Load MCP config"] --> B{"Config source?"}
|
||||
B -->|".mcp.json"| C["Read project .mcp.json"]
|
||||
B -->|"Settings"| D["Read from localSettings"]
|
||||
B -->|"MCPB"| E["Download + extract MCPB bundle"]
|
||||
|
||||
C --> F["Normalize server names: UG()"]
|
||||
D --> F
|
||||
E --> F
|
||||
|
||||
F --> G{"Transport type?"}
|
||||
G -->|"stdio"| H["Spawn child process"]
|
||||
G -->|"sse"| I["HTTP SSE connection"]
|
||||
G -->|"websocket"| J["WebSocket connection"]
|
||||
|
||||
H --> K["Send: initialize"]
|
||||
I --> K
|
||||
J --> K
|
||||
|
||||
K --> L["Receive: capabilities"]
|
||||
L --> M["Send: tools/list"]
|
||||
M --> N["Register tools as mcp__server__tool"]
|
||||
|
||||
N --> O["Tool invocation"]
|
||||
O --> P["Send: tools/call"]
|
||||
P --> Q["Receive: tool result"]
|
||||
Q --> R["Return to agent loop"]
|
||||
|
||||
K --> S["Send: resources/list"]
|
||||
S --> T["Register resources"]
|
||||
|
||||
R --> U{"Server error?"}
|
||||
U -->|"Connection lost"| V["Restart MCP server process"]
|
||||
U -->|"Timeout"| W["k91() - get MCP_TIMEOUT"]
|
||||
```
|
||||
|
||||
## 6. Compaction Flow
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Token count check"] --> B{"input_tokens > threshold?"}
|
||||
B -->|No| C["Continue normally"]
|
||||
B -->|Yes| D["Start compaction"]
|
||||
|
||||
D --> E["Set spinner: compacting"]
|
||||
E --> F["Call API: querySource='compact'"]
|
||||
F --> G["Stream summary response"]
|
||||
G --> H{"Summary valid?"}
|
||||
|
||||
H -->|"Empty"| I["tengu_compact_failed: no_summary"]
|
||||
H -->|"API error prefix"| J["tengu_compact_failed: api_error"]
|
||||
H -->|"Prompt too long"| K["tengu_compact_failed: prompt_too_long"]
|
||||
H -->|"Valid"| L["Build new message history"]
|
||||
|
||||
L --> M["c12() - refresh readFileState"]
|
||||
M --> N["Re-read tracked files"]
|
||||
N --> O["z$('compact') - run SessionStart hooks"]
|
||||
O --> P["Assemble: summary + boundary + attachments + hooks"]
|
||||
P --> Q["Track: tengu_compact telemetry"]
|
||||
Q --> R["Return compacted messages"]
|
||||
|
||||
R --> S["Micro-compaction check"]
|
||||
S --> T{"Stale tool uses?"}
|
||||
T -->|Yes| U["Remove old tool_use blocks"]
|
||||
T -->|No| V["Done"]
|
||||
U --> V
|
||||
```
|
||||
|
||||
## 7. Sub-Agent Spawn Flow
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Agent tool invoked"] --> B["mVA() - agent generator"]
|
||||
B --> C["Resolve model: JsA()"]
|
||||
C --> D["Create agent ID: vQA()"]
|
||||
D --> E["Fork context: bV0()"]
|
||||
E --> F["Build agent system prompt"]
|
||||
F --> G["Create tool use context: x_A()"]
|
||||
|
||||
G --> H{"Agent permission mode?"}
|
||||
H -->|"Defined on agent"| I["Use agent's permissionMode"]
|
||||
H -->|"Async agent"| J["Override permission context"]
|
||||
H -->|"Inherit"| K["Use parent's context"]
|
||||
|
||||
I --> L["s$() - run agent's own loop"]
|
||||
J --> L
|
||||
K --> L
|
||||
|
||||
L --> M["Yield events back to parent"]
|
||||
M --> N{"Event type?"}
|
||||
N -->|"assistant"| O["Collect response"]
|
||||
N -->|"progress"| P["Forward to parent"]
|
||||
N -->|"user"| Q["Internal to agent"]
|
||||
```
|
||||
|
||||
## 8. Slash Command Dispatch
|
||||
|
||||
```
|
||||
User types /<command>
|
||||
├── Parse command name and args
|
||||
├── Look up in commands array
|
||||
│ ├── /clear → Clear conversation history
|
||||
│ ├── /compact → Trigger manual compaction
|
||||
│ ├── /config → Open config panel (React component)
|
||||
│ ├── /context → Show context usage grid
|
||||
│ ├── /cost → Show session cost/duration
|
||||
│ ├── /doctor → Run diagnostics
|
||||
│ ├── /help → Show help
|
||||
│ ├── /memory → Edit CLAUDE.md files
|
||||
│ ├── /mcp → Manage MCP servers
|
||||
│ ├── /model → Switch model (YI1 component)
|
||||
│ ├── /plan → View/open session plan
|
||||
│ ├── /resume → Resume conversation
|
||||
│ ├── /review → Review pull request
|
||||
│ ├── /status → Show version, model, account info
|
||||
│ ├── /vim → Toggle vim mode
|
||||
│ └── 30+ more commands
|
||||
├── Execute command handler
|
||||
│ ├── Some return React components (config, context)
|
||||
│ ├── Some modify app state (model, vim)
|
||||
│ └── Some yield messages (compact, review)
|
||||
└── Return: {newMessages, contextModifier, allowedTools, model}
|
||||
```
|
||||
296
docs/research/claude-code-rvsource/17-class-hierarchy.md
Normal file
296
docs/research/claude-code-rvsource/17-class-hierarchy.md
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
# 17 - Class Hierarchy
|
||||
|
||||
Class definitions, inheritance trees, and type system extracted from `cli.js` (v2.0.62).
|
||||
|
||||
## Class Statistics
|
||||
|
||||
| Metric | Count |
|
||||
|--------|-------|
|
||||
| Total classes | 1,557 |
|
||||
| Classes with inheritance | 956 |
|
||||
| Distinct base classes | ~30 |
|
||||
| Error subclasses | ~60 |
|
||||
|
||||
## Major Base Class Hierarchies
|
||||
|
||||
### 1. Error Hierarchy (`extends Error`)
|
||||
|
||||
60+ custom error classes. Key identified errors:
|
||||
|
||||
```
|
||||
Error
|
||||
├── Az (generic app error)
|
||||
├── BTA (unknown)
|
||||
├── D21 (unknown)
|
||||
├── E70 (unknown)
|
||||
├── E8 (base for BJA - tool errors)
|
||||
├── EE0 (unknown)
|
||||
├── GI (API/network error base - see below)
|
||||
├── Ha (unknown)
|
||||
├── JA0 (unknown)
|
||||
├── KU (unknown)
|
||||
├── LyA (unknown)
|
||||
├── Mh (unknown)
|
||||
├── NE (unknown)
|
||||
├── NNA (unknown)
|
||||
├── Oh (unknown)
|
||||
├── OY0 (unknown)
|
||||
├── PH0 (unknown)
|
||||
├── RY0 (unknown)
|
||||
├── TYA (unknown)
|
||||
├── U81 (unknown)
|
||||
├── V4 (unknown)
|
||||
├── VU (unknown)
|
||||
├── VX1 (unknown)
|
||||
├── Va1 (unknown)
|
||||
├── WF2 (unknown)
|
||||
├── YH1 (unknown)
|
||||
├── YV (unknown)
|
||||
├── bS (unknown)
|
||||
├── dI2 (unknown)
|
||||
├── do1 (unknown)
|
||||
├── el (unknown)
|
||||
├── fWA (unknown)
|
||||
├── gY (unknown)
|
||||
├── j22 (unknown)
|
||||
├── lU (unknown)
|
||||
├── mB1 (unknown)
|
||||
├── mn1 (unknown)
|
||||
├── oB (unknown)
|
||||
├── pYA (unknown)
|
||||
├── q71 (unknown)
|
||||
├── qAB (unknown)
|
||||
├── qi1 (unknown)
|
||||
├── uDA (unknown)
|
||||
├── uY (unknown)
|
||||
├── vaA (unknown)
|
||||
├── vS (unknown)
|
||||
├── yl2 (unknown)
|
||||
└── zQ1 (unknown)
|
||||
```
|
||||
|
||||
### 2. GI Hierarchy (API Error Classes)
|
||||
|
||||
`GI extends Error` serves as the base for API and network related errors:
|
||||
|
||||
```
|
||||
GI (extends Error) - "API Error Base"
|
||||
├── CAB
|
||||
├── DAB
|
||||
├── EAB
|
||||
├── Fx1
|
||||
├── HAB
|
||||
├── IAB
|
||||
├── JAB
|
||||
├── KAB
|
||||
├── LAB
|
||||
├── MAB
|
||||
├── NAB
|
||||
├── OAB
|
||||
├── UAB
|
||||
├── VAB
|
||||
├── WAB
|
||||
├── XAB
|
||||
├── YAB
|
||||
├── wAB
|
||||
└── zAB
|
||||
```
|
||||
|
||||
Evidence: `GI` is used in contexts involving HTTP status codes, retry logic, and API responses.
|
||||
The string `"ModelErrorException"` (`yhB` class) extends `uU` and is associated with stop reasons.
|
||||
|
||||
### 3. L6 Hierarchy (Tool/Component Classes)
|
||||
|
||||
`L6` is likely the base tool class or a React component base:
|
||||
|
||||
```
|
||||
L6 - "Tool/Component Base"
|
||||
├── A8A ├── IT ├── W8A
|
||||
├── AHA ├── J8A ├── X8A
|
||||
├── B8A ├── KT ├── XT
|
||||
├── BbA ├── Q8A ├── Y8A
|
||||
├── Bo ├── QbA ├── Yo
|
||||
├── EX ├── Zb ├── Z8A
|
||||
├── G8A ├── Zo ├── cd
|
||||
├── Go ├── dd ├── e4A
|
||||
├── I8A ├── eDA ├── md
|
||||
│ ├── mS ├── oDA
|
||||
│ ├── qw ├── rDA
|
||||
│ ├── sDA ├── t4A
|
||||
│ ├── tDA ├── uS
|
||||
│ └── ud
|
||||
```
|
||||
|
||||
~35 subclasses. Given 19 built-in tools plus slash commands plus internal components,
|
||||
this maps closely to the tool registry.
|
||||
|
||||
### 4. V9 Hierarchy (UI Component Base)
|
||||
|
||||
```
|
||||
V9 - "UI Component"
|
||||
├── CX
|
||||
├── DHA
|
||||
├── FHA
|
||||
├── IHA
|
||||
├── Io
|
||||
├── KHA
|
||||
├── VHA
|
||||
├── WHA
|
||||
├── Wo
|
||||
└── wC
|
||||
```
|
||||
|
||||
10 subclasses, likely representing distinct UI panels or widgets in the Ink terminal UI.
|
||||
|
||||
### 5. RX Hierarchy (Command/Handler Base)
|
||||
|
||||
```
|
||||
RX - "Command Handler"
|
||||
├── CE
|
||||
├── CqA
|
||||
├── EqA
|
||||
├── Mq
|
||||
├── XAA
|
||||
├── dZA
|
||||
├── jl
|
||||
├── jqA
|
||||
├── qqA
|
||||
├── uZA
|
||||
└── wqA
|
||||
```
|
||||
|
||||
11 subclasses. Matches roughly with the number of major command categories (slash commands
|
||||
that render React components like /config, /context, /cost, etc.).
|
||||
|
||||
### 6. oJ Hierarchy (Middleware/Processor Chain)
|
||||
|
||||
```
|
||||
oJ - "Processor/Middleware"
|
||||
├── C_2 ├── I_2 ├── O_2 ├── U_2
|
||||
├── D_2 ├── J_2 ├── q_2 ├── V_2
|
||||
├── E_2 ├── K_2 ├── R_2 ├── W_2
|
||||
├── F_2 ├── L_2 ├── Ra0 ├── w_2
|
||||
├── H_2 ├── M_2 ├── T_2 ├── z_2
|
||||
│ └── N_2
|
||||
```
|
||||
|
||||
~20 subclasses forming a processing chain, likely request/response middleware.
|
||||
|
||||
### 7. c90 / MIA / LIA Hierarchies (Specialized Bases)
|
||||
|
||||
```
|
||||
c90 - "State Manager?"
|
||||
├── Az2
|
||||
├── Bz2
|
||||
└── Qz2
|
||||
|
||||
MIA - "Input Schema?"
|
||||
├── CK2
|
||||
├── EK2
|
||||
└── zK2
|
||||
|
||||
LIA - "Output Schema?"
|
||||
├── DK2
|
||||
├── FK2
|
||||
├── HK2
|
||||
└── VK2
|
||||
```
|
||||
|
||||
## Key Named Classes (from string evidence)
|
||||
|
||||
| String Name | Context | Purpose |
|
||||
|-------------|---------|---------|
|
||||
| `"AgentBaseInternalState"` | State management | Internal state for agent instances |
|
||||
| `"ModelErrorException"` | Error handling | API model error (extends `uU`) |
|
||||
| `"McpError"` | MCP protocol | MCP communication errors |
|
||||
| `"FileReadStream"` | File I/O | Streaming file reader |
|
||||
| `"FileWriteStream"` | File I/O | Streaming file writer |
|
||||
| `"GlobalSession"` | Session management | Global session state singleton |
|
||||
| `"GlobalPreferences"` | Settings | User preferences singleton |
|
||||
| `"GlobalKeyMap"` | Input handling | Keyboard shortcut mappings |
|
||||
| `"GlobalRef"` | React state | Global reference container |
|
||||
|
||||
## Tool Registry Type (reconstructed from `XF0` class)
|
||||
|
||||
```typescript
|
||||
class ToolRegistry { // XF0 in minified
|
||||
toolDefinitions: Tool[];
|
||||
canUseTool: PermissionChecker;
|
||||
tools: Tool[];
|
||||
toolUseContext: ToolUseContext;
|
||||
hasErrored: boolean;
|
||||
progressAvailableResolve: Function;
|
||||
|
||||
constructor(tools: Tool[], canUseTool: PermissionChecker, context: ToolUseContext) {
|
||||
this.toolDefinitions = tools;
|
||||
this.canUseTool = canUseTool;
|
||||
this.toolUseContext = context;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## AppState Type (reconstructed from `Ll()`)
|
||||
|
||||
```typescript
|
||||
interface AppState {
|
||||
settings: Settings;
|
||||
backgroundTasks: Record<string, unknown>;
|
||||
verbose: boolean;
|
||||
mainLoopModel: string | null;
|
||||
mainLoopModelForSession: string | null;
|
||||
statusLineText: string | undefined;
|
||||
showExpandedTodos: boolean;
|
||||
toolPermissionContext: ToolPermissionContext;
|
||||
agent: string | undefined;
|
||||
agentDefinitions: {
|
||||
activeAgents: AgentDefinition[];
|
||||
allAgents: AgentDefinition[];
|
||||
};
|
||||
fileHistory: {
|
||||
snapshots: Snapshot[];
|
||||
trackedFiles: Set<string>;
|
||||
};
|
||||
mcp: {
|
||||
clients: McpClient[];
|
||||
tools: Tool[];
|
||||
commands: Command[];
|
||||
resources: Record<string, Resource[]>;
|
||||
};
|
||||
plugins: {
|
||||
enabled: Plugin[];
|
||||
disabled: Plugin[];
|
||||
commands: Command[];
|
||||
agents: AgentDefinition[];
|
||||
errors: Error[];
|
||||
installationStatus: InstallationStatus;
|
||||
};
|
||||
todos: Record<string, Todo>;
|
||||
notifications: { current: Notification | null; queue: Notification[] };
|
||||
elicitation: { queue: unknown[] };
|
||||
thinkingEnabled: boolean;
|
||||
feedbackSurvey: { timeLastShown: number | null; submitCountAtLastAppearance: number | null };
|
||||
sessionHooks: Record<string, unknown>;
|
||||
inbox: { messages: unknown[] };
|
||||
promptSuggestion: { text: string | null; shownAt: number };
|
||||
queuedCommands: Command[];
|
||||
gitDiff: { stats: unknown | null; hunks: Map<string, unknown>; lastUpdated: number };
|
||||
}
|
||||
```
|
||||
|
||||
## Model Names (from `yGA` / `kGA` arrays)
|
||||
|
||||
```typescript
|
||||
const modelNames = ["sonnet", "opus", "haiku", "sonnet[1m]"]; // yGA
|
||||
const modelNamesWithInherit = [...modelNames, "inherit"]; // kGA
|
||||
```
|
||||
|
||||
## Agent Definition Schema (from Zod validation)
|
||||
|
||||
```typescript
|
||||
const agentDefinitionSchema = z.object({
|
||||
prompt: z.string().min(1, "Prompt cannot be empty"),
|
||||
model: z.enum(kGA).optional(),
|
||||
permissionMode: z.enum(ET).optional(),
|
||||
// ET = ["acceptEdits", "bypassPermissions", "default", "dontAsk", "plan"]
|
||||
});
|
||||
```
|
||||
410
docs/research/claude-code-rvsource/18-state-machines.md
Normal file
410
docs/research/claude-code-rvsource/18-state-machines.md
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
# 18 - State Machine Diagrams
|
||||
|
||||
State machines extracted from actual code patterns in `cli.js` (v2.0.62).
|
||||
|
||||
## 1. Agent Loop State Machine
|
||||
|
||||
The agent loop (`s$`) is the primary state machine. It operates as an async generator
|
||||
that transitions through states by yielding events.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────┐ │
|
||||
│ IDLE │ (waiting for user input) │
|
||||
└────┬─────┘ │
|
||||
│ User submits query │
|
||||
▼ │
|
||||
┌──────────┐ │
|
||||
│ PREPARING │ JP() - prepareQuery │
|
||||
│ │ Count tokens, build system prompt │
|
||||
└────┬─────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────┐ ┌──────────┐ │
|
||||
│ CHECKING │────►│COMPACTING│ │
|
||||
│ CONTEXT │ │ │ Run summarization │
|
||||
└────┬─────┘ └────┬─────┘ │
|
||||
│ │ Done │
|
||||
│◄──────────────┘ │
|
||||
▼ │
|
||||
┌──────────┐ │
|
||||
│ STREAMING │ Call Anthropic Messages API │
|
||||
│ │ Process SSE events │
|
||||
└────┬─────┘ │
|
||||
│ Response complete │
|
||||
▼ │
|
||||
┌──────────┐ │
|
||||
│ EVALUATING│ Check stop_reason │
|
||||
└────┬─────┘ │
|
||||
│ │
|
||||
┌────────┼────────┐ │
|
||||
▼ ▼ ▼ │
|
||||
┌─────────┐ ┌──────┐ ┌──────────┐ │
|
||||
│end_turn │ │max_ │ │tool_use │ │
|
||||
│ │ │tokens│ │ │ │
|
||||
└────┬────┘ └──┬───┘ └────┬─────┘ │
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ │
|
||||
┌─────────┐ ┌──────┐ ┌──────────┐ │
|
||||
│ DONE │ │ DONE │ │DISPATCHING│ Process tool calls │
|
||||
└─────────┘ └──────┘ │ TOOLS │ │
|
||||
└────┬─────┘ │
|
||||
│ │
|
||||
┌─────────┼─────────┐ │
|
||||
▼ ▼ ▼ │
|
||||
┌──────────┐ ┌──────┐ ┌──────────┐ │
|
||||
│PERMISSION│ │EXEC │ │MCP CALL │ │
|
||||
│CHECK │ │TOOL │ │ │ │
|
||||
└────┬─────┘ └──┬───┘ └────┬─────┘ │
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ │
|
||||
┌──────────────────────────────┐ │
|
||||
│ ASSEMBLING TOOL RESULTS │ │
|
||||
└────────────┬─────────────────┘ │
|
||||
│ │
|
||||
│ yield* s$() (recursive) │
|
||||
└──────────────────────────────────┘
|
||||
```
|
||||
|
||||
### State Transitions Table
|
||||
|
||||
| From | To | Trigger | Action |
|
||||
|------|----|---------|--------|
|
||||
| IDLE | PREPARING | User input | `JP()` / `c_7()` |
|
||||
| PREPARING | CHECKING_CONTEXT | Query built | `qh2()` token count |
|
||||
| CHECKING_CONTEXT | COMPACTING | Tokens > threshold | Compaction API call |
|
||||
| CHECKING_CONTEXT | STREAMING | Tokens OK | `s$()` entry |
|
||||
| COMPACTING | CHECKING_CONTEXT | Summary received | Replace messages |
|
||||
| STREAMING | EVALUATING | `message_stop` SSE | Accumulate response |
|
||||
| EVALUATING | DONE | `end_turn` | Yield stop |
|
||||
| EVALUATING | DONE | `max_tokens` | Yield stop |
|
||||
| EVALUATING | DISPATCHING_TOOLS | `tool_use` blocks | Process tools |
|
||||
| DISPATCHING_TOOLS | PERMISSION_CHECK | Each tool | `canUseTool()` |
|
||||
| PERMISSION_CHECK | EXEC_TOOL | Allowed | `tool.call()` |
|
||||
| PERMISSION_CHECK | ASSEMBLING | Denied | Error result |
|
||||
| EXEC_TOOL | ASSEMBLING | Tool done | Collect result |
|
||||
| ASSEMBLING | STREAMING | `yield* s$()` | Recursive loop |
|
||||
|
||||
## 2. Permission System State Machine
|
||||
|
||||
```
|
||||
┌───────────────────┐
|
||||
│ PERMISSION CHECK │
|
||||
│ canUseTool() │
|
||||
└────────┬──────────┘
|
||||
│
|
||||
┌───────────┼───────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ MODE: │ │ MODE: │ │ MODE: │
|
||||
│ bypass │ │ default │ │ plan │
|
||||
│ dontAsk │ │ acceptEd │ │ │
|
||||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌────────┐ ┌──────────┐ ┌────────┐
|
||||
│ ALLOW │ │CHECK RULES│ │ DENY │
|
||||
└────────┘ └────┬─────┘ └────────┘
|
||||
│
|
||||
┌───────────┼───────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ MATCH │ │ MATCH │ │ NO MATCH │
|
||||
│ ALLOW │ │ DENY │ │ │
|
||||
│ RULE │ │ RULE │ │ │
|
||||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌────────┐ ┌────────┐ ┌──────────┐
|
||||
│ ALLOW │ │ DENY │ │ ASK USER │
|
||||
└────────┘ └────────┘ └────┬─────┘
|
||||
│
|
||||
┌────────┼────────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐┌────────┐┌──────────┐
|
||||
│ ALLOW ││ ALLOW ││ DENY │
|
||||
│ ONCE ││ ALWAYS ││ │
|
||||
└────────┘└───┬────┘└──────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ ADD TO ALWAYS │
|
||||
│ ALLOW RULES │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### Permission Rule Matching
|
||||
|
||||
```
|
||||
Rule Format: "ToolName" or "ToolName(pattern)" or "ToolName(pattern:wildcard)"
|
||||
|
||||
Examples:
|
||||
"Bash" → matches all Bash commands
|
||||
"Bash(npm run:*)" → matches "npm run build", "npm run test", etc.
|
||||
"Bash(git commit:*)" → matches "git commit -m ..."
|
||||
"WebFetch(domain:*.com)" → matches any .com domain
|
||||
"Edit" → matches all file edits
|
||||
|
||||
Matching algorithm:
|
||||
1. Exact tool name match
|
||||
2. If rule has pattern: extract command from input
|
||||
3. If rule has wildcard (*): prefix match
|
||||
4. If rule has glob: glob match (limited on Linux)
|
||||
```
|
||||
|
||||
## 3. Session Lifecycle State Machine
|
||||
|
||||
```
|
||||
┌──────────┐
|
||||
│ INIT │
|
||||
└────┬─────┘
|
||||
│ Load settings, credentials
|
||||
▼
|
||||
┌──────────┐
|
||||
│ AUTH │ Validate API key / OAuth
|
||||
└────┬─────┘
|
||||
│
|
||||
┌───────┼───────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐ ┌──────┐ ┌──────┐
|
||||
│ CLI │ │ SDK │ │ MCP │
|
||||
│ REPL │ │ MODE │ │SERVER│
|
||||
└───┬────┘ └──┬───┘ └──┬───┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────────────────────┐
|
||||
│ ACTIVE SESSION │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ AppState (Ll()) │ │
|
||||
│ │ - mainLoopModel │ │
|
||||
│ │ - permissionContext │ │
|
||||
│ │ - mcp clients │ │
|
||||
│ │ - plugins │ │
|
||||
│ │ - todos │ │
|
||||
│ │ - fileHistory │ │
|
||||
│ │ - thinkingEnabled │ │
|
||||
│ └─────────────────────┘ │
|
||||
└──────────┬───────────────┘
|
||||
│
|
||||
┌───────┼───────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐ ┌──────┐ ┌──────────┐
|
||||
│QUERYING│ │IDLE │ │COMPACTING│
|
||||
│(s$ loop│ │ │ │ │
|
||||
└───┬────┘ └──────┘ └──────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────┐
|
||||
│SAVING │ History → ~/.claude/history.jsonl
|
||||
│ │ Session → ~/.claude/sessions/
|
||||
└────┬─────┘
|
||||
│
|
||||
▼
|
||||
┌──────────┐
|
||||
│ EXIT │ Cleanup MCP connections
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
## 4. Streaming Response State Machine
|
||||
|
||||
```
|
||||
┌──────────────┐
|
||||
│ REQUESTING │ (spinner active)
|
||||
└──────┬───────┘
|
||||
│ First SSE event
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ message_start│ Initialize accumulator
|
||||
└──────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
│ PROCESSING BLOCKS │◄──────────────┐
|
||||
└───────────┬───────────┘ │
|
||||
│ │
|
||||
┌────────┼────────┐ │
|
||||
▼ ▼ ▼ │
|
||||
┌────────┐┌────────┐┌──────────┐ │
|
||||
│ TEXT ││TOOL USE││THINKING │ │
|
||||
│ BLOCK ││ BLOCK ││ BLOCK │ │
|
||||
└───┬────┘└───┬────┘└────┬─────┘ │
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ │
|
||||
┌────────┐┌────────┐┌──────────┐ │
|
||||
│text_ ││input_ ││thinking_ │ │
|
||||
│delta ││json_ ││delta │ Repeat │
|
||||
│chunks ││delta ││chunks │──────────►│
|
||||
└───┬────┘└───┬────┘└────┬─────┘ │
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ │
|
||||
┌──────────────────────────┐ │
|
||||
│ content_block_stop │──────────────┘
|
||||
└──────────┬───────────────┘
|
||||
│ All blocks done
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ message_delta │ Usage info, stop_reason
|
||||
└──────────┬───────┘
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ message_stop │ Response complete
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
### Stream Mode Transitions (UI)
|
||||
|
||||
```
|
||||
"requesting" ──[first text_delta]──► "responding"
|
||||
"responding" ──[tool_use block]──► "tool-input"
|
||||
"tool-input" ──[block_stop]──► "responding" (if more text)
|
||||
"responding" ──[message_stop]──► "requesting" (next turn)
|
||||
```
|
||||
|
||||
## 5. MCP Connection State Machine
|
||||
|
||||
```
|
||||
┌──────────────┐
|
||||
│ DISCONNECTED │
|
||||
└──────┬───────┘
|
||||
│ Config loaded
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ CONNECTING │ Spawn process / HTTP connect
|
||||
└──────┬───────┘
|
||||
│
|
||||
┌──────┼──────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐┌─────┐┌──────┐
|
||||
│ STDIO ││ SSE ││ WS │
|
||||
└───┬────┘└──┬──┘└──┬───┘
|
||||
│ │ │
|
||||
└────────┼──────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ INITIALIZING │ Send: initialize
|
||||
└──────┬───────┘
|
||||
│ Receive: capabilities
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ READY │ List tools, resources
|
||||
└──────┬───────┘
|
||||
│
|
||||
┌───────┼───────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐┌──────┐┌──────────┐
|
||||
│TOOL ││IDLE ││RESOURCE │
|
||||
│CALL ││ ││READ │
|
||||
└───┬────┘└──────┘└────┬─────┘
|
||||
│ │
|
||||
└───────┬───────────┘
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ ERROR │
|
||||
└──────┬───────┘
|
||||
│ Retry / restart
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ RESTARTING │ "Restarting MCP server process"
|
||||
└──────┬───────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ CONNECTING │ (back to start)
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
## 6. Sandbox State Machine (Linux)
|
||||
|
||||
```
|
||||
┌──────────────┐
|
||||
│ CHECK CONFIG │ IQ()?.sandbox?.enabled
|
||||
└──────┬───────┘
|
||||
│
|
||||
┌──────┼──────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐┌─────┐┌──────────┐
|
||||
│DISABLED││macOS││ LINUX │
|
||||
└────────┘│SEATB││ SOCKS │
|
||||
└──┬──┘└────┬─────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌────────────────────┐
|
||||
│ COMMAND RECEIVED │
|
||||
└────────┬───────────┘
|
||||
│
|
||||
┌────────┼────────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐┌──────┐┌──────────┐
|
||||
│EXCLUDED││SANDBO││DANGEROUS │
|
||||
│COMMAND ││XED ││LY DISABLE│
|
||||
└───┬────┘└──┬───┘└────┬─────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌────────┐┌────────┐┌────────┐
|
||||
│DIRECT ││WRAPPED ││DIRECT │
|
||||
│EXEC ││EXEC ││EXEC │
|
||||
└────────┘└────────┘└────────┘
|
||||
```
|
||||
|
||||
## 7. Model Selection State Machine
|
||||
|
||||
```
|
||||
┌──────────────────────────────┐
|
||||
│ ye() - resolveModel │
|
||||
└──────────────┬───────────────┘
|
||||
│
|
||||
┌──────────────┼──────────────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ ENV │ │ USER │ │ DEFAULT │
|
||||
│ OVERRIDE│ │ SELECTED │ │ │
|
||||
│ANTHROPIC│ │(AppState)│ │ Fg1 │
|
||||
│_MODEL │ └────┬─────┘ └────┬─────┘
|
||||
└───┬────┘ │ │
|
||||
│ ┌────┼────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌──────┐┌───┐┌──────┐ │
|
||||
│ │inherit││ ││direct│ │
|
||||
│ └──┬───┘│ │└──┬───┘ │
|
||||
│ │ │ │ │ │
|
||||
│ ▼ │ │ │ │
|
||||
│ ┌──────────┐│ │ │
|
||||
│ │PERMISSION│◄───┘ │
|
||||
│ │MODE CHECK│ │
|
||||
│ └────┬─────┘ │
|
||||
│ │ │
|
||||
│ ┌────┼────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌────┐┌────┐┌────┐ │
|
||||
│ │plan││def ││bypass │
|
||||
│ │mode││ ││ │ │
|
||||
│ └─┬──┘└─┬──┘└─┬──┘ │
|
||||
│ │ │ │ │
|
||||
└───┴─────┴─────┴───────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────┐
|
||||
│ YF() │ Normalize model string
|
||||
│ RESOLVED │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
## Key Observations
|
||||
|
||||
1. **The agent loop is recursive**, not iterative. Each tool execution triggers
|
||||
a new `yield*` delegation that creates a stack of generators. This enables
|
||||
natural backpressure and cancellation via abort controllers.
|
||||
|
||||
2. **Compaction is a sub-state of the main loop**, triggered by token counting
|
||||
before each API call. It can itself fail and has retry/fallback logic.
|
||||
|
||||
3. **Permission checking is synchronous within the loop** but can suspend
|
||||
for user input (interactive mode) or return immediately (bypass/dontAsk modes).
|
||||
|
||||
4. **Streaming is event-driven** with a well-defined state machine matching
|
||||
the Anthropic Messages API SSE protocol exactly.
|
||||
|
||||
5. **MCP connections are persistent** with automatic restart on failure,
|
||||
following the MCP specification's connection lifecycle.
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
# RuVector + Claude Code Integration Guide
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Connect to Shared Brain (30 seconds)
|
||||
|
||||
```bash
|
||||
claude mcp add π --url https://mcp.pi.ruv.io
|
||||
```
|
||||
|
||||
This gives you 40+ brain tools: `brain_search`, `brain_share`, `brain_status`, etc.
|
||||
|
||||
### 2. Install Full Local Stack (2 minutes)
|
||||
|
||||
```bash
|
||||
# MCP brain (local, 91 tools including vector DB, hooks, SONA)
|
||||
claude mcp add claude-flow -- npx -y @claude-flow/cli@latest
|
||||
|
||||
# Brain server (shared intelligence, 40 tools)
|
||||
claude mcp add π --url https://mcp.pi.ruv.io
|
||||
```
|
||||
|
||||
### 3. Add RuVector Agents
|
||||
|
||||
Copy to `.claude/agents/`:
|
||||
|
||||
```bash
|
||||
cp examples/claude-agents/*.md .claude/agents/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Tiers
|
||||
|
||||
### Tier 1: MCP Tools (You Have This)
|
||||
|
||||
**What**: Claude Code calls RuVector tools via MCP protocol.
|
||||
|
||||
**Architecture**:
|
||||
```
|
||||
Claude Code ──stdio──▶ claude-flow MCP ──▶ local tools (91)
|
||||
Claude Code ──SSE────▶ mcp.pi.ruv.io ──▶ brain tools (40)
|
||||
```
|
||||
|
||||
**Key tools**:
|
||||
| Tool | Use Case |
|
||||
|------|----------|
|
||||
| `brain_search` | Find existing patterns before coding |
|
||||
| `brain_share` | Contribute discoveries to collective |
|
||||
| `brain_partition` | See knowledge topology |
|
||||
| `brain_consciousness_compute` | IIT Phi on transition systems |
|
||||
| `brain_reason` | Neural-symbolic inference |
|
||||
|
||||
**Optimization**: Search brain BEFORE implementing. Add to CLAUDE.md:
|
||||
```markdown
|
||||
Before implementing any feature, search the π brain:
|
||||
brain_search("your feature description")
|
||||
```
|
||||
|
||||
### Tier 2: WASM-Accelerated Local Tools
|
||||
|
||||
**What**: Run vector search, embedding, and graph ops locally via WASM — no network round-trip.
|
||||
|
||||
**Architecture**:
|
||||
```
|
||||
Claude Code ──stdio──▶ RuVector Hybrid MCP
|
||||
├──▶ WASM (hot path): search, embed, phi
|
||||
└──▶ Network (cold path): write, train, sync
|
||||
```
|
||||
|
||||
**WASM modules available** (31 crates):
|
||||
|
||||
| Module | Size | Capability |
|
||||
|--------|------|------------|
|
||||
| `micro-hnsw-wasm` | 5.5KB | Vector nearest-neighbor search |
|
||||
| `ruvector-cnn-wasm` | ~50KB | CNN inference + embeddings |
|
||||
| `ruvector-consciousness-wasm` | ~30KB | IIT 4.0 Phi computation |
|
||||
| `ruvector-delta-wasm` | ~10KB | Delta/change tracking |
|
||||
| `ruvector-dag-wasm` | ~15KB | DAG graph operations |
|
||||
| `ruqu-wasm` | ~8KB | Vector quantization (4-32x compression) |
|
||||
| `ruvector-attention-wasm` | ~20KB | Attention mechanisms |
|
||||
|
||||
**Build a hybrid MCP server**:
|
||||
|
||||
```rust
|
||||
// crates/ruvector-claude-mcp/src/main.rs
|
||||
use micro_hnsw_wasm::HnswIndex;
|
||||
use ruvector_cnn_wasm::Embedder;
|
||||
|
||||
struct HybridMcpServer {
|
||||
// Local WASM-powered operations
|
||||
local_index: HnswIndex, // cached vectors for search
|
||||
embedder: Embedder, // local embedding generation
|
||||
|
||||
// Remote brain for writes
|
||||
brain_url: String, // https://pi.ruv.io
|
||||
}
|
||||
|
||||
impl HybridMcpServer {
|
||||
async fn brain_search(&self, query: &str) -> Vec<Memory> {
|
||||
// 1. Embed query locally (WASM, <5ms)
|
||||
let embedding = self.embedder.embed(query);
|
||||
|
||||
// 2. Search local cache first (WASM HNSW, <1ms)
|
||||
let local_results = self.local_index.search(&embedding, 10);
|
||||
|
||||
// 3. If cache miss or stale, fall back to remote
|
||||
if local_results.is_empty() || self.is_stale() {
|
||||
return self.remote_search(query).await;
|
||||
}
|
||||
local_results
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Tier 3: Hooks Integration
|
||||
|
||||
**What**: React to Claude Code events in real-time.
|
||||
|
||||
**Hook events mapped to RuVector actions**:
|
||||
|
||||
| Event | Trigger | RuVector Action |
|
||||
|-------|---------|-----------------|
|
||||
| `PreToolUse(Edit)` | Before file edit | Check brain for anti-patterns |
|
||||
| `PreToolUse(Bash)` | Before command | Security scan via WASM |
|
||||
| `PostToolUse(Bash)` | After command | Learn from errors, share to brain |
|
||||
| `PostToolUse(Edit)` | After file edit | Track delta, update knowledge graph |
|
||||
| `Stop` | Session ends | Share session discoveries to brain |
|
||||
| `Notification` | Agent notification | Route to brain voice system |
|
||||
|
||||
**Setup** (add to `.claude/settings.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "npx @ruvector/hooks pre-edit --file \"$CLAUDE_FILE_PATH\" --brain https://pi.ruv.io"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "npx @ruvector/hooks post-bash --exit-code \"$CLAUDE_EXIT_CODE\" --learn"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "npx @ruvector/hooks session-end --share-discoveries"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Tier 4: Custom Agents
|
||||
|
||||
**What**: Specialized AI personas that use RuVector tools natively.
|
||||
|
||||
**Agent: Brain-First Researcher**
|
||||
```markdown
|
||||
# .claude/agents/brain-researcher.md
|
||||
---
|
||||
name: brain-researcher
|
||||
description: Research with collective brain intelligence before coding
|
||||
model: claude-sonnet-4-6
|
||||
tools: [Read, Grep, Glob, WebSearch, mcp__pi-brain__brain_search, mcp__pi-brain__brain_share, mcp__pi-brain__brain_partition]
|
||||
---
|
||||
|
||||
You are a researcher with access to the π collective brain (6,600+ memories, 100+ contributors).
|
||||
|
||||
ALWAYS search the brain before starting research:
|
||||
1. brain_search("topic") to find existing knowledge
|
||||
2. brain_partition() to see knowledge clusters
|
||||
3. Only then do your own research
|
||||
4. brain_share() any new discoveries back to the collective
|
||||
```
|
||||
|
||||
**Agent: Consciousness Analyzer**
|
||||
```markdown
|
||||
# .claude/agents/consciousness-analyst.md
|
||||
---
|
||||
name: consciousness-analyst
|
||||
description: Analyze code structures using IIT 4.0 consciousness metrics
|
||||
model: claude-opus-4-6
|
||||
tools: [Read, Grep, mcp__pi-brain__brain_consciousness_compute, mcp__pi-brain__brain_consciousness_status]
|
||||
---
|
||||
|
||||
You analyze software systems through the lens of Integrated Information Theory.
|
||||
Use brain_consciousness_compute to measure Phi (integrated information) of:
|
||||
- Module dependency graphs (as transition probability matrices)
|
||||
- State machines (as TPMs)
|
||||
- Data flow networks
|
||||
Higher Phi suggests more tightly integrated, conscious-like systems.
|
||||
```
|
||||
|
||||
### Tier 5: Prompt Cache Optimization
|
||||
|
||||
**What**: Structure CLAUDE.md for maximum Anthropic prompt cache hits.
|
||||
|
||||
**Principle**: Claude Code caches system prompt prefixes. Put stable content first:
|
||||
|
||||
```markdown
|
||||
# CLAUDE.md (optimized for cache)
|
||||
|
||||
## [STABLE - cached across sessions]
|
||||
### Project Rules
|
||||
- Use TypeScript strict mode
|
||||
- Follow TDD London School
|
||||
- Keep files under 500 lines
|
||||
|
||||
### RuVector Tool Reference
|
||||
brain_search(query) - semantic search across 6,600+ shared memories
|
||||
brain_share(category, title, content) - contribute knowledge
|
||||
brain_status() - system health check
|
||||
[... all 40 tool descriptions ...]
|
||||
|
||||
## [DYNAMIC - changes per session]
|
||||
### Current Sprint
|
||||
- Working on SSE proxy decoupling (ADR-130)
|
||||
- Brain has 6,628 memories, 101 contributors
|
||||
```
|
||||
|
||||
**Impact**: ~60-80% cache hit rate on system prompt tokens, significant cost reduction.
|
||||
|
||||
### Tier 6: Agent SDK + Remote Control
|
||||
|
||||
**What**: Embed Claude Code inside RuVector orchestration.
|
||||
|
||||
**Use case**: RuVector swarm coordinator drives multiple Claude Code instances.
|
||||
|
||||
```typescript
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
// Brain-enhanced autonomous coding
|
||||
async function brainAssistedTask(task: string) {
|
||||
// Pre-fetch brain context
|
||||
const context = await fetch("https://pi.ruv.io/v1/memories/search?q=" + encodeURIComponent(task));
|
||||
const memories = await context.json();
|
||||
|
||||
// Inject brain context into Claude Code session
|
||||
const enrichedPrompt = `
|
||||
Brain context (${memories.length} relevant memories):
|
||||
${memories.map(m => `- [${m.category}] ${m.title}`).join('\n')}
|
||||
|
||||
Task: ${task}
|
||||
`;
|
||||
|
||||
for await (const event of query({
|
||||
prompt: enrichedPrompt,
|
||||
options: {
|
||||
allowedTools: ["Read", "Edit", "Bash", "Grep"],
|
||||
maxTurns: 20,
|
||||
}
|
||||
})) {
|
||||
if (event.type === "result") {
|
||||
// Share discoveries back to brain
|
||||
await fetch("https://pi.ruv.io/v1/memories", {
|
||||
method: "POST",
|
||||
headers: { "Authorization": "Bearer " + apiKey },
|
||||
body: JSON.stringify({
|
||||
category: "solution",
|
||||
title: `Auto-discovered: ${task.slice(0, 80)}`,
|
||||
content: event.result,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Comparison
|
||||
|
||||
| Operation | Current (MCP+Network) | Optimized (WASM+Local) | Speedup |
|
||||
|-----------|----------------------|----------------------|---------|
|
||||
| `brain_search` | ~200ms | <5ms | 40x |
|
||||
| Embedding | ~100ms (API) | <10ms (WASM) | 10x |
|
||||
| Phi compute | ~500ms (network) | <20ms (WASM) | 25x |
|
||||
| Tool schema load | 40 tools at once | Deferred groups | 4x less tokens |
|
||||
| Security check | N/A | <1ms (WASM hook) | New capability |
|
||||
|
||||
## Architecture: Full Integration Stack
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ Claude Code CLI │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌─────────────────────────┐ │
|
||||
│ │ Agent │ │ Hooks │ │ MCP Servers │ │
|
||||
│ │ Loop │──│ Engine │──│ │ │
|
||||
│ │ (s$) │ │ │ │ ┌─────────────────────┐ │ │
|
||||
│ └──────────┘ │ Pre/Post │ │ │ RuVector Hybrid │ │ │
|
||||
│ │ Edit/Bash│ │ │ ┌─────────────────┐ │ │ │
|
||||
│ ┌──────────┐ │ Stop │ │ │ │ WASM Runtime │ │ │ │
|
||||
│ │ Custom │ └──────────┘ │ │ │ • hnsw-search │ │ │ │
|
||||
│ │ Agents │ │ │ │ • embed │ │ │ │
|
||||
│ │ brain-* │ │ │ │ • phi-compute │ │ │ │
|
||||
│ └──────────┘ │ │ │ • quantize │ │ │ │
|
||||
│ │ │ └────────┬────────┘ │ │ │
|
||||
│ ┌──────────┐ │ │ │ cache │ │ │
|
||||
│ │ Skills │ │ │ miss ▼ │ │ │
|
||||
│ │ /brain │ │ │ ┌──────────────┐ │ │ │
|
||||
│ │ /phi │ │ │ │ pi.ruv.io │ │ │ │
|
||||
│ └──────────┘ │ │ │ (REST API) │ │ │ │
|
||||
│ │ │ └──────────────┘ │ │ │
|
||||
│ │ └─────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────────────┐ │ │
|
||||
│ │ │ mcp.pi.ruv.io │ │ │
|
||||
│ │ │ (SSE proxy) │ │ │
|
||||
│ │ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────┘ │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Build `crates/ruvector-claude-mcp/` hybrid server (Tier 1)
|
||||
2. Ship agent definitions in `examples/claude-agents/` (Tier 2)
|
||||
3. Create `@ruvector/hooks` npm package (Tier 3)
|
||||
4. Restructure CLAUDE.md for cache optimization (Tier 4)
|
||||
5. Prototype Agent SDK embedding (Tier 5)
|
||||
6. Package as Claude Code plugin (Tier 6)
|
||||
|
||||
## References
|
||||
|
||||
- [ADR-134: RuVector Deep Integration](../../adr/ADR-134-ruvector-claude-code-deep-integration.md)
|
||||
- [ADR-133: Claude Code Source Analysis](../../adr/ADR-133-claude-code-source-analysis.md)
|
||||
- [13-extension-points.md](./13-extension-points.md)
|
||||
- [15-core-module-analysis.md](./15-core-module-analysis.md)
|
||||
- [16-call-graphs.md](./16-call-graphs.md)
|
||||
116
docs/research/claude-code-rvsource/extracted/agent-loop.rvf
Normal file
116
docs/research/claude-code-rvsource/extracted/agent-loop.rvf
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
type: source-extraction
|
||||
module: agent-loop
|
||||
binary: claude-code
|
||||
version: 2.0.62
|
||||
extraction-method: strings+pattern-match
|
||||
confidence: high
|
||||
---
|
||||
|
||||
# Agent Loop (s$) - Core Async Generator
|
||||
|
||||
## Function Signature (reconstructed from call sites)
|
||||
|
||||
```javascript
|
||||
async function* s$({
|
||||
messages, // Message[]
|
||||
systemPrompt, // string
|
||||
userContext, // Record<string, unknown>
|
||||
systemContext, // Record<string, unknown>
|
||||
canUseTool, // (toolName, input) => PermissionResult
|
||||
toolUseContext, // ToolUseContext object
|
||||
autoCompactTracking, // optional CompactTracker
|
||||
fallbackModel, // optional string
|
||||
stopHookActive, // optional boolean
|
||||
querySource // "sdk" | "repl" | "hook_agent" | "compact" | etc.
|
||||
})
|
||||
```
|
||||
|
||||
## Call Sites Found (10 invocations of s$)
|
||||
|
||||
1. SDK entry: `for await(let P1 of s$({messages:B1,systemPrompt:WA,userContext:r,systemContext:BA,canUseTool:t,toolUseContext:jA,fallbackModel:E,querySource:"sdk"}))`
|
||||
2. REPL query: `for await(let R8 of s$({messages:e0,systemPrompt:vK,userContext:_Y,systemContext:kI,canUseTool:IJ,toolUseContext:K6,querySource:jVA()}))`
|
||||
3. Direct query: `for await(let kI of s$({messages:[...CQ,...HB],systemPrompt:Y9,userContext:h8,systemContext:A5,canUseTool:IJ,toolUseContext:_Y,querySource:jVA()}))`
|
||||
4. Agent fork: `for await(let U of s$({messages:E,systemPrompt:W,userContext:K,systemContext:V,canUseTool:B,toolUseContext:H,querySource:G}))`
|
||||
5. Sub-agent: `for await(let r of s$({messages:H,systemPrompt:b,userContext:C,systemContext:U,canUseTool:G,toolUseContext:d,querySource:J}))`
|
||||
6. Tool result continuation (recursive): `yield*s$({messages:[...A,...Q,...K],systemPrompt:B,userContext:G,systemContext:Z,canUseTool:Y,toolUseContext:V,autoCompactTracking:I,fallbackModel:W,querySource:X})`
|
||||
7. Attachment resending: `yield*s$({messages:[...A,...Q,...K],systemPrompt:B,userContext:G,systemContext:Z,canUseTool:Y,toolUseContext:V,autoCompactTracking:I,fallbackModel:W,querySource:X})`
|
||||
8. Stop hook continuation: `yield*s$({messages:[...A,...Q,...D],systemPrompt:B,userContext:G,systemContext:Z,canUseTool:Y,toolUseContext:J,autoCompactTracking:I,fallbackModel:W,stopHookActive:!0,querySource:X})`
|
||||
9. Hook agent: `for await(let r of s$({messages:H,systemPrompt:b,userContext:{},systemContext:{},canUseTool:a$,toolUseContext:t,querySource:"hook_agent"}))`
|
||||
10. Compaction: called with `querySource:"compact"` for summarization
|
||||
|
||||
## Entry Point (s$ definition, partially reconstructed)
|
||||
|
||||
```javascript
|
||||
async function* s$({messages, systemPrompt, userContext, systemContext, canUseTool, toolUseContext, autoCompactTracking, fallbackModel, stopHookActive, querySource}) {
|
||||
let sdkBetas = toolUseContext.options.sdkBetas;
|
||||
yield {type: "stream_request_start"};
|
||||
|
||||
// Build API parameters
|
||||
// ... token counting, system prompt assembly ...
|
||||
|
||||
// Call Anthropic Messages API (streaming)
|
||||
// ... SSE processing loop ...
|
||||
|
||||
// For each content block:
|
||||
// - text: accumulate text_delta
|
||||
// - tool_use: accumulate input_json_delta
|
||||
// - thinking: accumulate thinking_delta
|
||||
|
||||
// When message_stop:
|
||||
yield {type: "assistant", message: accumulatedMessage};
|
||||
|
||||
// If tool_use blocks present:
|
||||
// For each tool:
|
||||
// 1. Permission check via canUseTool
|
||||
// 2. Execute tool.call()
|
||||
// 3. Collect results
|
||||
// Assemble tool_result messages
|
||||
// yield {type: "user", tool_results}
|
||||
// yield* s$({...updatedParams}) // RECURSIVE
|
||||
|
||||
// If end_turn:
|
||||
// yield {type: "stop"}
|
||||
|
||||
// Run stop hooks if active
|
||||
}
|
||||
```
|
||||
|
||||
## Event Consumer Pattern (iBA function)
|
||||
|
||||
```javascript
|
||||
// iBA processes events from the generator:
|
||||
function iBA(event, addMessage, updateLength, setStreamMode, clearSpinner) {
|
||||
switch (event.type) {
|
||||
case "assistant":
|
||||
addMessage(event.message);
|
||||
break;
|
||||
case "user":
|
||||
addMessage(event.message);
|
||||
break;
|
||||
case "stream_event":
|
||||
if (event.event.type === "content_block_delta" && event.event.delta.type === "text_delta") {
|
||||
updateLength(event.event.delta.text.length);
|
||||
}
|
||||
break;
|
||||
// ... other event types
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Query Preparation (JP / c_7 functions)
|
||||
|
||||
```javascript
|
||||
// c_7 prepares the query context
|
||||
async function c_7({input, mode, messages, mainLoopModel, pastedContents, ideSelection,
|
||||
memoryPath, thinkingTokens, thinkingEnabled, querySource, commands,
|
||||
isLoading, setIsLoading, setToolJSX, getToolUseContext,
|
||||
setUserInputOnProcessing, setAbortController, onQuery,
|
||||
resetLoadingState, setAppState, onBeforeQuery, resetHistory}) {
|
||||
// 1. Create abort controller
|
||||
// 2. Build thinking config: p_7(mode, thinkingTokens, input, thinkingEnabled)
|
||||
// 3. Prepare messages and tools
|
||||
// 4. Call onQuery callback
|
||||
// 5. Return history entry
|
||||
}
|
||||
```
|
||||
225
docs/research/claude-code-rvsource/extracted/context-manager.rvf
Normal file
225
docs/research/claude-code-rvsource/extracted/context-manager.rvf
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
---
|
||||
type: source-extraction
|
||||
module: context-manager
|
||||
binary: claude-code
|
||||
version: 2.0.62
|
||||
extraction-method: strings+pattern-match
|
||||
confidence: high
|
||||
---
|
||||
|
||||
# Context Window Management
|
||||
|
||||
## Token Counting (qh2 function)
|
||||
|
||||
```javascript
|
||||
async function qh2(messages, mainLoopModel, getPermissionContext, tools, agentDefinitions, terminalWidth) {
|
||||
let model = resolveModel({permissionMode: (await getPermissionContext()).mode, mainLoopModel});
|
||||
let contextWindow = getContextWindow(model); // Bd(model)
|
||||
|
||||
// Count tokens from multiple sources in parallel:
|
||||
let [
|
||||
messageTokens,
|
||||
{claudeMdTokens, memoryFileDetails},
|
||||
systemPromptTokens,
|
||||
{mcpToolTokens, mcpToolDetails},
|
||||
{agentTokens, agentDetails},
|
||||
{slashCommandTokens, commandInfo},
|
||||
totalBaseTokens
|
||||
] = await Promise.all([
|
||||
countMessageTokens(messages, model), // ra5
|
||||
countClaudeMdTokens(), // oa5
|
||||
countSystemPromptTokens(messages, getPermissionContext, agentDefinitions, model), // ta5
|
||||
countMcpToolTokens(messages, getPermissionContext, agentDefinitions, model), // pjA
|
||||
countAgentTokens(agentDefinitions), // Qs5
|
||||
countSlashCommandTokens(messages, getPermissionContext, agentDefinitions), // As5
|
||||
countBaseTokens(query) // Bs5
|
||||
]);
|
||||
|
||||
// Return breakdown for /context command display
|
||||
return {
|
||||
totalTokens,
|
||||
contextWindow,
|
||||
items: [
|
||||
{ name: "messages", tokens: messageTokens },
|
||||
{ name: "claudeMd", tokens: claudeMdTokens },
|
||||
{ name: "mcpTools", tokens: mcpToolTokens },
|
||||
// ...
|
||||
]
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Auto-Compact Configuration
|
||||
|
||||
```javascript
|
||||
// Compact trigger configuration sent to API:
|
||||
{
|
||||
type: "clear_tool_uses_20250919", // API feature name
|
||||
trigger: {
|
||||
type: "input_tokens",
|
||||
value: API_TARGET_INPUT_TOKENS // from env or default (qzB)
|
||||
},
|
||||
clear_at_least: {
|
||||
type: "input_tokens",
|
||||
value: targetValue
|
||||
}
|
||||
}
|
||||
|
||||
// Environment override:
|
||||
// API_TARGET_INPUT_TOKENS env var controls the threshold
|
||||
```
|
||||
|
||||
## Compaction Algorithm
|
||||
|
||||
```javascript
|
||||
// Triggered when: input_tokens > threshold
|
||||
// Telemetry event: "tengu_compact"
|
||||
|
||||
async function* compact(messages, toolUseContext, ...) {
|
||||
// 1. Set stream mode to "requesting"
|
||||
toolUseContext.setStreamMode?.("requesting");
|
||||
|
||||
// 2. Call API with compaction prompt
|
||||
let response = await callAPI({
|
||||
messages: messages,
|
||||
querySource: "compact",
|
||||
// Separate system prompt for compaction
|
||||
});
|
||||
|
||||
// 3. Validate response
|
||||
let summary = extractTextContent(response); // Sn()
|
||||
if (!summary) throw Error("Failed to generate conversation summary");
|
||||
if (summary.startsWith(ERROR_PREFIX)) throw Error(summary); // VV constant
|
||||
if (summary.startsWith(SYSTEM_PREFIX)) throw Error("prompt_too_long"); // GIA constant
|
||||
|
||||
// 4. Refresh file state
|
||||
refreshReadFileState(toolUseContext.readFileState); // c12()
|
||||
|
||||
// 5. Run post-compact hooks
|
||||
let hookResults = await runHooks("compact"); // z$("compact")
|
||||
|
||||
// 6. Restore tracked files
|
||||
let fileAttachments = await Promise.all(
|
||||
trackedFiles.map(async (file) => {
|
||||
let content = await readFileForCompact(file.filename, {
|
||||
fileReadingLimits: { maxTokens: FILE_TOKEN_LIMIT } // iE5
|
||||
});
|
||||
return content ? createAttachment(content) : null;
|
||||
})
|
||||
);
|
||||
|
||||
// 7. Track metrics
|
||||
let postCompactTokenCount = countTokens(summary);
|
||||
trackEvent("tengu_compact", {
|
||||
preCompactTokenCount,
|
||||
postCompactTokenCount,
|
||||
compactionInputTokens: usage?.input_tokens,
|
||||
compactionOutputTokens: usage?.output_tokens,
|
||||
compactionCacheReadTokens: usage?.cache_read_input_tokens ?? 0,
|
||||
compactionCacheCreationTokens: usage?.cache_creation_input_tokens ?? 0,
|
||||
});
|
||||
|
||||
// 8. Return compacted state
|
||||
return {
|
||||
boundaryMarker,
|
||||
summaryMessages: [summary],
|
||||
attachments: fileAttachments,
|
||||
hookResults,
|
||||
userDisplayMessage,
|
||||
preCompactTokenCount,
|
||||
postCompactTokenCount,
|
||||
compactionUsage: usage
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Micro-Compaction
|
||||
|
||||
```javascript
|
||||
// Removes stale tool_use blocks without full re-summarization
|
||||
// Tracked as: "tengu_microcompact"
|
||||
|
||||
function microCompact(messages, toolUseContext) {
|
||||
let compactedTools = new Set();
|
||||
let totalUncompactedTokens = 0;
|
||||
let tokensSaved = 0;
|
||||
|
||||
for (let msg of messages) {
|
||||
if (isStaleToolUse(msg)) {
|
||||
compactedTools.add(msg.id);
|
||||
tokensSaved += countTokens(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactedTools.size > 0) {
|
||||
trackEvent("tengu_microcompact", {
|
||||
toolsCompacted: compactedTools.size,
|
||||
totalUncompactedTokens,
|
||||
tokensAfterCompaction: totalUncompactedTokens - tokensSaved,
|
||||
tokensSaved,
|
||||
triggerType: "auto"
|
||||
});
|
||||
}
|
||||
|
||||
return filteredMessages;
|
||||
}
|
||||
```
|
||||
|
||||
## File Read State Cache
|
||||
|
||||
```javascript
|
||||
// LRU cache for file read state
|
||||
// Used during compaction to track which files are in context
|
||||
let readFileState = new LRUCache({ max: 1000 }); // new eS({max: 1000})
|
||||
|
||||
// After compaction, stale entries are cleaned:
|
||||
function refreshReadFileState(readFileState) {
|
||||
// Remove entries for files no longer referenced
|
||||
// Re-read files that are still tracked
|
||||
}
|
||||
```
|
||||
|
||||
## Compact Boundary Marker
|
||||
|
||||
```javascript
|
||||
// System message marking compaction point in history:
|
||||
{
|
||||
type: "system",
|
||||
content: "Conversation compacted",
|
||||
level: "info",
|
||||
subtype: "compact_boundary",
|
||||
uuid: generateUUID(),
|
||||
timestamp: new Date().toISOString(),
|
||||
isMeta: true // synthetic message
|
||||
}
|
||||
```
|
||||
|
||||
## Context Window Sizes (from Bd function)
|
||||
|
||||
```javascript
|
||||
// getContextWindow(model) returns max context tokens
|
||||
// Known model context windows:
|
||||
// - sonnet: standard context
|
||||
// - sonnet[1m]: 1M token context
|
||||
// - opus: standard context
|
||||
// - haiku: standard context
|
||||
// Exact values derived from model configuration
|
||||
```
|
||||
|
||||
## Thinking Token Budget
|
||||
|
||||
```javascript
|
||||
// Thinking tokens controlled by:
|
||||
const ULTRATHINK = 31999; // Maximum thinking tokens for ultrathink mode
|
||||
const NONE = 0;
|
||||
|
||||
// Regex to detect ultrathink request:
|
||||
const ultrathinkPattern = /\bultrathink\b/gi;
|
||||
|
||||
// Function to determine thinking budget:
|
||||
function getThinkingTokens(mode, userTokens, input, enabled) {
|
||||
if (!enabled) return 0;
|
||||
if (ultrathinkPattern.test(input)) return ULTRATHINK;
|
||||
return userTokens ?? getDefaultForModel(mode);
|
||||
}
|
||||
```
|
||||
214
docs/research/claude-code-rvsource/extracted/mcp-client.rvf
Normal file
214
docs/research/claude-code-rvsource/extracted/mcp-client.rvf
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
---
|
||||
type: source-extraction
|
||||
module: mcp-client
|
||||
binary: claude-code
|
||||
version: 2.0.62
|
||||
extraction-method: strings+pattern-match
|
||||
confidence: high
|
||||
---
|
||||
|
||||
# MCP Client Implementation
|
||||
|
||||
## Config Sources
|
||||
|
||||
```javascript
|
||||
// MCP server configurations loaded from:
|
||||
// 1. .mcp.json in project directory
|
||||
// 2. localSettings
|
||||
// 3. policySettings
|
||||
// 4. MCPB (MCP Bundles - downloadable packages)
|
||||
// 5. Dynamic config at runtime
|
||||
|
||||
// Config normalization:
|
||||
function normalizeServerName(name) {
|
||||
return UG(name); // Minified normalizer
|
||||
}
|
||||
```
|
||||
|
||||
## Tool Name Format
|
||||
|
||||
```javascript
|
||||
// MCP tools are namespaced: "mcp__<serverName>__<toolName>"
|
||||
// Example: "mcp__claude-flow__memory_store"
|
||||
|
||||
// Parsing:
|
||||
function parseMcpToolName(fullName) {
|
||||
// "mcp__" prefix check
|
||||
// Split on "__" to extract server and tool
|
||||
return { serverName, toolName };
|
||||
}
|
||||
|
||||
// Reverse:
|
||||
function buildMcpToolName(serverName, toolName) {
|
||||
return `mcp__${normalizeServerName(serverName)}__${toolName}`;
|
||||
}
|
||||
|
||||
// IDE tools have special prefix: "mcp__ide__"
|
||||
// Known: "mcp__ide__executeCode", "mcp__ide__getDiagnostics"
|
||||
```
|
||||
|
||||
## Transport Types
|
||||
|
||||
### stdio Transport
|
||||
```javascript
|
||||
// Spawns child process, communicates via stdin/stdout
|
||||
// Message format: 4-byte length prefix (LE uint32) + JSON payload
|
||||
async callTool(name, args) {
|
||||
let message = { method: "tools/call", params: { name, arguments: args } };
|
||||
let payload = JSON.stringify(message);
|
||||
let header = Buffer.allocUnsafe(4);
|
||||
header.writeUInt32LE(payload.length, 0);
|
||||
let packet = Buffer.concat([header, Buffer.from(payload)]);
|
||||
process.stdin.write(packet);
|
||||
}
|
||||
```
|
||||
|
||||
### SSE Transport
|
||||
```javascript
|
||||
// HTTP Server-Sent Events connection
|
||||
// Endpoint started on localhost with random port
|
||||
// Secret-based authentication
|
||||
class McpSseTransport {
|
||||
port;
|
||||
secret;
|
||||
isClosed = false;
|
||||
|
||||
constructor(serverName) {
|
||||
// Start HTTP server
|
||||
// Handle /sse endpoint for event stream
|
||||
// Handle /message endpoint for tool calls
|
||||
}
|
||||
|
||||
async sendMessage(message) {
|
||||
// POST to /message with JSON payload
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this.isClosed) return;
|
||||
this.isClosed = true;
|
||||
this.onclose?.();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### WebSocket Transport
|
||||
```javascript
|
||||
// WebSocket connection
|
||||
// Events: mcp_websocket_connect_fail, mcp_websocket_message_fail
|
||||
// Error states: mcp_websocket_send_not_opened, mcp_websocket_start_not_opened
|
||||
```
|
||||
|
||||
## MCP Protocol Messages
|
||||
|
||||
```javascript
|
||||
// Initialize handshake:
|
||||
// Client → Server: { method: "initialize", params: { capabilities, clientInfo } }
|
||||
// Server → Client: { result: { capabilities, serverInfo } }
|
||||
|
||||
// Tool discovery:
|
||||
// Client → Server: { method: "tools/list" }
|
||||
// Server → Client: { result: { tools: [...] } }
|
||||
|
||||
// Tool execution:
|
||||
// Client → Server: { method: "tools/call", params: { name, arguments } }
|
||||
// Server → Client: { result: { content: [...] } }
|
||||
|
||||
// Resource discovery:
|
||||
// Client → Server: { method: "resources/list" }
|
||||
// Server → Client: { result: { resources: [...] } }
|
||||
|
||||
// Resource read:
|
||||
// Client → Server: { method: "resources/read", params: { uri } }
|
||||
// Server → Client: { result: { contents: [...] } }
|
||||
```
|
||||
|
||||
## MCPB (MCP Bundles)
|
||||
|
||||
```javascript
|
||||
// MCPB files are packaged MCP servers
|
||||
// Download: LI5(url, targetPath, progressCallback)
|
||||
// Content hash: NI5(bytes) for integrity verification
|
||||
// Extraction: extract to ~/.claude/ directory
|
||||
|
||||
async function loadMcpBundle(name, config, progressCallback) {
|
||||
// 1. Download MCPB file
|
||||
// 2. Verify hash
|
||||
// 3. Extract to local path
|
||||
// 4. Return { mcpConfig, extractedPath }
|
||||
}
|
||||
|
||||
// State file management:
|
||||
// Read: readMcpStateFile(path) → { configs, normalizedNames, resources }
|
||||
// Write: persisted to ~/.claude/ state files
|
||||
```
|
||||
|
||||
## MCP Server Management (from /mcp command)
|
||||
|
||||
```javascript
|
||||
// Telemetry events:
|
||||
// "mcp_message" - message sent/received
|
||||
// "mcp_resource" - resource accessed
|
||||
// "mcp_tool_result" - tool execution result
|
||||
// "mcp_tool_use" - tool invocation
|
||||
// "mcp_status" - server status change
|
||||
|
||||
// Server restart:
|
||||
// "Restarting MCP server process"
|
||||
// "Establishing connection to MCP server"
|
||||
|
||||
// Error handling:
|
||||
// Timeout: k91() reads MCP_TIMEOUT env var (default from process.env)
|
||||
// Connection failure: logged and retried
|
||||
```
|
||||
|
||||
## Tool Registration
|
||||
|
||||
```javascript
|
||||
// MCP tools registered with enhanced metadata:
|
||||
async registerMcpTools(client, tools, getPermissionContext) {
|
||||
return tools.map(tool => ({
|
||||
...tool,
|
||||
description: await tool.prompt({
|
||||
getToolPermissionContext: async () => permCtx,
|
||||
tools: allTools,
|
||||
agents: []
|
||||
}),
|
||||
inputSchema: normalizeSchema(tool.inputSchema),
|
||||
outputSchema: tool.outputSchema
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
## Headers Helper
|
||||
|
||||
```javascript
|
||||
// MCP servers can specify a headersHelper script
|
||||
// Executed to get authentication headers dynamically
|
||||
async function getHeaders(serverName, config) {
|
||||
if (!config.headersHelper) return {};
|
||||
let result = await exec(config.headersHelper, [], { shell: true, timeout: 10000 });
|
||||
if (result.code !== 0 || !result.stdout) {
|
||||
throw Error(`headersHelper for MCP server '${serverName}' did not return valid value`);
|
||||
}
|
||||
return JSON.parse(result.stdout.trim());
|
||||
}
|
||||
```
|
||||
|
||||
## OAuth/OIDC Support
|
||||
|
||||
```javascript
|
||||
// MCP specification requires S256 code challenge method
|
||||
// OIDC discovery at authorization endpoint
|
||||
async function discoverOidcProvider(endpoint) {
|
||||
// Check for S256 code_challenge_methods_supported
|
||||
// If not supported: throw "Incompatible OIDC provider"
|
||||
}
|
||||
|
||||
// OAuth flow for MCP authentication:
|
||||
async function startOAuthFlow({metadata, clientInformation, redirectUrl, scope, state, resource}) {
|
||||
// 1. Check authorization_endpoint
|
||||
// 2. Verify response_types includes "code"
|
||||
// 3. Build authorization URL
|
||||
// 4. Return redirect URL
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
type: source-extraction
|
||||
module: permission-system
|
||||
binary: claude-code
|
||||
version: 2.0.62
|
||||
extraction-method: strings+pattern-match
|
||||
confidence: high
|
||||
---
|
||||
|
||||
# Permission System
|
||||
|
||||
## Permission Mode Enum (ET)
|
||||
|
||||
```javascript
|
||||
const ET = ["acceptEdits", "bypassPermissions", "default", "dontAsk", "plan"];
|
||||
```
|
||||
|
||||
## Permission Context (from xC() and Ll())
|
||||
|
||||
```javascript
|
||||
// toolPermissionContext structure:
|
||||
{
|
||||
mode: "default" | "acceptEdits" | "bypassPermissions" | "dontAsk" | "plan",
|
||||
alwaysAllowRules: {
|
||||
command: string[] // ["Bash(npm run:*)", "Bash(git:*) Edit", ...]
|
||||
}
|
||||
// Additional deny rules for paths, domains
|
||||
}
|
||||
```
|
||||
|
||||
## Rule Format Examples (from string literals)
|
||||
|
||||
```
|
||||
"Bash" → Allow all bash commands
|
||||
"Bash - allows all commands" → Description string
|
||||
"Bash(npm install express)" → Exact command match
|
||||
"Bash(npm run:*)" → Wildcard: any npm run subcommand
|
||||
"Bash(npm:*)" → Wildcard: any npm command
|
||||
"Bash(git:*)" → Wildcard: any git command
|
||||
"Bash(git commit:*)" → Wildcard: git commit with any args
|
||||
"Bash(git:*) Edit" → Combined: git + file editing
|
||||
"Bash,Edit,Read" → Multiple tools
|
||||
"Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),..."
|
||||
→ GitHub CLI permissions
|
||||
"WebFetch(domain:example.com)" → Exact domain
|
||||
"WebFetch(domain:*.google.com)" → Wildcard domain
|
||||
"WebSearch(claude ai)" → Specific search query
|
||||
```
|
||||
|
||||
## Path Permission Check (tD function)
|
||||
|
||||
```javascript
|
||||
// tD(path, toolPermissionContext, action, defaultResult)
|
||||
// action: "read" | "write" | "edit" | "deny"
|
||||
// Returns: "allow" | "deny" | "ask"
|
||||
|
||||
// File read permissions:
|
||||
// - Bash output files from current session: always allowed for reading
|
||||
// - Files matching sandbox rules: checked against read/write lists
|
||||
// - Project directory files: generally allowed
|
||||
// - Outside project: requires permission
|
||||
|
||||
// File write permissions:
|
||||
// - Checked against denyWrite list
|
||||
// - Glob patterns limited on Linux ("Glob patterns in sandbox permission rules are not fully supported on Linux")
|
||||
```
|
||||
|
||||
## Sandbox Configuration
|
||||
|
||||
```javascript
|
||||
// From IQ() settings:
|
||||
sandbox: {
|
||||
enabled: boolean,
|
||||
autoAllowBashIfSandboxed: boolean, // Auto-allow bash when sandbox is on
|
||||
allowUnsandboxedCommands: boolean, // Allow dangerouslyDisableSandbox
|
||||
excludedCommands: string[], // Commands that bypass sandbox
|
||||
ignoreViolations: boolean, // Don't report sandbox violations
|
||||
enableWeakerNestedSandbox: boolean, // For Docker environments
|
||||
ripgrep: RipgrepConfig // Ripgrep-specific sandbox config
|
||||
}
|
||||
```
|
||||
|
||||
## macOS Sandbox (seatbelt)
|
||||
|
||||
```javascript
|
||||
// Uses sandbox-exec -p <profile> to run commands
|
||||
// Profile includes:
|
||||
// - Essential permissions based on Chrome sandbox policy
|
||||
// - Process permissions: (allow process-exec)
|
||||
// - Network access control
|
||||
// - File system access control based on permission rules
|
||||
```
|
||||
|
||||
## Linux Sandbox (SOCKS bridge)
|
||||
|
||||
```javascript
|
||||
// Uses a SOCKS proxy bridge process for network isolation
|
||||
// Bridge socket: checked via existsSync()
|
||||
// Error: "The bridge process may have died. Try reinitializing the sandbox."
|
||||
```
|
||||
|
||||
## Sandbox Violation Tracking
|
||||
|
||||
```javascript
|
||||
// Violations are tracked and can be appended to tool context:
|
||||
function appendSandboxViolations(command) {
|
||||
let violations = getViolationsForCommand(command);
|
||||
if (violations.length === 0) return original;
|
||||
let result = original;
|
||||
result += "\n<sandbox_violations>\n";
|
||||
for (let v of violations) result += v.line + "\n";
|
||||
result += "</sandbox_violations>";
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
## Permission Decisions for Agent Types
|
||||
|
||||
```javascript
|
||||
// Agent definitions can specify permissionMode:
|
||||
// - Built-in agents like the plan mode agent use "dontAsk"
|
||||
// - Custom agents can use any mode from ET
|
||||
// - "inherit" model option inherits parent's permission mode
|
||||
|
||||
// Plan mode agent:
|
||||
{
|
||||
tools: [ED, pI, w7, nK, nS], // Limited tool set
|
||||
source: "built-in",
|
||||
model: "haiku",
|
||||
permissionMode: "dontAsk"
|
||||
}
|
||||
```
|
||||
|
||||
## Feature Flag Integration
|
||||
|
||||
```javascript
|
||||
// Permission behavior is gated by feature flags:
|
||||
// - Statsig: "default-permission-mode-config"
|
||||
// - GrowthBook: various experiment flags
|
||||
// - bypassPermissions can be disabled: "bypassPermissions mode is disabled by Statsig gate"
|
||||
// - autoAllowBashIfSandboxed behavior controlled by flags
|
||||
```
|
||||
|
||||
## Settings Sources (precedence)
|
||||
|
||||
```javascript
|
||||
// Permission settings loaded from multiple sources:
|
||||
// 1. localSettings (user's ~/.claude/settings.json)
|
||||
// 2. policySettings (enterprise policy)
|
||||
// 3. Project .claude/settings.json
|
||||
// 4. Environment variables
|
||||
// 5. CLI flags
|
||||
|
||||
// Key check:
|
||||
function hasSandboxConfig(sources) {
|
||||
for (let source of sources) {
|
||||
let settings = getSettings(source);
|
||||
if (settings?.sandbox?.enabled !== undefined ||
|
||||
settings?.sandbox?.autoAllowBashIfSandboxed !== undefined ||
|
||||
settings?.sandbox?.allowUnsandboxedCommands !== undefined)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
---
|
||||
type: source-extraction
|
||||
module: streaming-handler
|
||||
binary: claude-code
|
||||
version: 2.0.62
|
||||
extraction-method: strings+pattern-match
|
||||
confidence: high
|
||||
---
|
||||
|
||||
# Streaming Handler
|
||||
|
||||
## SSE Event Processing
|
||||
|
||||
Two parallel implementations exist in the codebase (SDK and internal client).
|
||||
Both follow the same pattern.
|
||||
|
||||
### Stream Event Router (from content_block_delta handler)
|
||||
|
||||
```javascript
|
||||
// Internal stream processor (NL class):
|
||||
class StreamProcessor {
|
||||
_emit(eventName, event, accumulator) { /* ... */ }
|
||||
|
||||
processEvent(event, accumulator) {
|
||||
this._emit("streamEvent", event, accumulator);
|
||||
|
||||
switch (event.type) {
|
||||
case "message_start":
|
||||
// Initialize response: accumulator = { content: [], usage: {} }
|
||||
break;
|
||||
|
||||
case "content_block_start":
|
||||
// Add new block to accumulator
|
||||
accumulator.content.push(event.content_block);
|
||||
// Block types: "text", "tool_use", "thinking", "server_tool_use", "mcp_tool_use"
|
||||
break;
|
||||
|
||||
case "content_block_delta":
|
||||
let block = accumulator.content.at(event.index);
|
||||
switch (event.delta.type) {
|
||||
case "text_delta":
|
||||
if (block.type === "text") {
|
||||
block.text += event.delta.text;
|
||||
}
|
||||
break;
|
||||
case "input_json_delta":
|
||||
// Tool use JSON accumulation
|
||||
if (block.type === "tool_use") {
|
||||
block.input_json = (block.input_json || "") + event.delta.partial_json;
|
||||
}
|
||||
break;
|
||||
case "thinking_delta":
|
||||
if (block.type === "thinking") {
|
||||
block.thinking += event.delta.thinking;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "content_block_stop":
|
||||
// Finalize block (parse JSON for tool_use, etc.)
|
||||
break;
|
||||
|
||||
case "message_delta":
|
||||
// Update usage and stop_reason
|
||||
if (event.usage) {
|
||||
accumulator.usage = { ...accumulator.usage, ...event.usage };
|
||||
}
|
||||
if (event.usage?.cache_read_input_tokens != null) {
|
||||
accumulator.usage.cache_read_input_tokens = event.usage.cache_read_input_tokens;
|
||||
}
|
||||
if (event.usage?.server_tool_use != null) {
|
||||
accumulator.usage.server_tool_use = event.usage.server_tool_use;
|
||||
}
|
||||
break;
|
||||
|
||||
case "message_stop":
|
||||
// Response complete
|
||||
break;
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SSE Line Parser
|
||||
|
||||
```javascript
|
||||
// Parses SSE text/event-stream format
|
||||
// Only processes events with specific types:
|
||||
function* parseSSEStream(lines) {
|
||||
for (let line of lines) {
|
||||
if (line.event === "message_start" ||
|
||||
line.event === "message_delta" ||
|
||||
line.event === "message_stop" ||
|
||||
line.event === "content_block_start" ||
|
||||
line.event === "content_block_delta" ||
|
||||
line.event === "content_block_stop") {
|
||||
try {
|
||||
yield JSON.parse(line.data);
|
||||
} catch (error) {
|
||||
throw error; // Parsing failure is fatal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Stream Mode State Management
|
||||
|
||||
```javascript
|
||||
// UI stream mode tracked for rendering:
|
||||
// setStreamMode: (mode) => void
|
||||
// Modes:
|
||||
// "requesting" - waiting for API response
|
||||
// "responding" - receiving text content
|
||||
// "tool-input" - receiving tool use JSON
|
||||
|
||||
// Transitions:
|
||||
// on content_block_delta with text_delta:
|
||||
// mode = "responding"
|
||||
// on content_block_start with tool_use:
|
||||
// mode = "tool-input"
|
||||
// on message_stop:
|
||||
// mode = "requesting"
|
||||
|
||||
// UI rendering hook:
|
||||
function handleStreamEvent(event, setStreamMode) {
|
||||
if (event.type === "content_block_delta") {
|
||||
switch (event.delta.type) {
|
||||
case "text_delta":
|
||||
setStreamMode("responding");
|
||||
break;
|
||||
case "input_json_delta":
|
||||
setStreamMode("tool-input");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Response Length Tracking
|
||||
|
||||
```javascript
|
||||
// setResponseLength tracks cumulative response size
|
||||
// Used for UI progress indicators
|
||||
|
||||
// In agent loop consumer (iBA):
|
||||
function handleEvent(event, addMessage, updateLength, setStreamMode, clearSpinner) {
|
||||
if (event.type === "stream_event" &&
|
||||
event.event.type === "content_block_delta" &&
|
||||
event.event.delta.type === "text_delta") {
|
||||
updateLength(event.event.delta.text.length);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Token Usage Tracking
|
||||
|
||||
```javascript
|
||||
// Per-model usage accumulator (FQ global state):
|
||||
// FQ.modelUsage[modelId] = {
|
||||
// inputTokens, outputTokens,
|
||||
// cacheReadInputTokens, cacheCreationInputTokens,
|
||||
// webSearchRequests, costUSD, contextWindow
|
||||
// }
|
||||
|
||||
function trackUsage(cost, model, usage) {
|
||||
let entry = FQ.modelUsage[model] || {
|
||||
inputTokens: 0, outputTokens: 0,
|
||||
cacheReadInputTokens: 0, cacheCreationInputTokens: 0,
|
||||
webSearchRequests: 0, costUSD: 0, contextWindow: 0
|
||||
};
|
||||
entry.inputTokens += usage.input_tokens ?? 0;
|
||||
entry.outputTokens += usage.output_tokens ?? 0;
|
||||
entry.cacheReadInputTokens += usage.cache_read_input_tokens ?? 0;
|
||||
entry.cacheCreationInputTokens += usage.cache_creation_input_tokens ?? 0;
|
||||
entry.webSearchRequests += usage.server_tool_use?.web_search_requests ?? 0;
|
||||
entry.costUSD += cost;
|
||||
entry.contextWindow = getContextWindow(model);
|
||||
FQ.modelUsage[model] = entry;
|
||||
}
|
||||
|
||||
// Cost calculation:
|
||||
function calculateCost(usage, pricing) {
|
||||
return (usage.input_tokens / 1e6 * pricing.inputTokens) +
|
||||
(usage.output_tokens / 1e6 * pricing.outputTokens) +
|
||||
((usage.cache_read_input_tokens ?? 0) / 1e6 * pricing.promptCacheReadTokens) +
|
||||
((usage.cache_creation_input_tokens ?? 0) / 1e6 * pricing.promptCacheWriteTokens) +
|
||||
((usage.server_tool_use?.web_search_requests ?? 0) * pricing.webSearchRequests);
|
||||
}
|
||||
```
|
||||
|
||||
## Tool Use JSON Accumulation
|
||||
|
||||
```javascript
|
||||
// Tool use input arrives as incremental JSON chunks via input_json_delta
|
||||
// The handler accumulates partial JSON:
|
||||
|
||||
let toolUseId = null;
|
||||
let jsonBuffer = "";
|
||||
|
||||
for await (let event of stream) {
|
||||
if (event.type === "content_block_start" && event.content_block.type === "tool_use") {
|
||||
toolUseId = event.content_block.id;
|
||||
jsonBuffer = "";
|
||||
}
|
||||
|
||||
if (toolUseId && event.type === "content_block_delta") {
|
||||
let delta = event.delta;
|
||||
if (delta?.type === "input_json_delta" && delta.partial_json) {
|
||||
jsonBuffer += delta.partial_json;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type === "content_block_stop" && toolUseId) {
|
||||
let toolInput = JSON.parse(jsonBuffer);
|
||||
// Process complete tool call
|
||||
toolUseId = null;
|
||||
jsonBuffer = "";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```javascript
|
||||
// API errors during streaming:
|
||||
// - tengu_streaming_error: content_block_delta for unknown index
|
||||
// - Retry logic for transient failures
|
||||
// - Fallback to non-streaming mode (didFallBackToNonStreaming telemetry)
|
||||
|
||||
// Stop reasons:
|
||||
const STOP_REASONS = {
|
||||
END_TURN: "end_turn",
|
||||
GUARDRAIL_INTERVENED: "guardrail_intervened",
|
||||
MAX_TOKENS: "max_tokens",
|
||||
STOP_SEQUENCE: "stop_sequence",
|
||||
TOOL_USE: "tool_use"
|
||||
};
|
||||
```
|
||||
209
docs/research/claude-code-rvsource/extracted/tool-dispatch.rvf
Normal file
209
docs/research/claude-code-rvsource/extracted/tool-dispatch.rvf
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
---
|
||||
type: source-extraction
|
||||
module: tool-dispatch
|
||||
binary: claude-code
|
||||
version: 2.0.62
|
||||
extraction-method: strings+pattern-match
|
||||
confidence: high
|
||||
---
|
||||
|
||||
# Tool Dispatch System
|
||||
|
||||
## Tool Registry (XF0 class)
|
||||
|
||||
```javascript
|
||||
class XF0 { // ToolRegistry
|
||||
toolDefinitions; // Tool[]
|
||||
canUseTool; // PermissionChecker
|
||||
tools = []; // Tool[] (active subset)
|
||||
toolUseContext; // ToolUseContext
|
||||
hasErrored = false;
|
||||
progressAvailableResolve;
|
||||
|
||||
constructor(tools, canUseTool, context) {
|
||||
this.toolDefinitions = tools;
|
||||
this.canUseTool = canUseTool;
|
||||
this.toolUseContext = context;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tool Interface (reconstructed from implementations)
|
||||
|
||||
```typescript
|
||||
interface Tool {
|
||||
name: string;
|
||||
type: string;
|
||||
userFacingName(): string;
|
||||
isEnabled(): boolean;
|
||||
inputSchema: ZodSchema;
|
||||
outputSchema?: ZodSchema;
|
||||
prompt?(context: {getToolPermissionContext, tools, agents}): Promise<string>;
|
||||
validateInput(input, context: ToolContext): Promise<{result: boolean; message?: string; meta?: any}>;
|
||||
call(input, context: ToolContext, canUseTool, message): Promise<ToolResult>;
|
||||
getPath?(input): string;
|
||||
renderToolUseMessage?(input, context): ReactElement;
|
||||
renderToolResultMessage?(result, context): ReactElement;
|
||||
renderToolUseErrorMessage?(error, context): ReactElement;
|
||||
mapToolResultToToolResultBlockParam(result, toolUseId): ToolResultBlock;
|
||||
}
|
||||
```
|
||||
|
||||
## ToolContext (reconstructed from call sites)
|
||||
|
||||
```typescript
|
||||
interface ToolContext {
|
||||
abortController: AbortController;
|
||||
options: {
|
||||
commands: Command[];
|
||||
tools: Tool[];
|
||||
mainLoopModel: string;
|
||||
maxThinkingTokens: number;
|
||||
mcpClients: McpClient[];
|
||||
mcpResources: Record<string, Resource[]>;
|
||||
isNonInteractiveSession: boolean;
|
||||
hasAppendSystemPrompt: boolean;
|
||||
debug: boolean;
|
||||
verbose: boolean;
|
||||
agentDefinitions: { activeAgents: AgentDef[]; allAgents: AgentDef[] };
|
||||
theme: Theme;
|
||||
maxBudgetUsd?: number;
|
||||
sdkBetas?: string[];
|
||||
ideInstallationStatus?: any;
|
||||
dynamicMcpConfig?: any;
|
||||
};
|
||||
getAppState(): Promise<AppState>;
|
||||
setAppState(updater): void;
|
||||
messages: Message[];
|
||||
setMessages(updater): void;
|
||||
readFileState: LRUCache; // new eS({max: 1000})
|
||||
setInProgressToolUseIDs(updater): void;
|
||||
setResponseLength(updater): void;
|
||||
updateFileHistoryState(updater): void;
|
||||
agentId: string;
|
||||
onChangeAPIKey?: Function;
|
||||
openMessageSelector?: Function;
|
||||
addNotification?: Function;
|
||||
setToolJSX?: Function;
|
||||
setStreamMode?: Function;
|
||||
setSpinnerMessage?: Function;
|
||||
setSpinnerColor?: Function;
|
||||
resume?: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Built-in Tool Definitions (from string literals and code patterns)
|
||||
|
||||
### BashTool
|
||||
```javascript
|
||||
{
|
||||
name: "Bash",
|
||||
// Validates: command string, timeout, description, run_in_background, dangerouslyDisableSandbox
|
||||
// Execution: child_process with sandbox wrapping
|
||||
// Sandbox: macOS seatbelt or Linux SOCKS bridge
|
||||
// Special handling for: sandbox violations tracking, command path extraction
|
||||
}
|
||||
```
|
||||
|
||||
### FileReadTool (I6)
|
||||
```javascript
|
||||
{
|
||||
name: "Read", // userFacingName
|
||||
// validateInput: checks path permissions via tD(), file existence
|
||||
// call: reads file with offset/limit, returns content with line numbers
|
||||
// Special: compact mode returns {type: "compact_file_reference", filename}
|
||||
// LRU cache for read state: new eS({max: 1000})
|
||||
}
|
||||
```
|
||||
|
||||
### FileEditTool
|
||||
```javascript
|
||||
{
|
||||
name: "Edit", // userFacingName
|
||||
// validateInput: checks path permissions for "edit" action
|
||||
// Validates: old_string !== new_string, file_path is absolute
|
||||
// call: string replacement with optional replace_all
|
||||
}
|
||||
```
|
||||
|
||||
### FileWriteTool
|
||||
```javascript
|
||||
{
|
||||
name: "Write", // userFacingName
|
||||
// validateInput: checks path permissions for "write" action
|
||||
// Rejects glob patterns in path
|
||||
// call: writes content to file
|
||||
}
|
||||
```
|
||||
|
||||
### Agent Tool (sub-agent spawner)
|
||||
```javascript
|
||||
{
|
||||
name: "Agent",
|
||||
// Creates sub-agent with own s$() loop
|
||||
// Parameters: description, prompt, subagent_type, model, resume, run_in_background
|
||||
// Models: "sonnet" | "opus" | "haiku" | "inherit"
|
||||
// Permission modes: defined per agent or inherited
|
||||
// Spawns via mVA() async generator
|
||||
}
|
||||
```
|
||||
|
||||
## MCP Tool Dispatch
|
||||
|
||||
```javascript
|
||||
// MCP tool name format: "mcp__<serverName>__<toolName>"
|
||||
// Parsing:
|
||||
function parseMcpToolName(fullName) {
|
||||
let prefix = `mcp__${normalizeServerName(serverName)}__`;
|
||||
let toolName = fullName.replace(prefix, "");
|
||||
return { serverName, toolName };
|
||||
}
|
||||
|
||||
// MCP tool execution flow:
|
||||
// 1. Parse tool name to extract server and tool
|
||||
// 2. Find MCP client for server
|
||||
// 3. Send tools/call JSON-RPC message
|
||||
// 4. Await response with timeout (k91() / MCP_TIMEOUT env)
|
||||
// 5. Return result as tool_result content block
|
||||
```
|
||||
|
||||
## Tool Result Mapping
|
||||
|
||||
```javascript
|
||||
// Each tool maps its result to the API format:
|
||||
mapToolResultToToolResultBlockParam(result, toolUseId) {
|
||||
return {
|
||||
tool_use_id: toolUseId,
|
||||
type: "tool_result",
|
||||
content: result, // string or content block array
|
||||
is_error: false
|
||||
};
|
||||
}
|
||||
|
||||
// Error results:
|
||||
{
|
||||
tool_use_id: id,
|
||||
type: "tool_result",
|
||||
content: `Error: Tool '${name}' not found`,
|
||||
is_error: true
|
||||
}
|
||||
```
|
||||
|
||||
## Slash Commands (not tools, but command handlers)
|
||||
|
||||
```javascript
|
||||
// 40+ slash commands with format:
|
||||
{
|
||||
name: "command-name",
|
||||
description: "What it does",
|
||||
// handler returns:
|
||||
{
|
||||
data: { success: boolean, commandName: string },
|
||||
newMessages: Message[],
|
||||
contextModifier(toolUseContext) {
|
||||
// Can modify: alwaysAllowRules, mainLoopModel, maxThinkingTokens
|
||||
return modifiedContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
32
docs/research/claude-code-rvsource/versions/README.md
Normal file
32
docs/research/claude-code-rvsource/versions/README.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Claude Code RVF Corpus
|
||||
|
||||
Binary RVF containers for every major Claude Code CLI release, with
|
||||
HNSW-indexed vector embeddings and witness chains for provenance.
|
||||
|
||||
## Versions
|
||||
|
||||
| Series | Version | Bundle | RVF Size | Vectors | File ID |
|
||||
|--------|---------|--------|----------|---------|---------|
|
||||
| 0.2 | 0.2.126 | 6.9MB | 159.0KB | 300 | `679f4bde2ea7...` |
|
||||
| 1.0 | 1.0.128 | 8.9MB | 251.4KB | 482 | `689f54de1ca7...` |
|
||||
| 2.0 | 2.0.77 | 10.5MB | 405.3KB | 785 | `6c9f5dde1ca7...` |
|
||||
| 2.1 | 2.1.91 | 12.6MB | 1056.8KB | 2068 | `6d9f5dde25a7...` |
|
||||
|
||||
## How to Use
|
||||
|
||||
```bash
|
||||
# Build the corpus
|
||||
./scripts/claude-code-rvf-corpus.sh
|
||||
|
||||
# Build only specific series
|
||||
./scripts/claude-code-rvf-corpus.sh --series 2.0,2.1
|
||||
```
|
||||
|
||||
## Format
|
||||
|
||||
Each version directory contains:
|
||||
- A binary `.rvf` container (128-dim cosine-distance HNSW index)
|
||||
- A `.manifest.json` sidecar with vector-to-fragment mapping
|
||||
- Extracted JavaScript modules in `source/`
|
||||
|
||||
Generated by `scripts/claude-code-rvf-corpus.sh` using `@ruvector/rvf-node`.
|
||||
42
docs/research/claude-code-rvsource/versions/v0.2.x/README.md
Normal file
42
docs/research/claude-code-rvsource/versions/v0.2.x/README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Claude Code v0.2.126 (0.2 series)
|
||||
|
||||
## Binary RVF Container
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Version | 0.2.126 |
|
||||
| Series | 0.2 |
|
||||
| Bundle size | 6.9MB |
|
||||
| RVF size | 159.0KB |
|
||||
| Vectors | 300 |
|
||||
| RVF File ID | `679f4bde2ea78a28eaddf8bc08d25018` |
|
||||
| Classes | 1049 |
|
||||
| Functions | 13869 |
|
||||
| Modules | 9 |
|
||||
| Extracted | 2026-04-02T23:28:42+00:00 |
|
||||
|
||||
## Files
|
||||
|
||||
- `claude-code-v0.2.rvf` - Binary RVF container with HNSW index + witness chain
|
||||
- `claude-code-v0.2.rvf.manifest.json` - Container manifest (vector ID map, metadata)
|
||||
- `source/` - Extracted JavaScript module fragments
|
||||
|
||||
## RVF Container Details
|
||||
|
||||
The `.rvf` file is a real binary container created with the `@ruvector/rvf-node`
|
||||
native backend. It contains:
|
||||
|
||||
- **128-dimensional fingerprint vectors** for each code fragment
|
||||
- **HNSW index** (M=16, ef_construction=200) for fast similarity search
|
||||
- **Cosine distance** metric
|
||||
- **Witness chain** for provenance verification
|
||||
|
||||
To query this container:
|
||||
|
||||
```typescript
|
||||
import { RvfDatabase } from '@ruvector/rvf';
|
||||
|
||||
const db = await RvfDatabase.openReadonly('./claude-code-v0.2.rvf');
|
||||
const results = await db.query(queryVector, 10);
|
||||
await db.close();
|
||||
```
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,719 @@
|
|||
class Me1 extends Error
|
||||
class lK
|
||||
class SAA
|
||||
class Ey
|
||||
class ju
|
||||
class p0A
|
||||
class kw1
|
||||
class n0A extends i0A
|
||||
class xw1 extends Kv2
|
||||
class s0A extends Hv2
|
||||
class G2A
|
||||
class w2A
|
||||
class iw1
|
||||
class nw1
|
||||
class aw1
|
||||
class sw1
|
||||
class R2A
|
||||
class S2A extends Og2
|
||||
class g9A
|
||||
class rA1
|
||||
class oA1
|
||||
class tA1
|
||||
class eA1
|
||||
class A01
|
||||
class B01
|
||||
class I01
|
||||
class A5A
|
||||
class q5A
|
||||
class O5A extends R5A
|
||||
class yE1 extends on2
|
||||
class JT
|
||||
class L8A
|
||||
class sZ
|
||||
class as
|
||||
class Dp
|
||||
class DzA
|
||||
class ZzA
|
||||
class WzA
|
||||
class jq1
|
||||
class zzA
|
||||
class xq1
|
||||
class wzA extends xq1
|
||||
class I
|
||||
class G
|
||||
class const
|
||||
class interface
|
||||
class constant
|
||||
class struct
|
||||
class ahk_pid
|
||||
class instance
|
||||
class type
|
||||
class reduce
|
||||
class classmethod
|
||||
class def
|
||||
class module
|
||||
class safecall
|
||||
class case
|
||||
class associate
|
||||
class default
|
||||
class double
|
||||
class family
|
||||
class defmacro
|
||||
class iter
|
||||
class object
|
||||
class extends
|
||||
class instancetype
|
||||
class constraint
|
||||
class concat
|
||||
class clone
|
||||
class compile_error
|
||||
class enum
|
||||
class auth_type
|
||||
class Conj
|
||||
class untracemem
|
||||
class define
|
||||
class exit
|
||||
class cleanup
|
||||
class classutil
|
||||
class extension
|
||||
class compare
|
||||
class namespace
|
||||
class clocking
|
||||
class endclocking
|
||||
class iT
|
||||
class HSA
|
||||
class sT
|
||||
class dSA
|
||||
class uSA
|
||||
class tSA
|
||||
class C_A
|
||||
class x_A
|
||||
class m_A
|
||||
class DjA
|
||||
class VjA extends T61
|
||||
class EjA extends tT
|
||||
class _61 extends B6
|
||||
class A
|
||||
class YxA extends Xc9
|
||||
class XxA extends zc9
|
||||
class qxA
|
||||
class dxA extends bc9
|
||||
class A extends Uint8Array
|
||||
class did
|
||||
class A extends Error
|
||||
class A extends n51
|
||||
class DmA
|
||||
class VmA
|
||||
class EmA
|
||||
class A extends mH
|
||||
class A extends _2
|
||||
class A extends uf
|
||||
class A extends dZ4
|
||||
class A extends bW
|
||||
class beA extends veA
|
||||
class A extends yW4
|
||||
class A extends HU
|
||||
class Q extends A
|
||||
class A extends _
|
||||
class A extends iX
|
||||
class j50
|
||||
class v50
|
||||
class p50 extends dN4
|
||||
class hM
|
||||
class mM
|
||||
class xv extends mM
|
||||
class hi extends mM
|
||||
class TQ1 extends mM
|
||||
class w4 extends Z
|
||||
class L80 extends g
|
||||
class my1
|
||||
class DV
|
||||
class BG0
|
||||
class pn
|
||||
class KI1
|
||||
class A extends iA
|
||||
class A extends rW
|
||||
class A extends mz0
|
||||
class A extends Pa
|
||||
class A extends g1
|
||||
class A extends EY
|
||||
class eb
|
||||
class rJ
|
||||
class sJ
|
||||
class sb1 extends Error
|
||||
class UL0 extends Set
|
||||
class PL0 extends RL0
|
||||
class tb1 extends w16
|
||||
class eb1
|
||||
class r4
|
||||
class xZ1 extends t16
|
||||
class aa
|
||||
class Gg1 extends aa
|
||||
class wR0 extends aa
|
||||
class ER0 extends aa
|
||||
class vZ1
|
||||
class SR0
|
||||
class oa
|
||||
class oR0
|
||||
class AO0 extends A06
|
||||
class GO0
|
||||
class YZ extends D06
|
||||
class CO0 extends C06
|
||||
class KO0 extends X06
|
||||
class Vg extends Error
|
||||
class IT0
|
||||
class fg1
|
||||
class bg1 extends H26
|
||||
class nZ1 extends z26
|
||||
class Gs extends VT0
|
||||
class wT0
|
||||
class ug1 extends NT0
|
||||
class aZ1 extends _26
|
||||
class OT0
|
||||
class _T0
|
||||
class eg1 extends u26
|
||||
class gT0
|
||||
class pT0
|
||||
class Zs extends r26
|
||||
class nT0
|
||||
class oU extends Error
|
||||
class Yh1 extends oU
|
||||
class Wh1 extends oU
|
||||
class aT0 extends oU
|
||||
class Fh1 extends oU
|
||||
class Jh1 extends oU
|
||||
class Ch1 extends oU
|
||||
class tZ1 extends oU
|
||||
class Kh1
|
||||
class Hh1 extends Error
|
||||
class IP0 extends W96
|
||||
class ZP0
|
||||
class wh1 extends FP0
|
||||
class JP0 extends E96
|
||||
class Nh1
|
||||
class NP0
|
||||
class LP0 extends k96
|
||||
class qh1 extends h96
|
||||
class O3 extends Error
|
||||
class mP0 extends O3
|
||||
class dP0 extends O3
|
||||
class uP0 extends O3
|
||||
class pP0 extends O3
|
||||
class cP0 extends O3
|
||||
class lP0 extends O3
|
||||
class iP0 extends O3
|
||||
class Lh1 extends O3
|
||||
class nP0 extends Lh1
|
||||
class aP0 extends O3
|
||||
class sP0 extends O3
|
||||
class rP0 extends O3
|
||||
class oP0 extends O3
|
||||
class tP0 extends O3
|
||||
class eP0 extends O3
|
||||
class AS0 extends O3
|
||||
class BS0 extends O3
|
||||
class QS0 extends Error
|
||||
class IS0 extends O3
|
||||
class GS0 extends O3
|
||||
class DS0 extends O3
|
||||
class ZS0 extends O3
|
||||
class Oh1
|
||||
class Ph1
|
||||
class xS0
|
||||
class yh1 extends H66
|
||||
class bS0 extends yh1
|
||||
class hS0 extends z66
|
||||
class dh1
|
||||
class a_0 extends N56
|
||||
class r_0
|
||||
class o_0
|
||||
class _z
|
||||
class jz
|
||||
class Sj0
|
||||
class zm1
|
||||
class uj0
|
||||
class tj0 extends J36
|
||||
class Om1
|
||||
class Iy0
|
||||
class Hy0 extends c36
|
||||
class Oy0 extends FQ6
|
||||
class fy0
|
||||
class my0 extends xQ6
|
||||
class iy0 extends uQ6
|
||||
class mm1
|
||||
class ey0 extends oQ6
|
||||
class Jk0 extends eQ6
|
||||
class nm1 extends X76
|
||||
class Lk0
|
||||
class _k0 extends Sk0
|
||||
class jk0 extends Sk0
|
||||
class yk0 extends O76
|
||||
class gk0 extends j76
|
||||
class ck0 extends x76
|
||||
class tm1 extends p76
|
||||
class ls
|
||||
class Wx0
|
||||
class Hx0 extends FI6
|
||||
class Mx0 extends HI6
|
||||
class jx0 extends kI6
|
||||
class px0 extends pI6
|
||||
class nx0
|
||||
class ax0 extends nI6
|
||||
class IW1
|
||||
class WD
|
||||
class FD
|
||||
class zf0
|
||||
class wf0
|
||||
class P8
|
||||
class jd1 extends ND6
|
||||
class os extends Event
|
||||
class i5 extends EventTarget
|
||||
class mz
|
||||
class pL
|
||||
class JF extends Event
|
||||
class Zh extends Event
|
||||
class cL extends Event
|
||||
class nv0
|
||||
class Qb0
|
||||
class Kb0
|
||||
class Nb0
|
||||
class v5 extends EventTarget
|
||||
class fb0 extends eY6
|
||||
class Xh extends EventTarget
|
||||
class eb0
|
||||
class l8
|
||||
class Jg0
|
||||
class yV
|
||||
class ed1
|
||||
class zg0 extends WF6
|
||||
class Ug0 extends Eg0
|
||||
class Rg0 extends Iu1
|
||||
class Pg0 extends KF6
|
||||
class _g0 extends HF6
|
||||
class kg0 extends EF6
|
||||
class bg0
|
||||
class Yh0
|
||||
class Lr
|
||||
class eL
|
||||
class oh0
|
||||
class lu0
|
||||
class Zp1
|
||||
class gh
|
||||
class hF1
|
||||
class Xp0
|
||||
class Fp1
|
||||
class hh
|
||||
class Jp1 extends hh
|
||||
class Cp1 extends hh
|
||||
class Xp1 extends hh
|
||||
class Vp1 extends hh
|
||||
class ir
|
||||
class Kp1 extends ir
|
||||
class Hp1 extends ir
|
||||
class zp1 extends ir
|
||||
class _p0
|
||||
class qp1
|
||||
class up0
|
||||
class Ac0
|
||||
class Ic0
|
||||
class Zc0
|
||||
class Jc0
|
||||
class bp1
|
||||
class gp1
|
||||
class dp1
|
||||
class ac0
|
||||
class lp1
|
||||
class ap1
|
||||
class lF1 extends Error
|
||||
class yl0
|
||||
class sr
|
||||
class vl0
|
||||
class Ac1
|
||||
class Bc1
|
||||
class nl0 extends Error
|
||||
class ol0
|
||||
class Ii0
|
||||
class ch
|
||||
class aF1
|
||||
class Ki0
|
||||
class Ri0
|
||||
class Si0
|
||||
class YA2
|
||||
class Ec1
|
||||
class IJ1 extends Error
|
||||
class rA2
|
||||
class A02
|
||||
class Qo
|
||||
class w02
|
||||
class C_
|
||||
class ZJ1
|
||||
class Io
|
||||
class YJ1
|
||||
class WJ1
|
||||
class Mc1
|
||||
class Lc1
|
||||
class Rc1
|
||||
class c02
|
||||
class a02 extends Vx6
|
||||
class e02
|
||||
class Sc1
|
||||
class Zo
|
||||
class N22
|
||||
class a22
|
||||
class A92
|
||||
class G92
|
||||
class W92
|
||||
class dc1
|
||||
class E92
|
||||
class sh
|
||||
class O92 extends sh
|
||||
class T92 extends sh
|
||||
class P92 extends sh
|
||||
class S92 extends sh
|
||||
class rh
|
||||
class _92 extends rh
|
||||
class j92 extends rh
|
||||
class y92 extends rh
|
||||
class f92
|
||||
class h92
|
||||
class lc1
|
||||
class u92 extends lc1
|
||||
class l92
|
||||
class Jo
|
||||
class r92 extends if6
|
||||
class sc1
|
||||
class C42
|
||||
class z42
|
||||
class w42
|
||||
class M42
|
||||
class T42 extends Yv6
|
||||
class j42
|
||||
class y42
|
||||
class k42
|
||||
class x42
|
||||
class b42
|
||||
class d42
|
||||
class l42
|
||||
class rc1
|
||||
class s42
|
||||
class e42
|
||||
class I62
|
||||
class F62
|
||||
class V62
|
||||
class N62
|
||||
class L62 extends Error
|
||||
class y62
|
||||
class h62
|
||||
class n62 extends qb6
|
||||
class IB2
|
||||
class WB2
|
||||
class fB2 extends eh6
|
||||
class lB2 extends Jm6
|
||||
class hJ1
|
||||
class Bm
|
||||
class mJ1 extends Bm
|
||||
class rl1 extends Bm
|
||||
class ol1 extends Bm
|
||||
class Im
|
||||
class Gi1 extends Im
|
||||
class U32
|
||||
class pJ1 extends Im
|
||||
class Uo extends Im
|
||||
class cJ1 extends Im
|
||||
class _32
|
||||
class j32
|
||||
class sJ1
|
||||
class v32
|
||||
class m32
|
||||
class r32
|
||||
class Yi1
|
||||
class e32 extends Yi1
|
||||
class AQ2
|
||||
class BQ2
|
||||
class QQ2 extends BQ2
|
||||
class IQ2 extends QQ2
|
||||
class GQ2 extends AQ2
|
||||
class hV extends GQ2
|
||||
class DQ2 extends IQ2
|
||||
class JQ2 extends lu6
|
||||
class CQ2 extends Wi1
|
||||
class XQ2 extends Wi1
|
||||
class VQ2 extends Wi1
|
||||
class wQ2
|
||||
class So extends Error
|
||||
class LQ2
|
||||
class RQ2
|
||||
class OQ2
|
||||
class Ji1
|
||||
class TQ2 extends Ji1
|
||||
class PQ2 extends Ji1
|
||||
class jQ2
|
||||
class I extends _o
|
||||
class dI2
|
||||
class uI2
|
||||
class Yn1
|
||||
class pI2 extends Yn1
|
||||
class Wn1
|
||||
class cI2 extends Wn1
|
||||
class tI2
|
||||
class WG2
|
||||
class HG2
|
||||
class EG2
|
||||
class MG2
|
||||
class LG2
|
||||
class kC1
|
||||
class qn1
|
||||
class vG2
|
||||
class ao
|
||||
class dG2 extends ao
|
||||
class uG2 extends ao
|
||||
class pG2 extends ao
|
||||
class On1 extends xn6
|
||||
class cG2
|
||||
class tG2
|
||||
class ID2
|
||||
class YD2
|
||||
class WD2
|
||||
class FD2
|
||||
class VD2
|
||||
class wD2 extends Ra6
|
||||
class ED2
|
||||
class UD2
|
||||
class ND2
|
||||
class LD2
|
||||
class PD2 extends ka6
|
||||
class SD2 extends kn1
|
||||
class _D2 extends kn1
|
||||
class jD2 extends kn1
|
||||
class qm
|
||||
class bn1 extends qm
|
||||
class gn1 extends qm
|
||||
class hn1 extends qm
|
||||
class mn1 extends qm
|
||||
class cD2
|
||||
class lD2
|
||||
class iD2
|
||||
class nD2
|
||||
class cn1
|
||||
class GZ2
|
||||
class Tm
|
||||
class XZ2
|
||||
class iC1
|
||||
class HZ2
|
||||
class EZ2
|
||||
class TZ2
|
||||
class Ia1
|
||||
class Da1
|
||||
class hZ2
|
||||
class Za1
|
||||
class Bt
|
||||
class lZ2 extends Vr6
|
||||
class iZ2
|
||||
class nZ2
|
||||
class Xa1
|
||||
class za1
|
||||
class yY2 extends ho6
|
||||
class hY2
|
||||
class kR extends Ma1
|
||||
class B
|
||||
class F extends G
|
||||
class Q extends B
|
||||
class I extends Q
|
||||
class I extends B
|
||||
class G extends Q
|
||||
class F extends Y
|
||||
class T
|
||||
class Q
|
||||
class q
|
||||
class W extends G
|
||||
class n
|
||||
class D extends I
|
||||
class A extends Array
|
||||
class Se
|
||||
class CK1
|
||||
class XK1
|
||||
class At1 extends Array
|
||||
class ut1 extends Error
|
||||
class lN2 extends ut1
|
||||
class iN2
|
||||
class nN2
|
||||
class aN2
|
||||
class sN2
|
||||
class at1 extends w75
|
||||
class cI
|
||||
class VJ
|
||||
class Mp extends Array
|
||||
class Hk
|
||||
class Lp
|
||||
class hU1
|
||||
class SDA extends hU1
|
||||
class LT extends gU1
|
||||
class pU1 extends Lp
|
||||
class dDA extends Lp
|
||||
class iD
|
||||
class a21 extends iD
|
||||
class s21 extends iD
|
||||
class cU1
|
||||
class kp extends cU1
|
||||
class xp extends cU1
|
||||
class r21 extends xp
|
||||
class Ek
|
||||
class fp
|
||||
class lU1
|
||||
class cDA
|
||||
class lDA
|
||||
class vp
|
||||
class iU1
|
||||
class o21 extends iU1
|
||||
class t21 extends iU1
|
||||
class zH
|
||||
class jW extends Error
|
||||
class cG
|
||||
class OX
|
||||
class v4
|
||||
class LX extends v4
|
||||
class xq extends v4
|
||||
class fq extends v4
|
||||
class Mx extends v4
|
||||
class fT extends v4
|
||||
class Hc extends v4
|
||||
class Lx extends v4
|
||||
class Rx extends v4
|
||||
class vT extends v4
|
||||
class kq extends v4
|
||||
class MH extends v4
|
||||
class zc extends v4
|
||||
class RX extends v4
|
||||
class sB extends v4
|
||||
class Ox extends v4
|
||||
class w41 extends v4
|
||||
class Tx extends v4
|
||||
class LH extends v4
|
||||
class wc extends v4
|
||||
class Ec extends v4
|
||||
class bT extends v4
|
||||
class Px extends v4
|
||||
class Sx extends v4
|
||||
class vq extends v4
|
||||
class _x extends v4
|
||||
class gT extends v4
|
||||
class yW extends v4
|
||||
class rE extends v4
|
||||
class jx extends v4
|
||||
class yx extends v4
|
||||
class Uc extends v4
|
||||
class E41 extends v4
|
||||
class Nc extends v4
|
||||
class kx extends v4
|
||||
class DRA
|
||||
class sTA
|
||||
class kc
|
||||
class CPA
|
||||
class VPA
|
||||
class HPA extends Sv9
|
||||
class pc
|
||||
class yL1
|
||||
class UR1
|
||||
class M40
|
||||
class Nj1 extends TypeError
|
||||
class dQ extends Error
|
||||
class qv extends Error
|
||||
class yP extends Error
|
||||
class Q60
|
||||
class bj1
|
||||
class I60 extends bj1
|
||||
class G60 extends bj1
|
||||
class ci
|
||||
class tQ1 extends MU
|
||||
class eQ1
|
||||
class ti extends Map
|
||||
class F71 extends Map
|
||||
class WQ
|
||||
class X71
|
||||
class i30
|
||||
class PNGf
|
||||
class furl
|
||||
class q9 extends Error
|
||||
class K5 extends q9
|
||||
class BI extends K5
|
||||
class SU extends K5
|
||||
class Yn extends SU
|
||||
class Wn extends K5
|
||||
class Fn extends K5
|
||||
class Jn extends K5
|
||||
class Cn extends K5
|
||||
class Xn extends K5
|
||||
class Vn extends K5
|
||||
class Kn extends K5
|
||||
class Hn extends K5
|
||||
class sM
|
||||
class AZ
|
||||
class dQ0
|
||||
class tP extends Promise
|
||||
class uQ0
|
||||
class j71 extends tP
|
||||
class jU extends uQ0
|
||||
class GG
|
||||
class Nn extends GG
|
||||
class rv
|
||||
class Tn
|
||||
class ev extends GG
|
||||
class dJ extends GG
|
||||
class oM extends GG
|
||||
class Pn extends GG
|
||||
class Bb
|
||||
class tX extends GG
|
||||
class Qb extends GG
|
||||
class G8
|
||||
class Dz extends G8
|
||||
class Jb extends Error
|
||||
class Qa
|
||||
class Ex1 extends Qa
|
||||
class Ia
|
||||
class Px1
|
||||
class _x1 extends Error
|
||||
class jx1 extends Event
|
||||
class Eb extends EventTarget
|
||||
class ZS extends Error
|
||||
class LZ0 extends Error
|
||||
class cI1
|
||||
class sx1
|
||||
class wZ1 extends AZ
|
||||
class EZ1 extends G8
|
||||
class QY1 extends G8
|
||||
class Vr extends Error
|
||||
class SV
|
||||
class La1
|
||||
class h_ extends Error
|
||||
class YF2
|
||||
class ym
|
||||
class jt
|
||||
class mY
|
||||
class yt
|
||||
class jX1
|
||||
class SC
|
||||
class _t
|
||||
class nF2
|
||||
class definition
|
||||
class Foo
|
||||
class Aw2
|
||||
class GK1
|
||||
class vo1
|
||||
class pN
|
||||
class Iw2 extends pN
|
||||
class Gw2 extends pN
|
||||
class Dw2 extends pN
|
||||
class Zw2 extends pN
|
||||
class Yw2 extends pN
|
||||
class Ww2 extends pN
|
||||
class bo1 extends pN
|
||||
class go1 extends pN
|
||||
class Fw2
|
||||
class Sw
|
||||
class Dt1
|
||||
class Jt1
|
||||
class wt1
|
||||
class vt1 extends GN2
|
||||
class et1 extends Qa
|
||||
class Ae1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
name:"sharp",description:"High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images"
|
||||
name:"clear",description:"Clear conversation history and free up context"
|
||||
name:"compact",description:"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]"
|
||||
name:"config",description:"Open config panel"
|
||||
name:"cost",description:"Show the total cost and duration of the current session"
|
||||
name:"doctor",description:"Checks the health of your Claude Code installation"
|
||||
name:"memory",description:"Edit Claude memory files"
|
||||
name:"help",description:"Show help and available commands"
|
||||
name:"ide",description:"Manage IDE integrations and show status"
|
||||
name:"init",description:"Initialize a new CLAUDE.md file with codebase documentation"
|
||||
name:"logout",description:"Sign out from your Anthropic account"
|
||||
name:"install-github-app",description:"Set up Claude GitHub Actions for a repository"
|
||||
name:"migrate-installer",description:"Migrate from global npm installation to local installation"
|
||||
name:"mcp",description:"Show MCP server connection status"
|
||||
name:"pr-comments",description:"Get comments from a GitHub pull request"
|
||||
name:"review",description:"Review a pull request"
|
||||
name:"status",description:"Show Claude Code status including version, model, account, and tool statuses"
|
||||
name:"tasks",description:"List and manage background tasks"
|
||||
name:"vim",description:"Toggle between Vim and Normal editing modes"
|
||||
name:"allowed-tools",description:"List all currently allowed tools"
|
||||
name:"files",description:"List all files currently in context"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
if(I&&typeof I==="object"&&"isNewTopic"in I&&"title"in I){if(I.isNewTopic&&I.title)mo1(I.title)}}catch(B){m1(B)}}function MQ(){return new Promise((A)=>{process.stdout.write("\x1B[2J\x1B[3J\x1B[H",()=>{A()})})}async function ww2({setMessages:A,readFileState:B}){await MQ(),A([]),dY.cache.clear?.(),EZ.cache.clear?.(),hW(p4()),Object.keys(B).forEach((Q)=>{delete B[Q]})}var s85={type:"local",name:"clear",description:"Clear conversation history and free up context",isEnabled:!0,isHidden:!1,async call(A,B){return ww2(B),""},userFacingName(){return"clear"}},Ew2=s85;var r85={type:"local",name:"compact",description:"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]",isEnabled:!0,isHidden:!1,argumentHint:"<optional custom summarization instructions>",async call(A,B){let{abortController:Q,messages:I}=B;if(I.length===0)throw new Error("No messages to compact");let G=A.trim();try{return await qX1(I,B,!1,G),dY.cache.clear?.(),EZ.cache.clear?.(),""}catch(D){if(Q.signal.aborted)throw new Error("Compaction canceled.");else if(D instanceof Error&&D.message===Et)throw new Error(Et);else throw m1(D instanceof Error?D:new Error(String(D))),new Error(`Error during compaction: ${D}`)}},userFacingName(){return"compact"}},Uw2=r85;var x9=J1(_1(),1),Oe=J1(_1(),1);var $4=J1(_1(),1);var Nw2=J1(_1(),1)
|
||||
|
||||
P0(S),I(S),S1("tengu_auto_compact_setting_changed",{enabled:O})}},{id:"todoFeatureEnabled",label:"Use todo list",value:F,type:"boolean",onChange:M},{id:"verbose",label:"Verbose output",value:J,type:"boolean",onChange:q},{id:"theme",label:"Theme",value:Q.theme,type:"managedEnum",onChange(O){let S={...XA(),theme:O};P0(S),I(S)}},{id:"notifChannel",label:"Notifications",value:Q.preferredNotifChannel,options:["auto","iterm2","terminal_bell","iterm2_with_bell","kitty","notifications_disabled"],type:"enum",onChange(O){let S={...XA(),preferredNotifChannel:O};P0(S),I(S)}},{id:"editorMode",label:"Editor mode",value:Q.editorMode==="emacs"?"normal":Q.editorMode||"normal",options:["normal","vim"],type:"enum",onChange(O){let S={...XA(),editorMode:O};P0(S),I(S),S1("tengu_editor_mode_changed",{mode:O,source:"config_panel"})}},...process.env.ENABLE_IDE_INTEGRATION==="true"&&B?[{id:"diffTool",label:"Diff tool",value:Q.diffTool,options:["terminal","auto"],type:"enum",onChange(O){let S={...XA(),diffTool:O};P0(S),I(S),S1("tengu_diff_tool_changed",{tool:O,source:"config_panel"})}}]:[],...[],...N?[{id:"showExternalIncludesDialog",label:"External CLAUDE.md includes",value:(()=>{if(w9().hasClaudeMdExternalIncludesApproved)return"true";else return"false"})(),type:"managedEnum",onChange(){}}]:[],...(process.env.ANTHROPIC_API_KEY,[]),...[]];return H0((O,S)=>{if(S.escape){if(K!==null){E(null);return}let n=Object.entries(X).map(([r,N1])=>{return S1("tengu_config_changed",{key:r,value:N1}),`Set ${r} to ${LA.bold(N1)}`}),g=Boolean(process.env.ANTHROPIC_API_KEY&&G.current.customApiKeyResponses?.approved?.includes(ZP(process.env.ANTHROPIC_API_KEY))),Y1=Boolean(process.env.ANTHROPIC_API_KEY&&Q.customApiKeyResponses?.approved?.includes(ZP(process.env.ANTHROPIC_API_KEY)));if(g!==Y1)n.push(`${Y1?"Enabled":"Disabled"} custom API key`),S1("tengu_config_changed",{key:"env.ANTHROPIC_API_KEY",value:Y1});if(Q.theme!==G.current.theme)n.push(`Set theme to ${LA.bold(Q.theme)}`)
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
class Jb extends Error{constructor(A,B,Q){super(`MCP error ${A}: ${B}`);this.code=A,this.data=Q,this.name="McpError"}}var TS4=60000;class Qa{constructor(A){this._options=A,this._requestMessageId=0,this._requestHandlers=new Map,this._requestHandlerAbortControllers=new Map,this._notificationHandlers=new Map,this._responseHandlers=new Map,this._progressHandlers=new Map,this._timeoutInfo=new Map,this.setNotificationHandler(OI1,(B)=>{let Q=this._requestHandlerAbortControllers.get(B.params.requestId);Q===null||Q===void 0||Q.abort(B.params.reason)}),this.setNotificationHandler(PI1,(B)=>{this._onprogress(B)}),this.setRequestHandler(TI1,(B)=>({}))}_setupTimeout(A,B,Q,I,G=!1){this._timeoutInfo.set(A,{timeoutId:setTimeout(I,B),startTime:Date.now(),timeout:B,maxTotalTimeout:Q,resetTimeoutOnProgress:G,onTimeout:I})}_resetTimeout(A){let B=this._timeoutInfo.get(A);if(!B)return!1;let Q=Date.now()-B.startTime;if(B.maxTotalTimeout&&Q>=B.maxTotalTimeout)throw this._timeoutInfo.delete(A),new Jb(IL.RequestTimeout,"Maximum total timeout exceeded",{maxTotalTimeout:B.maxTotalTimeout,totalElapsed:Q});return clearTimeout(B.timeoutId),B.timeoutId=setTimeout(B.onTimeout,B.timeout),!0}_cleanupTimeout(A){let B=this._timeoutInfo.get(A);if(B)clearTimeout(B.timeoutId),this._timeoutInfo.delete(A)}async connect(A){this._transport=A,this._transport.onclose=()=>{this._onclose()},this._transport.onerror=(B)=>{this._onerror(B)},this._transport.onmessage=(B,Q)=>{if(Zx1(B)||qD0(B))this._onresponse(B);else if(wD0(B))this._onrequest(B,Q);else if(UD0(B))this._onnotification(B);else this._onerror(new Error(`Unknown message type: ${JSON.stringify(B)}`))},await this._transport.start()}_onclose(){var A;let B=this._responseHandlers;this._responseHandlers=new Map,this._progressHandlers.clear(),this._transport=void 0,(A=this.onclose)===null||A===void 0||A.call(this);let Q=new Jb(IL.ConnectionClosed,"Connection closed");for(let I of B.values())I(Q)}_onerror(A){var B;(B=this.onerror)===null||B===void 0||B.call(this,A)}_onnotification(A){var B
|
||||
|
||||
case"notifications/cancelled":break;case"notifications/progress":break}}assertRequestHandlerCapability(A){switch(A){case"sampling/createMessage":if(!this._capabilities.sampling)throw new Error(`Client does not support sampling capability (required for ${A})`);break;case"roots/list":if(!this._capabilities.roots)throw new Error(`Client does not support roots capability (required for ${A})`);break;case"ping":break}}async ping(A){return this.request({method:"ping"},vU,A)}async complete(A,B){return this.request({method:"completion/complete",params:A},Hx1,B)}async setLoggingLevel(A,B){return this.request({method:"logging/setLevel",params:{level:A}},vU,B)}async getPrompt(A,B){return this.request({method:"prompts/get",params:A},Cx1,B)}async listPrompts(A,B){return this.request({method:"prompts/list",params:A},Aa,B)}async listResources(A,B){return this.request({method:"resources/list",params:A},jI1,B)}async listResourceTemplates(A,B){return this.request({method:"resources/templates/list",params:A},Jx1,B)}async readResource(A,B){return this.request({method:"resources/read",params:A},yI1,B)}async subscribeResource(A,B){return this.request({method:"resources/subscribe",params:A},vU,B)}async unsubscribeResource(A,B){return this.request({method:"resources/unsubscribe",params:A},vU,B)}async callTool(A,B=Fb,Q){return this.request({method:"tools/call",params:A},B,Q)}async listTools(A,B){return this.request({method:"tools/list",params:A},Ba,B)}async sendRootsListChanged(){return this.notification({method:"notifications/roots/list_changed"})}}var wZ0=J1(zZ0(),1);import hI1 from"node:process";import{PassThrough as G_4}from"node:stream";class Ia{append(A){this._buffer=this._buffer?Buffer.concat([this._buffer,A]):A}readMessage(){if(!this._buffer)return null;let A=this._buffer.indexOf(`
|
||||
`);if(A===-1)return null;let B=this._buffer.toString("utf8",0,A).replace(/\r$/,"")
|
||||
|
||||
if(!G.success){let D=G.error.errors.map((Z)=>`${Z.path.join(".")}: ${Z.message}`).join(", ");throw new Error(`Invalid configuration: ${D}`)}Nb(A,G.data,Q)}function JY0(A,B="local"){if(B==="project"){let Q=UU();if(!Q[A])throw new Error(`No MCP server found with name: ${A} in .mcp.json`);let I={mcpServers:{...Q}};delete I.mcpServers[A];try{Sj1(I)}catch(G){throw new Error(`Failed to remove from .mcp.json: ${G}`)}}else if(B==="user"){let Q=XA();if(!Q.mcpServers?.[A])throw new Error(`No global MCP server found with name: ${A}`);delete Q.mcpServers[A],P0(Q)}else{let Q=w9();if(!Q.mcpServers?.[A])throw new Error(`No local MCP server found with name: ${A}`);delete Q.mcpServers[A],S6(Q)}}function rx1(A){let B=w9(),Q=UU(),I=XA();if(B.mcpServers?.[A])return{...B.mcpServers[A],scope:"local"};if(Q?.[A])return{...Q[A],scope:"project"};if(I.mcpServers?.[A])return{...I.mcpServers[A],scope:"user"};return}var ZY0=parseInt(process.env.MCP_TIMEOUT||"",10)||30000;function ox1(A){let B=w9();if(B.disabledMcpjsonServers?.includes(A))return"rejected";if(B.enabledMcpjsonServers?.includes(A)||B.enableAllProjectMcpServers)return"approved";return"pending"}var FV=f0(()=>{let A=XA().mcpServers??{},B=UU(),Q=w9().mcpServers??{},I=VU1(B,(G,D)=>ox1(D)==="approved");return S1("tengu_mcp_servers",{global:Object.keys(A).length,project:Object.keys(I).length,user:Object.keys(Q).length}),{...A,...I,...Q}}),CY0=f0(async(A,B)=>{try{let Q;if(B.type==="sse"){let W=await DY0(A,B.url),F=B.headers||{},J={...F,Accept:"text/event-stream"};if(W)J.Authorization=`Bearer ${W}`;let C={...F,"Content-Type":"application/json"};if(W)C.Authorization=`Bearer ${W}`;let X={eventSourceInit:{fetch:(V,K)=>{return fetch(V,{...K,headers:{...K?.headers,...J}})}},requestInit:{headers:C}};Q=new cI1(new URL(B.url),X)}else if(B.type==="sse-ide")Q=new cI1(new URL(B.url));else if(B.type==="ws-ide"){let W=new kQ1.default(B.url,["mcp"]);Q=new sx1(W)}else Q=new Px1({command:B.command,args:B.args,env:{...process.env,...B.env},stderr:"pipe"})
|
||||
|
||||
function kW6(){return process.env.HTTPS_PROXY||process.env.HTTP_PROXY?{dispatcher:new id1({uri:process.env.HTTPS_PROXY||process.env.HTTP_PROXY||"",pipelining:1})}:void 0}function nb0(A){if(A?.startsWith("claude-3-5-haiku"))return process.env.VERTEX_REGION_CLAUDE_3_5_HAIKU;else if(A?.startsWith("claude-3-5-sonnet"))return process.env.VERTEX_REGION_CLAUDE_3_5_SONNET;else if(A?.startsWith("claude-3-7-sonnet"))return process.env.VERTEX_REGION_CLAUDE_3_7_SONNET;return process.env.CLOUD_ML_REGION||"us-east5"}async function ab0(A,B){if(!A)return 0;return bW1([{role:"user",content:A}],B)}async function bW1(A,B){try{if(!A||A.length===0)return 0;let Q=await YQ(),I=await PV({maxRetries:1,model:Q,isNonInteractiveSession:B}),G=await SH();return(await I.beta.messages.countTokens({model:Q,messages:A,...G.length>0?{betas:G}:{}})).input_tokens}catch(Q){return m1(Q),null}}function Xr(A){return A.length/4}var nd1=25000,xW6=0.5;function fW6(A){return A.type==="text"}function vW6(A){return A.type==="image"}function bW6(A){if(!A)return 0;if(typeof A==="string")return Xr(A);return A.reduce((B,Q)=>{if(fW6(Q))return B+Xr(Q.text);else if(vW6(Q))return B+1600;return B},0)}class Vr extends Error{constructor(A,B){super(`MCP tool "${A}" response (${B} tokens) exceeds maximum allowed tokens (${nd1}). Please use pagination, filtering, or limit parameters to reduce the response size.`);this.name="MCPContentTooLargeError"}}async function ad1(A,B,Q){if(!A)return;if(bW6(A)<=nd1*xW6)return;try{let D=await bW1(typeof A==="string"?[{role:"user",content:A}]:[{role:"user",content:A}],Q);if(D&&D>nd1)throw new Vr(B,D)}catch(G){if(G instanceof Vr)throw G;m1(G instanceof Error?G:new Error(String(G)))}}var gW6=new Set(["image/jpeg","image/png","image/gif","image/webp"]),hW6=parseInt(process.env.MCP_TOOL_TIMEOUT||"",10)||1e8,mW6=["mcp__ide__executeCode","mcp__ide__getDiagnostics"];function dW6(A){return!A.name.startsWith("mcp__ide__")||mW6.includes(A.name)}var uW6=f0(async(A)=>{if(A.type!=="connected")return[];try{if(!A.capabilities?.tools)return[]
|
||||
|
||||
return(await A.client.request({method:"tools/list"},Ba)).tools.map((Q)=>({...NY0,name:"mcp__"+A.name.replace(/\s+/g,"_")+"__"+Q.name,isMcp:!0,async description(){return Q.description??""},async prompt(){return Q.description??""},inputJSONSchema:Q.inputSchema,async*call(I,G){yield{type:"result",data:await ob0({client:A,tool:Q.name,args:I,signal:G.abortController.signal,isNonInteractiveSession:G.options.isNonInteractiveSession})}},userFacingName(){return`${A.name}:${Q.name} (MCP)`}})).filter(dW6)}catch(B){return QY(A.name,`Failed to fetch tools: ${B instanceof Error?B.message:String(B)}`),[]}}),pW6=f0(async(A)=>{if(A.type!=="connected")return[];let B=A;try{if(!A.capabilities?.prompts)return[];let Q=await A.client.request({method:"prompts/list"},Aa);if(!Q.prompts)return[];return Q.prompts.map((I)=>{let G=Object.values(I.arguments??{}).map((D)=>D.name);return{type:"prompt",name:"mcp__"+B.name.replace(/\s+/g,"_")+"__"+I.name,description:I.description??"",isEnabled:!0,isHidden:!1,isMcp:!0,progressMessage:"running",userFacingName(){return`${B.name}:${I.name} (MCP)`},argNames:G,async getPromptForCommand(D){let Z=D.split(" ");try{return(await B.client.getPrompt({name:I.name,arguments:zU1(G,Z)})).messages.map((W)=>{let F=rb0(W.content,A.name);return{role:W.role,content:F}})}catch(Y){throw QY(A.name,`Error running command '${I.name}': ${Y instanceof Error?Y.message:String(Y)}`),Y}}}})}catch(Q){return QY(A.name,`Failed to fetch commands: ${Q instanceof Error?Q.message:String(Q)}`),[]}});async function QL(A,B,Q,I){return ob0({client:Q,tool:A,args:B,signal:new AbortController().signal,isNonInteractiveSession:I})}async function sd1(A,B){let Q=!1,I=FV(),G=B?{...I,...B}:I;await Promise.all(Object.entries(G).map(async([D,Z])=>{let Y=await CY0(D,Z);if(Y.type!=="connected"){A({client:Y,tools:[],commands:[]});return}let W=!!Y.capabilities?.resources,[F,J]=await Promise.all([uW6(Y),pW6(Y)]),C=[];A({client:Y,tools:[...F,...C],commands:J})}))}async function sb0(A){return new Promise((B)=>{let Q=0,I=0,G=FV(),D=A?{...G,...A}:G
|
||||
|
||||
if(Q=Object.keys(D).length,Q===0){B({clients:[],tools:[],commands:[]});return}let Z=[],Y=[],W=[];sd1((F)=>{if(Z.push(F.client),Y.push(...F.tools),W.push(...F.commands),I++,I>=Q)B({clients:Z,tools:Y,commands:W})},A)})}function rb0(A,B){switch(A.type){case"text":return[{type:"text",text:A.text}];case"image":return[{type:"image",source:{data:String(A.data),media_type:A.mimeType||"image/jpeg",type:"base64"}}];case"resource":{let Q=A.resource,I="";if("text"in Q)return[{type:"text",text:`${Q.text}`}];else if("blob"in Q)if(gW6.has(Q.mimeType??"")){let D=[];return D.push({type:"image",source:{data:Q.blob,media_type:Q.mimeType||"image/jpeg",type:"base64"}}),D}else return[{type:"text",text:`Base64 data (${Q.mimeType||"unknown type"}) ${Q.blob}`}];return[]}default:return[]}}async function ob0({client:{client:A,name:B},tool:Q,args:I,signal:G,isNonInteractiveSession:D}){try{let Z=await A.callTool({name:Q,arguments:I},Fb,{signal:G,timeout:hW6});if("isError"in Z&&Z.isError){let W=`Error calling tool ${Q}: ${Z.error}`;throw QY(B,W),Error(W)}if("toolResult"in Z){let W=String(Z.toolResult);return await ad1(W,Q,D),W}if("content"in Z&&Array.isArray(Z.content)){let F=Z.content.map((J)=>rb0(J,B)).flat();return await ad1(F,Q,D),F}let Y=`Unexpected response format from tool ${Q}`;throw QY(B,Y),Error(Y)}catch(Z){if(Z instanceof Vr)throw Z;if(!(Z instanceof Error)||Z.name!=="AbortError")throw Z}}class SV{static instance;baseline=new Map;initialized=!1;mcpClient;lastProcessedTimestamps=new Map;lastDiagnosticsByUri=new Map;rightFileDiagnosticsState=new Map;static getInstance(){if(!SV.instance)SV.instance=new SV;return SV.instance}initialize(A){if(process.env.ENABLE_IDE_INTEGRATION!=="true")return;if(this.initialized)return;if(this.mcpClient=A,this.initialized=!0,this.mcpClient&&this.mcpClient.type==="connected"){let B=i.object({method:i.literal("diagnostics_changed"),params:i.object({uri:i.string()})});this.mcpClient.client.setNotificationHandler(B,async(Q)=>{let{uri:I}=Q.params
|
||||
|
||||
if(b1().existsSync(D))return D}}}catch(Q){m1(Q instanceof Error?Q:new Error(String(Q)))}throw new Error("Could not find Claude Desktop config file in Windows. Make sure Claude Desktop is installed on Windows.")}function w$2(){if(!CM1.includes(NJ()))throw new Error("Unsupported platform - Claude Desktop integration only works on macOS and WSL.");try{let A=d75();if(!b1().existsSync(A))return{};let B=b1().readFileSync(A,{encoding:"utf8"}),Q=I8(B);if(!Q||typeof Q!=="object")return{};let I=Q.mcpServers;if(!I||typeof I!=="object")return{};let G={};for(let[D,Z]of Object.entries(I)){if(!Z||typeof Z!=="object")continue;let Y=qj1.safeParse(Z);if(Y.success)G[D]=Y.data}return G}catch(A){return m1(A instanceof Error?A:new Error(String(A))),{}}}import{cwd as BO}from"process";function u75(A,B,Q){if(Q.type!=="assistant")return;if(!Array.isArray(Q.message.content))return;for(let I of Q.message.content){if(I.type!=="tool_use")continue;let G=A.find((D)=>D.name===I.name);if(G)B.set(I.id,G)}}function ue(A,B){try{let Q=Vu0(A);if(Q[Q.length-1]?.type==="user")Q.push(xV({content:fr}));let G=new Map;for(let D of Q)u75(B,G,D);return Q}catch(Q){throw m1(Q),Q}}var p75=J1(_1(),1);var qI=J1(_1(),1);import{homedir as E$2}from"os";function U$2({onDone:A}){let B=$1(),Q=UU(),I=Object.keys(Q).length>0;qI.default.useEffect(()=>{let Z=E$2()===pA();S1("trust_dialog_shown",{isHomeDir:Z,hasMcpServers:I})},[I]);function G(Z){let Y=w9();if(Z==="no")process.exit(1);let W=Z==="yes_enable_mcp",F=E$2()===pA();if(S1("trust_dialog_accept",{isHomeDir:F,hasMcpServers:I,enableMcp:W}),I)S6({...Y,...F?{}:{hasTrustDialogAccepted:!0},...W?{enabledMcpjsonServers:Object.keys(Q),enableAllProjectMcpServers:!0}:{disabledMcpjsonServers:Object.keys(Q)}});else if(!F)S6({...Y,hasTrustDialogAccepted:!0});A()}let D=k2();return H0((Z,Y)=>{if(Y.escape){process.exit(0)
|
||||
|
||||
if(!Y.disabledMcpjsonServers)Y.disabledMcpjsonServers=[];for(let W of A)if(!Y.disabledMcpjsonServers.includes(W))Y.disabledMcpjsonServers.push(W);S6(Y),B();return}}),AW.default.createElement(AW.default.Fragment,null,AW.default.createElement(m,{flexDirection:"column",gap:1,padding:1,borderStyle:"round",borderColor:Q.warning},AW.default.createElement(y,{bold:!0,color:Q.warning},A.length," new MCP servers found in .mcp.json"),AW.default.createElement(y,null,"Select any you wish to enable."),AW.default.createElement(tK1,null),AW.default.createElement(G71,{options:A.map((D)=>({label:D,value:D})),defaultValue:A,onSubmit:I})),AW.default.createElement(m,{marginLeft:3},AW.default.createElement(y,{dimColor:!0},G.pending?AW.default.createElement(AW.default.Fragment,null,"Press ",G.keyName," again to exit"):AW.default.createElement(AW.default.Fragment,null,"Space to select · Enter to confirm · Esc to reject all"))))}var jF=J1(_1(),1);function _$2({serverName:A,onDone:B}){let Q=$1();function I(D){let Z=w9();switch(S1("tengu_mcp_dialog_choice",{choice:D}),D){case"yes":case"yes_all":{if(!Z.enabledMcpjsonServers)Z.enabledMcpjsonServers=[];if(!Z.enabledMcpjsonServers.includes(A))Z.enabledMcpjsonServers.push(A);if(D==="yes_all")Z.enableAllProjectMcpServers=!0;S6(Z),B();break}case"no":{if(!Z.disabledMcpjsonServers)Z.disabledMcpjsonServers=[];if(!Z.disabledMcpjsonServers.includes(A))Z.disabledMcpjsonServers.push(A);S6(Z),B();break}}}let G=k2();return H0((D,Z)=>{if(Z.escape){B()
|
||||
|
||||
S6({...I,enabledMcpjsonServers:[],disabledMcpjsonServers:[],enableAllProjectMcpServers:!1}),console.log("All project-scoped (.mcp.json) server approvals and rejections have been reset."),console.log("You will be prompted for approval next time you start Claude Code."),process.exit(0)}),A.command("migrate-installer").description("Migrate from global npm installation to local installation").helpOption("-h, --help","Display help for command").action(async()=>{if(sR())console.log("Already running from local installation. No migration needed."),process.exit(0);S1("tengu_migrate_installer_command",{}),await new Promise((I)=>{let{waitUntilExit:G}=d8(b3.default.createElement(pQ,null,b3.default.createElement(qd,null)));G().then(()=>{I()})}),process.exit(0)}),A.command("doctor").description("Check the health of your Claude Code auto-updater").helpOption("-h, --help","Display help for command").action(async()=>{S1("tengu_doctor_command",{}),await new Promise((I)=>{d8(b3.default.createElement(pQ,null,b3.default.createElement(EK1,{onDone:()=>I(),doctorMode:!0})),{exitOnCtrlC:!1})}),process.exit(0)}),A.command("update").description("Check for updates and install if available").helpOption("-h, --help","Display help for command").action(async()=>{if(S1("tengu_update_check",{}),console.log(`Current version: ${{ISSUES_EXPLAINER:"report the issue at https://github.com/anthropics/claude-code/issues",PACKAGE_URL:"@anthropic-ai/claude-code",README_URL:"https://docs.anthropic.com/s/claude-code",VERSION:"0.2.126"}.VERSION}`),console.log("Checking for updates..."),await eR())try{let W=await xK1();if(!W.latestVersion)console.error("Failed to check for updates"),process.exit(1)
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"version": "3.12.1",
|
||||
"sizeBytes": 7239275,
|
||||
"lines": 2354,
|
||||
"functions": 13869,
|
||||
"asyncFunctions": 350,
|
||||
"arrowFunctions": 13308,
|
||||
"classes": 1049,
|
||||
"extends": 571,
|
||||
"sourceFile": "cli.js",
|
||||
"extractedAt": "2026-04-02T23:28:41.868Z",
|
||||
"modules": {
|
||||
"permission-system": {
|
||||
"fragments": 126,
|
||||
"sizeBytes": 297775
|
||||
},
|
||||
"tool-dispatch": {
|
||||
"fragments": 11,
|
||||
"sizeBytes": 138273
|
||||
},
|
||||
"agent-loop": {
|
||||
"fragments": 17,
|
||||
"sizeBytes": 37065
|
||||
},
|
||||
"streaming-handler": {
|
||||
"fragments": 10,
|
||||
"sizeBytes": 19443
|
||||
},
|
||||
"mcp-client": {
|
||||
"fragments": 9,
|
||||
"sizeBytes": 16967
|
||||
},
|
||||
"context-manager": {
|
||||
"fragments": 2,
|
||||
"sizeBytes": 3319
|
||||
},
|
||||
"telemetry": {
|
||||
"fragments": 161,
|
||||
"sizeBytes": 4726
|
||||
},
|
||||
"commands": {
|
||||
"fragments": 21,
|
||||
"sizeBytes": 1620
|
||||
},
|
||||
"class-hierarchy": {
|
||||
"fragments": 719,
|
||||
"sizeBytes": 10837
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,27 @@
|
|||
try{for await(let D of BR4(A,B)){if(D.event==="completion")try{yield JSON.parse(D.data)}catch(Z){throw console.error("Could not parse message into JSON:",D.data),console.error("From chunk:",D.raw),Z}if(D.event==="message_start"||D.event==="message_delta"||D.event==="message_stop"||D.event==="content_block_start"||D.event==="content_block_delta"||D.event==="content_block_stop")try{yield JSON.parse(D.data)}catch(Z){throw console.error("Could not parse message into JSON:",D.data),console.error("From chunk:",D.raw),Z}if(D.event==="ping")continue;if(D.event==="error")throw new K5(void 0,O71(D.data)??D.data,void 0,A.headers)}G=!0}catch(D){if(PU(D))return;throw D}finally{if(!G)B.abort()}}return new AZ(I,B)}static fromReadableStream(A,B){let Q=!1;async function*I(){let D=new sM,Z=wn(A);for await(let Y of Z)for(let W of D.decode(Y))yield W;for(let Y of D.flush())yield Y}async function*G(){if(Q)throw new q9("Cannot iterate over a consumed stream, use `.tee()` to split the stream.");Q=!0;let D=!1;try{for await(let Z of I()){if(D)continue;if(Z)yield JSON.parse(Z)}D=!0}catch(Z){if(PU(Z))return;throw Z}finally{if(!D)B.abort()}}return new AZ(G,B)}[Symbol.asyncIterator](){return this.iterator()}tee(){let A=[],B=[],Q=this.iterator(),I=(G)=>{return{next:()=>{if(G.length===0){let D=Q.next();A.push(D),B.push(D)}return G.shift()}}};return[new AZ(()=>I(A),this.controller),new AZ(()=>I(B),this.controller)]}toReadableStream(){let A=this,B;return zk1({async start(){B=A[Symbol.asyncIterator]()},async pull(Q){try{let{value:I,done:G}=await B.next();if(G)return Q.close();let D=En(JSON.stringify(I)+`
|
||||
`);Q.enqueue(D)}catch(I){Q.error(I)}},async cancel(){await B.return?.()}})}}async function*BR4(A,B){if(!A.body){if(B.abort(),typeof globalThis.navigator!=="undefined"&&globalThis.navigator.product==="ReactNative")throw new q9("The default react-native fetch implementation does not support streaming. Please use expo/fetch: https://docs.expo.dev/versions/latest/sdk/expo/#expofetch-api")
|
||||
|
||||
F0(this,Mn,"f").call(this,I),F0(this,Rn,"f").call(this,I),this._emit("end");return}if(A==="error"){let I=B[0];if(!F0(this,tv,"f")&&!Q?.length)Promise.reject(I);F0(this,Mn,"f").call(this,I),F0(this,Rn,"f").call(this,I),this._emit("end")}}_emitFinal(){if(this.receivedMessages.at(-1))this._emit("finalMessage",F0(this,mJ,"m",qk1).call(this))}async _fromReadableStream(A,B){let Q=B?.signal;if(Q){if(Q.aborted)this.controller.abort();Q.addEventListener("abort",()=>this.controller.abort())}F0(this,mJ,"m",Lk1).call(this),this._connected(null);let I=AZ.fromReadableStream(A,this.controller);for await(let G of I)F0(this,mJ,"m",Rk1).call(this,G);if(I.controller.signal?.aborted)throw new BI;F0(this,mJ,"m",Ok1).call(this)}[(rM=new WeakMap,qn=new WeakMap,f71=new WeakMap,Mn=new WeakMap,Ln=new WeakMap,v71=new WeakMap,Rn=new WeakMap,yU=new WeakMap,On=new WeakMap,b71=new WeakMap,g71=new WeakMap,tv=new WeakMap,h71=new WeakMap,m71=new WeakMap,Mk1=new WeakMap,mJ=new WeakSet,qk1=function A(){if(this.receivedMessages.length===0)throw new q9("stream ended without producing a Message with role=assistant");return this.receivedMessages.at(-1)},sQ0=function A(){if(this.receivedMessages.length===0)throw new q9("stream ended without producing a Message with role=assistant");let B=this.receivedMessages.at(-1).content.filter((Q)=>Q.type==="text").map((Q)=>Q.text);if(B.length===0)throw new q9("stream ended without producing a content block with type=text");return B.join(" ")},Lk1=function A(){if(this.ended)return;l9(this,rM,void 0,"f")},Rk1=function A(B){if(this.ended)return;let Q=F0(this,mJ,"m",rQ0).call(this,B);switch(this._emit("streamEvent",B,Q),B.type){case"content_block_delta":{let I=Q.content.at(-1);switch(B.delta.type){case"text_delta":{if(I.type==="text")this._emit("text",B.delta.text,I.text||"");break}case"citations_delta":{if(I.type==="text")this._emit("citation",B.delta.citation,I.citations??[]);break}case"input_json_delta":{if(I.type==="tool_use"&&I.input)this._emit("inputJson",B.delta.partial_json,I.input)
|
||||
|
||||
break}case"thinking_delta":{if(I.type==="thinking")this._emit("thinking",B.delta.thinking,I.thinking);break}case"signature_delta":{if(I.type==="thinking")this._emit("signature",I.signature);break}default:tQ0(B.delta)}break}case"message_stop":{this._addMessageParam(Q),this._addMessage(Q,!0);break}case"content_block_stop":{this._emit("contentBlock",Q.content.at(-1));break}case"message_start":{l9(this,rM,Q,"f");break}case"content_block_start":case"message_delta":break}},Ok1=function A(){if(this.ended)throw new q9("stream has ended, this shouldn't happen");let B=F0(this,rM,"f");if(!B)throw new q9("request ended without sending any chunks");return l9(this,rM,void 0,"f"),B},rQ0=function A(B){let Q=F0(this,rM,"f");if(B.type==="message_start"){if(Q)throw new q9(`Unexpected event order, got ${B.type} before receiving "message_stop"`);return B.message}if(!Q)throw new q9(`Unexpected event order, got ${B.type} before "message_start"`);switch(B.type){case"message_stop":return Q;case"message_delta":if(Q.stop_reason=B.delta.stop_reason,Q.stop_sequence=B.delta.stop_sequence,Q.usage.output_tokens=B.usage.output_tokens,B.usage.input_tokens!=null)Q.usage.input_tokens=B.usage.input_tokens;if(B.usage.cache_creation_input_tokens!=null)Q.usage.cache_creation_input_tokens=B.usage.cache_creation_input_tokens;if(B.usage.cache_read_input_tokens!=null)Q.usage.cache_read_input_tokens=B.usage.cache_read_input_tokens;if(B.usage.server_tool_use!=null)Q.usage.server_tool_use=B.usage.server_tool_use;return Q;case"content_block_start":return Q.content.push(B.content_block),Q;case"content_block_delta":{let I=Q.content.at(B.index);switch(B.delta.type){case"text_delta":{if(I?.type==="text")I.text+=B.delta.text;break}case"citations_delta":{if(I?.type==="text")I.citations??(I.citations=[]),I.citations.push(B.delta.citation);break}case"input_json_delta":{if(I?.type==="tool_use"){let G=I[oQ0]||""
|
||||
|
||||
if(G+=B.delta.partial_json,Object.defineProperty(I,oQ0,{value:G,enumerable:!1,writable:!0}),G)I.input=x71(G)}break}case"thinking_delta":{if(I?.type==="thinking")I.thinking+=B.delta.thinking;break}case"signature_delta":{if(I?.type==="thinking")I.signature=B.delta.signature;break}default:tQ0(B.delta)}return Q}case"content_block_stop":return Q}},Symbol.asyncIterator)](){let A=[],B=[],Q=!1;return this.on("streamEvent",(I)=>{let G=B.shift();if(G)G.resolve(I);else A.push(I)}),this.on("end",()=>{Q=!0;for(let I of B)I.resolve(void 0);B.length=0}),this.on("abort",(I)=>{Q=!0;for(let G of B)G.reject(I);B.length=0}),this.on("error",(I)=>{Q=!0;for(let G of B)G.reject(I);B.length=0}),{next:async()=>{if(!A.length){if(Q)return{value:void 0,done:!0};return new Promise((G,D)=>B.push({resolve:G,reject:D})).then((G)=>G?{value:G,done:!1}:{value:void 0,done:!0})}return{value:A.shift(),done:!1}},return:async()=>{return this.abort(),{value:void 0,done:!0}}}}toReadableStream(){return new AZ(this[Symbol.asyncIterator].bind(this),this.controller).toReadableStream()}}function tQ0(A){}var eQ0={"claude-1.3":"November 6th, 2024","claude-1.3-100k":"November 6th, 2024","claude-instant-1.1":"November 6th, 2024","claude-instant-1.1-100k":"November 6th, 2024","claude-instant-1.2":"November 6th, 2024","claude-3-sonnet-20240229":"July 21st, 2025","claude-2.1":"July 21st, 2025","claude-2.0":"July 21st, 2025"};class ev extends GG{constructor(){super(...arguments);this.batches=new $n(this._client)}create(A,B){let{betas:Q,...I}=A;if(I.model in eQ0)console.warn(`The model '${I.model}' is deprecated and will reach end-of-life on ${eQ0[I.model]}
|
||||
Please migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`)
|
||||
|
||||
F0(this,uJ,"m",jk1).call(this)}[(tM=new WeakMap,Sn=new WeakMap,d71=new WeakMap,_n=new WeakMap,jn=new WeakMap,u71=new WeakMap,yn=new WeakMap,kU=new WeakMap,kn=new WeakMap,p71=new WeakMap,c71=new WeakMap,Ab=new WeakMap,l71=new WeakMap,i71=new WeakMap,Pk1=new WeakMap,uJ=new WeakSet,Tk1=function A(){if(this.receivedMessages.length===0)throw new q9("stream ended without producing a Message with role=assistant");return this.receivedMessages.at(-1)},A70=function A(){if(this.receivedMessages.length===0)throw new q9("stream ended without producing a Message with role=assistant");let B=this.receivedMessages.at(-1).content.filter((Q)=>Q.type==="text").map((Q)=>Q.text);if(B.length===0)throw new q9("stream ended without producing a content block with type=text");return B.join(" ")},Sk1=function A(){if(this.ended)return;l9(this,tM,void 0,"f")},_k1=function A(B){if(this.ended)return;let Q=F0(this,uJ,"m",B70).call(this,B);switch(this._emit("streamEvent",B,Q),B.type){case"content_block_delta":{let I=Q.content.at(-1);switch(B.delta.type){case"text_delta":{if(I.type==="text")this._emit("text",B.delta.text,I.text||"");break}case"citations_delta":{if(I.type==="text")this._emit("citation",B.delta.citation,I.citations??[]);break}case"input_json_delta":{if(I.type==="tool_use"&&I.input)this._emit("inputJson",B.delta.partial_json,I.input);break}case"thinking_delta":{if(I.type==="thinking")this._emit("thinking",B.delta.thinking,I.thinking);break}case"signature_delta":{if(I.type==="thinking")this._emit("signature",I.signature);break}default:I70(B.delta)}break}case"message_stop":{this._addMessageParam(Q),this._addMessage(Q,!0);break}case"content_block_stop":{this._emit("contentBlock",Q.content.at(-1));break}case"message_start":{l9(this,tM,Q,"f");break}case"content_block_start":case"message_delta":break}},jk1=function A(){if(this.ended)throw new q9("stream has ended, this shouldn't happen");let B=F0(this,tM,"f");if(!B)throw new q9("request ended without sending any chunks")
|
||||
|
||||
return l9(this,tM,void 0,"f"),B},B70=function A(B){let Q=F0(this,tM,"f");if(B.type==="message_start"){if(Q)throw new q9(`Unexpected event order, got ${B.type} before receiving "message_stop"`);return B.message}if(!Q)throw new q9(`Unexpected event order, got ${B.type} before "message_start"`);switch(B.type){case"message_stop":return Q;case"message_delta":if(Q.stop_reason=B.delta.stop_reason,Q.stop_sequence=B.delta.stop_sequence,Q.usage.output_tokens=B.usage.output_tokens,B.usage.input_tokens!=null)Q.usage.input_tokens=B.usage.input_tokens;if(B.usage.cache_creation_input_tokens!=null)Q.usage.cache_creation_input_tokens=B.usage.cache_creation_input_tokens;if(B.usage.cache_read_input_tokens!=null)Q.usage.cache_read_input_tokens=B.usage.cache_read_input_tokens;if(B.usage.server_tool_use!=null)Q.usage.server_tool_use=B.usage.server_tool_use;return Q;case"content_block_start":return Q.content.push(B.content_block),Q;case"content_block_delta":{let I=Q.content.at(B.index);switch(B.delta.type){case"text_delta":{if(I?.type==="text")I.text+=B.delta.text;break}case"citations_delta":{if(I?.type==="text")I.citations??(I.citations=[]),I.citations.push(B.delta.citation);break}case"input_json_delta":{if(I?.type==="tool_use"){let G=I[Q70]||"";if(G+=B.delta.partial_json,Object.defineProperty(I,Q70,{value:G,enumerable:!1,writable:!0}),G)I.input=x71(G)}break}case"thinking_delta":{if(I?.type==="thinking")I.thinking+=B.delta.thinking;break}case"signature_delta":{if(I?.type==="thinking")I.signature=B.delta.signature;break}default:I70(B.delta)}return Q}case"content_block_stop":return Q}},Symbol.asyncIterator)](){let A=[],B=[],Q=!1;return this.on("streamEvent",(I)=>{let G=B.shift();if(G)G.resolve(I);else A.push(I)}),this.on("end",()=>{Q=!0;for(let I of B)I.resolve(void 0);B.length=0}),this.on("abort",(I)=>{Q=!0;for(let G of B)G.reject(I);B.length=0}),this.on("error",(I)=>{Q=!0;for(let G of B)G.reject(I);B.length=0}),{next:async()=>{if(!A.length){if(Q)return{value:void 0,done:!0}
|
||||
|
||||
return{...A,message:{...A.message,content:[...Q,...I]}}}function TF1(A){if(typeof A==="string")return[{type:"text",text:A}];return A}function $w6(A,B){let Q=tZ(A);if(Q?.type==="tool_result"&&typeof Q.content==="string"&&B.every((I)=>I.type==="text"))return[...A.slice(0,-1),{...Q,content:[Q.content,...B.map((I)=>I.text)].map((I)=>I.trim()).filter(Boolean).join(`
|
||||
|
||||
`)}];return[...A,...B]}function _F1(A){let B=A.filter((Q)=>Q.type!=="text"||Q.text.trim().length>0);if(B.length===0)return S1("tengu_empty_model_response",{}),[{type:"text",text:_Y}];return B}function jF1(A){return gr(A).trim()===""||A.trim()===_Y}var qw6=["commit_analysis","context","function_analysis","pr_analysis"];function gr(A){let B=new RegExp(`<(${qw6.join("|")})>.*?</\\1>
|
||||
?`,"gs");return A.replace(B,"").trim()}function hr(A){switch(A.type){case"attachment":return null;case"assistant":if(A.message.content[0]?.type!=="tool_use")return null;return A.message.content[0].id;case"user":if(A.message.content[0]?.type!=="tool_result")return null;return A.message.content[0].tool_use_id;case"progress":return A.toolUseID}}function Vu0(A){let B=WB(A),Q=wN(B);return B.filter((G,D)=>{if(G.type==="assistant"&&G.message.content[0]?.type==="tool_use"&&Q.has(G.message.content[0].id))return!1;return!0})}function yF1(A){if(A.type!=="assistant")return null;if(Array.isArray(A.message.content))return A.message.content.filter((B)=>B.type==="text").map((B)=>B.type==="text"?B.text:"").join(`
|
||||
`).trim()||null;return null}function tu1(A,B){let Q=hr(A);if(!Q)return[];return B.filter((I)=>I.type==="progress"&&I.parentToolUseID===Q)}function eu1(A,B,Q,I){if(A.type!=="stream_event"&&A.type!=="stream_request_start"){B(A);return}if(A.type==="stream_request_start"){I("requesting");return}if(A.event.type==="message_stop"){I("tool-use");return}switch(A.event.type){case"content_block_start":switch(A.event.content_block.type){case"thinking":case"redacted_thinking":I("thinking");return;case"text":I("responding");return;case"tool_use":I("tool-input");return
|
||||
|
||||
case"server_tool_use":case"web_search_tool_result":I("tool-input");return}break;case"content_block_delta":switch(A.event.delta.type){case"text_delta":Q(A.event.delta.text);return;case"input_json_delta":Q(A.event.delta.partial_json);return;case"thinking_delta":Q(A.event.delta.thinking);return;case"signature_delta":Q(A.event.delta.signature);return;default:return}default:I("responding");return}}function Mw6(A){switch(A.type){case"new_directory":return[ru1(KC.name,{path:A.path}),Yu0(KC,A.content)];case"edited_text_file":return[q2({content:`<system-reminder>
|
||||
Note: ${A.filename} was modified, either by the user or by a linter. Don't tell the user this, since they are already aware. This change was intentional, so make sure to take it into account as you proceed (ie. don't revert it unless the user asks you to). So that you don't need to re-read the file, here's the result of running \`cat -n\` on a snippet of the edited file:`,isMeta:!0}),q2({content:A.snippet,isMeta:!0}),q2({content:"</system-reminder>",isMeta:!0})];case"edited_image_file":return[];case"new_file":{let B=A.content;switch(B.type){case"image":return[ru1(y3.name,{file_path:A.filename}),q2({content:[{source:{data:B.file.base64,type:"base64",media_type:B.file.type},type:"image"}]})];case"text":return[ru1(y3.name,{file_path:A.filename}),Yu0(y3,B),...A.truncated?[q2({content:`Note: The file ${A.filename} was too large and has been truncated to the first 100 lines. Don't tell the user about this truncation. Use ${y3.name} to read more of the file if you need.`,isMeta:!0})]:[]]}break}case"selected_lines_in_ide":return[q2({content:`The user selected the following lines from ${A.filename}:
|
||||
${A.content}`,isMeta:!0})];case"opened_file_in_ide":return[q2({content:`The user opened the file ${A.filename} in the IDE.`,isMeta:!0})]
|
||||
|
||||
else _X(`CLAUDE_CODE_EXTRA_BODY env var must be a JSON object, but was given ${Q}`)}catch(D){_X(`Error parsing CLAUDE_CODE_EXTRA_BODY: ${D instanceof Error?D.message:String(D)}`)}let G={...B,...I};if(A&&A.length>0)if(G.anthropic_beta&&Array.isArray(G.anthropic_beta)){let D=G.anthropic_beta,Z=A.filter((Y)=>!D.includes(Y));G.anthropic_beta=[...D,...Z]}else G.anthropic_beta=A;return G}var bY="API Error",Ct="Prompt is too long",xa1="Credit balance is too low",CX1="Invalid API key · Please run /login",fa1="Claude AI usage limit reached",KW2="placeholder-R529",_Y="(no content)",XX1="OAuth token revoked · Please run /login",m_=!T31(process.env.DISABLE_PROMPT_CACHING),HW2=1,zW2="placeholder-COSM";function dr(){return{user_id:fP()}}async function wW2(A,B){if(B)return!0;try{let Q=await QU();return await Jt(()=>PV({apiKey:A,maxRetries:3,model:oH(),isNonInteractiveSession:B}),async(I)=>{let G=oH(),D=[{role:"user",content:"test"}];return await I.beta.messages.create({model:G,max_tokens:1,messages:D,temperature:0,...Q.length>0?{betas:Q}:{},metadata:dr(),...ka1()}),!0},{maxRetries:2,showErrors:!1,model:oH()}),!0}catch(Q){let I=Q;if(Q instanceof h_)I=Q.originalError;if(m1(I),I instanceof Error&&I.message.includes('{"type":"error","error":{"type":"authentication_error","message":"invalid x-api-key"}}'))return!1;throw I}}async function Mt6(A){let B=Date.now(),Q,I=null;for await(let D of A)if(D.type==="message_start")Q=Date.now()-B,I={cache_read_input_tokens:D.message.usage.cache_read_input_tokens,cache_creation_input_tokens:D.message.usage.cache_creation_input_tokens};let G=await A.finalMessage();return{...G,ttftMs:Q,usage:{...G.usage,cache_read_input_tokens:G.usage.cache_read_input_tokens??I?.cache_read_input_tokens??0,cache_creation_input_tokens:G.usage.cache_creation_input_tokens??I?.cache_creation_input_tokens??0}}}function Lt6(A,B=!1){if(B)if(typeof A.message.content==="string")return{role:"user",content:[{type:"text",text:A.message.content,...m_?{cache_control:{type:"ephemeral"}}:{}}]}
|
||||
|
||||
try{for await(let v of E){if(v.type==="message_start"&&v.message?.usage)q={cache_read_input_tokens:v.message.usage.cache_read_input_tokens,cache_creation_input_tokens:v.message.usage.cache_creation_input_tokens};yield{type:"stream_event",event:v}}N=await E.finalMessage(),N={...N,usage:{...N.usage,cache_read_input_tokens:N.usage.cache_read_input_tokens??q?.cache_read_input_tokens??0,cache_creation_input_tokens:N.usage.cache_creation_input_tokens??q?.cache_creation_input_tokens??0}}}catch(v){if(v instanceof BI)throw v;m1(v),S1("tengu_streaming_error_fallback",{error:v instanceof Error?v.message:String(v),model:D.model}),N=await Jt(()=>PV({maxRetries:0,model:D.model,isNonInteractiveSession:D.isNonInteractiveSession}),async(g,Y1,r)=>{return K=Y1,await g.beta.messages.create(L(r))},{showErrors:!D.isNonInteractiveSession,model:D.model})}}catch(v){let n=v,g=D.model;if(v instanceof h_)n=v.originalError,g=v.retryContext.model;return _a1({error:n,model:g,messageCount:C.length,messageTokens:EN(C),durationMs:Date.now()-V,durationMsIncludingRetries:Date.now()-X,attempt:K,requestId:E?.request_id}),ya1(n,g)}if(!N||!Su0(N)){let v=_u0(N);return ya1(new Error(`Failed to get response from API${v?` (${v})`:""}`),D.model)}let{costUSD:M,durationMs:T}=ja1({response:N,start:V,startIncludingRetries:X,attempt:K,messageCount:C.length,messageTokens:EN(C),requestId:E?.request_id}),O=NW2(N);if(O)return O;return{message:{...N,content:_F1(N.content)},costUSD:M,durationMs:T,type:"assistant",uuid:VW2(),timestamp:new Date().toISOString()}}function ya1(A,B){if(A instanceof K5&&A.status===429&&p6()){let Q=A.headers?.get?.("anthropic-ratelimit-unified-reset"),I=Number(Q)||0,G=`${fa1}|${I}`;return rz({content:G})}if(A instanceof Error&&A.message.includes("prompt is too long"))return rz({content:Ct});if(A instanceof Error&&A.message.includes("Your credit balance is too low"))return rz({content:xa1});if(A instanceof Error&&A.message.toLowerCase().includes("x-api-key"))return rz({content:CX1})
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
"tengu_oauth_token_refresh_success"
|
||||
"tengu_oauth_token_refresh_failure"
|
||||
"tengu_oauth_roles_stored"
|
||||
"tengu_oauth_api_key"
|
||||
"tengu_config_add"
|
||||
"tengu_config_remove"
|
||||
"tengu_mcpjson_found"
|
||||
"tengu_config_get"
|
||||
"tengu_config_set"
|
||||
"tengu_config_delete"
|
||||
"tengu_config_list"
|
||||
"tengu_ext_jetbrains_extension_install_unknown_ide"
|
||||
"tengu_ext_jetbrains_extension_install_source_missing"
|
||||
"tengu_ext_jetbrains_extension_install_error_reading_version"
|
||||
"tengu_ext_jetbrains_extension_install_no_plugin_directories"
|
||||
"tengu_ext_jetbrains_extension_install_error_installing"
|
||||
"tengu_ext_installed"
|
||||
"tengu_ext_install_error"
|
||||
"tengu_mcp_oauth_token_refresh_success"
|
||||
"tengu_mcp_oauth_token_refresh_error"
|
||||
"tengu_mcp_servers"
|
||||
"tengu_mcp_ide_server_connection_failed"
|
||||
"tengu_mcp_ide_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_failed"
|
||||
"tengu_empty_model_response"
|
||||
"tengu_sysprompt_block"
|
||||
"tengu_context_size"
|
||||
"tengu_tool_input_json_normalized"
|
||||
"tengu_claudeai_limits_status_changed"
|
||||
"tengu_data_sharing_response_err"
|
||||
"tengu_unknown_model_cost"
|
||||
"tengu_model_cost_discount"
|
||||
"tengu_api_query"
|
||||
"tengu_api_error"
|
||||
"tengu_api_success"
|
||||
"tengu_max_tokens_context_overflow_adjustment"
|
||||
"tengu_api_retry"
|
||||
"tengu_streaming_error_fallback"
|
||||
"tengu_refusal_api_response"
|
||||
"tengu_file_changed"
|
||||
"tengu_write_claudemd"
|
||||
"tengu_binary_feedback_display_decision"
|
||||
"tengu_compact"
|
||||
"tengu_compact_failed"
|
||||
"tengu_bash_prefix"
|
||||
"tengu_git_operation"
|
||||
"tengu_claude_md_permission_error"
|
||||
"tengu_thinking"
|
||||
"tengu_batch_tool_call"
|
||||
"tengu_batch_tool_tool_use_id_missing"
|
||||
"tengu_batch_tool_message_missing"
|
||||
"tengu_at_mention_extracting_directory_success"
|
||||
"tengu_at_mention_extracting_filename_success"
|
||||
"tengu_at_mention_extracting_filename_error"
|
||||
"tengu_watched_file_changed"
|
||||
"tengu_watched_file_stat_error"
|
||||
"tengu_attachments"
|
||||
"tengu_auto_compact_succeeded"
|
||||
"tengu_post_autocompact_turn"
|
||||
"tengu_tool_use_error"
|
||||
"tengu_tool_use_cancelled"
|
||||
"tengu_tool_use_success"
|
||||
"tengu_tool_use_progress"
|
||||
"tengu_add_memory_start"
|
||||
"tengu_add_memory_failure"
|
||||
"tengu_add_memory_success"
|
||||
"tengu_message_selector_opened"
|
||||
"tengu_message_selector_selected"
|
||||
"tengu_message_selector_cancelled"
|
||||
"tengu_unary_event"
|
||||
"tengu_tool_use_show_permission_request"
|
||||
"tengu_ext_will_show_diff"
|
||||
"tengu_ext_diff_accepted"
|
||||
"tengu_ext_diff_rejected"
|
||||
"tengu_auto_accept_disabled"
|
||||
"tengu_auto_accept_enabled"
|
||||
"tengu_bug_report_submitted"
|
||||
"tengu_auto_compact_setting_changed"
|
||||
"tengu_editor_mode_changed"
|
||||
"tengu_diff_tool_changed"
|
||||
"tengu_config_changed"
|
||||
"tengu_version_config"
|
||||
"tengu_auto_updater_lock_contention"
|
||||
"tengu_auto_updater_windows_npm_in_wsl"
|
||||
"tengu_local_install_migration"
|
||||
"tengu_auto_updater_local_installation"
|
||||
"tengu_auto_updater_permissions_check"
|
||||
"tengu_auto_updater_config_start"
|
||||
"tengu_ext_ide_command"
|
||||
"tengu_oauth_automatic_redirect"
|
||||
"tengu_oauth_automatic_redirect_error"
|
||||
"tengu_preflight_check_failed"
|
||||
"tengu_began_setup"
|
||||
"tengu_onboarding_step"
|
||||
"tengu_oauth_success"
|
||||
"tengu_oauth_manual_entry"
|
||||
"tengu_oauth_token_exchange_error"
|
||||
"tengu_oauth_storage_warning"
|
||||
"tengu_oauth_user_roles_error"
|
||||
"tengu_oauth_api_key_error"
|
||||
"tengu_oauth_error"
|
||||
"tengu_oauth_claudeai_selected"
|
||||
"tengu_oauth_console_selected"
|
||||
"tengu_setup_github_actions_started"
|
||||
"tengu_setup_github_actions_failed"
|
||||
"tengu_setup_github_actions_completed"
|
||||
"tengu_install_github_app_started"
|
||||
"tengu_install_github_app_error"
|
||||
"tengu_install_github_app_completed"
|
||||
"tengu_command_dir_search"
|
||||
"tengu_auto_updater_success"
|
||||
"tengu_auto_updater_fail"
|
||||
"tengu_native_auto_updater_success"
|
||||
"tengu_native_auto_updater_fail"
|
||||
"tengu_input_bash"
|
||||
"tengu_input_memory"
|
||||
"tengu_input_slash_missing"
|
||||
"tengu_input_prompt"
|
||||
"tengu_input_command"
|
||||
"tengu_input_slash_invalid"
|
||||
"tengu_help_toggled"
|
||||
"tengu_paste_text"
|
||||
"tengu_paste_image"
|
||||
"tengu_ext_at_mentioned"
|
||||
"tengu_timer"
|
||||
"tengu_cancel"
|
||||
"tengu_tool_use_granted_in_config"
|
||||
"tengu_tool_use_denied_in_config"
|
||||
"tengu_tool_use_rejected_in_prompt"
|
||||
"tengu_tool_use_granted_in_prompt_permanent"
|
||||
"tengu_tool_use_granted_in_prompt_temporary"
|
||||
"tengu_tip_shown"
|
||||
"tengu_cost_threshold_reached"
|
||||
"tengu_cost_threshold_acknowledged"
|
||||
"tengu_mcp_multidialog_choice"
|
||||
"tengu_mcp_dialog_choice"
|
||||
"tengu_migrate_apikeyhelper_success"
|
||||
"tengu_migrate_apikeyhelper_error"
|
||||
"tengu_migrate_globalconfig_env_success"
|
||||
"tengu_migrate_globalconfig_env_error"
|
||||
"tengu_forced_migration_start"
|
||||
"tengu_forced_migration_success"
|
||||
"tengu_forced_migration_failure"
|
||||
"tengu_startup_telemetry"
|
||||
"tengu_exit"
|
||||
"tengu_exit_feedback"
|
||||
"tengu_flicker"
|
||||
"tengu_init"
|
||||
"tengu_continue"
|
||||
"tengu_mcp_start"
|
||||
"tengu_mcp_add"
|
||||
"tengu_mcp_delete"
|
||||
"tengu_mcp_list"
|
||||
"tengu_mcp_get"
|
||||
"tengu_mcp_reset_mcpjson_choices"
|
||||
"tengu_migrate_installer_command"
|
||||
"tengu_doctor_command"
|
||||
"tengu_update_check"
|
||||
"tengu_continue_print"
|
||||
"tengu_resume_print"
|
||||
File diff suppressed because one or more lines are too long
42
docs/research/claude-code-rvsource/versions/v1.0.x/README.md
Normal file
42
docs/research/claude-code-rvsource/versions/v1.0.x/README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Claude Code v1.0.128 (1.0 series)
|
||||
|
||||
## Binary RVF Container
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Version | 1.0.128 |
|
||||
| Series | 1.0 |
|
||||
| Bundle size | 8.9MB |
|
||||
| RVF size | 251.4KB |
|
||||
| Vectors | 482 |
|
||||
| RVF File ID | `689f54de1ca78a28ea7d0a38ceda5068` |
|
||||
| Classes | 1390 |
|
||||
| Functions | 16593 |
|
||||
| Modules | 9 |
|
||||
| Extracted | 2026-04-02T23:28:45+00:00 |
|
||||
|
||||
## Files
|
||||
|
||||
- `claude-code-v1.0.rvf` - Binary RVF container with HNSW index + witness chain
|
||||
- `claude-code-v1.0.rvf.manifest.json` - Container manifest (vector ID map, metadata)
|
||||
- `source/` - Extracted JavaScript module fragments
|
||||
|
||||
## RVF Container Details
|
||||
|
||||
The `.rvf` file is a real binary container created with the `@ruvector/rvf-node`
|
||||
native backend. It contains:
|
||||
|
||||
- **128-dimensional fingerprint vectors** for each code fragment
|
||||
- **HNSW index** (M=16, ef_construction=200) for fast similarity search
|
||||
- **Cosine distance** metric
|
||||
- **Witness chain** for provenance verification
|
||||
|
||||
To query this container:
|
||||
|
||||
```typescript
|
||||
import { RvfDatabase } from '@ruvector/rvf';
|
||||
|
||||
const db = await RvfDatabase.openReadonly('./claude-code-v1.0.rvf');
|
||||
const results = await db.query(queryVector, 10);
|
||||
await db.close();
|
||||
```
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,810 @@
|
|||
class Yg
|
||||
class Jg
|
||||
class lm0
|
||||
class pm0
|
||||
class Bd0
|
||||
class Hd0
|
||||
class fd0
|
||||
class cd0
|
||||
class Jc0
|
||||
class Cc0 extends Yz1
|
||||
class Ec0 extends Vg
|
||||
class Jz1 extends d4
|
||||
class u5A
|
||||
class p5A
|
||||
class t5A extends _cQ
|
||||
class Y_
|
||||
class I_
|
||||
class La extends I_
|
||||
class P41 extends I_
|
||||
class zC1 extends I_
|
||||
class Q4 extends tcQ
|
||||
class _8A extends SlQ
|
||||
class as
|
||||
class jt1
|
||||
class Wq
|
||||
class ZU1
|
||||
class r41
|
||||
class A
|
||||
class yFA extends LB9
|
||||
class bFA extends TB9
|
||||
class pFA
|
||||
class JVA extends oB9
|
||||
class extends
|
||||
class A extends Uint8Array
|
||||
class did
|
||||
class A extends Error
|
||||
class A extends zw1
|
||||
class PCA
|
||||
class bCA
|
||||
class mCA
|
||||
class A extends jL
|
||||
class A extends yB
|
||||
class A extends Ls
|
||||
class A extends XC9
|
||||
class A extends rH
|
||||
class sOA extends aOA
|
||||
class A extends Z
|
||||
class A extends WP
|
||||
class Q extends A
|
||||
class A extends v
|
||||
class A extends Oq
|
||||
class A extends vB
|
||||
class A extends Ir
|
||||
class A extends Xu9
|
||||
class A extends eH
|
||||
class PdA extends TdA
|
||||
class A extends Ad9
|
||||
class A extends HP
|
||||
class bcA extends _cA
|
||||
class Q60 extends Xl9
|
||||
class TG extends Error
|
||||
class pcA extends TG
|
||||
class icA extends TG
|
||||
class ncA extends TG
|
||||
class acA extends TG
|
||||
class scA extends TG
|
||||
class rcA extends TG
|
||||
class ocA extends TG
|
||||
class G60 extends TG
|
||||
class tcA extends G60
|
||||
class ecA extends TG
|
||||
class AlA extends TG
|
||||
class BlA extends TG
|
||||
class QlA extends TG
|
||||
class ZlA extends TG
|
||||
class GlA extends TG
|
||||
class YlA extends TG
|
||||
class IlA extends TG
|
||||
class WlA extends Error
|
||||
class JlA extends TG
|
||||
class XlA extends TG
|
||||
class FlA extends TG
|
||||
class VlA extends TG
|
||||
class Pr
|
||||
class I60
|
||||
class J60
|
||||
class glA
|
||||
class K60 extends Hp9
|
||||
class dlA extends K60
|
||||
class llA extends Dp9
|
||||
class E60
|
||||
class G
|
||||
class epA extends wi9
|
||||
class BiA
|
||||
class QiA
|
||||
class sL
|
||||
class rL
|
||||
class xiA
|
||||
class r60
|
||||
class B50
|
||||
class niA
|
||||
class ZnA extends Xs9
|
||||
class I50
|
||||
class JnA
|
||||
class qnA extends cs9
|
||||
class RnA extends ts9
|
||||
class ynA extends Jr9
|
||||
class unA extends qr9
|
||||
class pnA extends _r9
|
||||
class onA extends mr9
|
||||
class q50
|
||||
class GaA extends rr9
|
||||
class DaA extends tr9
|
||||
class T50 extends Vo9
|
||||
class jaA extends qo9
|
||||
class vaA extends xaA
|
||||
class baA extends xaA
|
||||
class faA extends Oo9
|
||||
class caA extends So9
|
||||
class saA extends _o9
|
||||
class k50 extends do9
|
||||
class p81
|
||||
class zsA
|
||||
class qsA extends Jt9
|
||||
class PsA extends Ht9
|
||||
class bsA extends kt9
|
||||
class asA extends dt9
|
||||
class tsA
|
||||
class esA extends it9
|
||||
class _L1
|
||||
class EF
|
||||
class NF
|
||||
class ErA
|
||||
class NrA
|
||||
class v3
|
||||
class V80 extends w14
|
||||
class o81 extends Event
|
||||
class s8 extends EventTarget
|
||||
class YM
|
||||
class Ex
|
||||
class XD extends Event
|
||||
class zo extends Event
|
||||
class Nx extends Event
|
||||
class toA
|
||||
class WtA
|
||||
class wtA extends qA4
|
||||
class OtA
|
||||
class x8 extends EventTarget
|
||||
class utA extends tA4
|
||||
class wo extends EventTarget
|
||||
class A extends bB
|
||||
class A extends Dt
|
||||
class A extends oJ4
|
||||
class A extends HD
|
||||
class ZG2 extends QG2
|
||||
class A extends pF4
|
||||
class A extends cP
|
||||
class A extends HA
|
||||
class A extends UD
|
||||
class DV2 extends HV2
|
||||
class A extends JE4
|
||||
class A extends aP
|
||||
class A extends fB
|
||||
class A extends st
|
||||
class A extends DM4
|
||||
class A extends ED
|
||||
class A extends iU2
|
||||
class A extends t71
|
||||
class A extends o1
|
||||
class A extends Oz
|
||||
class Z
|
||||
class Me
|
||||
class eU
|
||||
class tU
|
||||
class Dv
|
||||
class jX0 extends Error
|
||||
class LR2 extends Set
|
||||
class kX0
|
||||
class h4
|
||||
class yS1 extends cc4
|
||||
class UZ1
|
||||
class fX0 extends UZ1
|
||||
class IT2 extends UZ1
|
||||
class WT2 extends UZ1
|
||||
class _S1
|
||||
class qZ1
|
||||
class uT2
|
||||
class cT2 extends pl4
|
||||
class nT2
|
||||
class mV extends rl4
|
||||
class AP2 extends Qp4
|
||||
class ZP2 extends Zp4
|
||||
class fe extends Error
|
||||
class iP2
|
||||
class HF0
|
||||
class CF0 extends Ii4
|
||||
class lS1 extends Wi4
|
||||
class TZ1 extends Qj2
|
||||
class Ij2
|
||||
class EF0 extends Xj2
|
||||
class pS1 extends Ei4
|
||||
class Dj2
|
||||
class wj2
|
||||
class kF0 extends _i4
|
||||
class Tj2
|
||||
class kj2
|
||||
class jZ1 extends mi4
|
||||
class bj2
|
||||
class Kj extends Error
|
||||
class uF0 extends Kj
|
||||
class mF0 extends Kj
|
||||
class fj2 extends Kj
|
||||
class dF0 extends Kj
|
||||
class cF0 extends Kj
|
||||
class lF0 extends Kj
|
||||
class sS1 extends Kj
|
||||
class nF0
|
||||
class aF0 extends Error
|
||||
class ij2 extends ei4
|
||||
class sj2
|
||||
class rF0 extends tj2
|
||||
class ej2 extends Xn4
|
||||
class eF0
|
||||
class XS2
|
||||
class zS2 extends Mn4
|
||||
class BV0 extends Sn4
|
||||
class rV0
|
||||
class J_2
|
||||
class eV0
|
||||
class X_2 extends eV0
|
||||
class const
|
||||
class interface
|
||||
class constant
|
||||
class struct
|
||||
class ahk_pid
|
||||
class instance
|
||||
class type
|
||||
class reduce
|
||||
class classmethod
|
||||
class def
|
||||
class module
|
||||
class safecall
|
||||
class case
|
||||
class associate
|
||||
class default
|
||||
class double
|
||||
class family
|
||||
class defmacro
|
||||
class iter
|
||||
class object
|
||||
class instancetype
|
||||
class constraint
|
||||
class concat
|
||||
class clone
|
||||
class compile_error
|
||||
class enum
|
||||
class auth_type
|
||||
class Conj
|
||||
class untracemem
|
||||
class define
|
||||
class exit
|
||||
class cleanup
|
||||
class classutil
|
||||
class extension
|
||||
class compare
|
||||
class namespace
|
||||
class clocking
|
||||
class endclocking
|
||||
class Ym2
|
||||
class X7
|
||||
class Cm2
|
||||
class IE
|
||||
class MK0
|
||||
class Nm2 extends PB6
|
||||
class Om2 extends Mm2
|
||||
class Tm2 extends SB6
|
||||
class ym2 extends PK0
|
||||
class xm2 extends xB6
|
||||
class bm2 extends vB6
|
||||
class gm2 extends hB6
|
||||
class cm2 extends mB6
|
||||
class zd2
|
||||
class XG1
|
||||
class fv
|
||||
class od2
|
||||
class A extends uv
|
||||
class A extends hB
|
||||
class A extends g11
|
||||
class A extends jK6
|
||||
class A extends SD
|
||||
class U1B extends C1B
|
||||
class A extends LH6
|
||||
class A extends jj
|
||||
class qAB extends wAB
|
||||
class A extends sB
|
||||
class A extends eM
|
||||
class A extends Array
|
||||
class c3B
|
||||
class l3B
|
||||
class i3B
|
||||
class B
|
||||
class X extends G
|
||||
class Q extends B
|
||||
class Z extends Q
|
||||
class Z extends B
|
||||
class G extends Q
|
||||
class X extends W
|
||||
class O
|
||||
class Q
|
||||
class L
|
||||
class J extends G
|
||||
class f
|
||||
class Y extends Z
|
||||
class jVB extends Error
|
||||
class mO
|
||||
class vzB
|
||||
class Y21
|
||||
class lW1
|
||||
class sHB
|
||||
class rM0
|
||||
class eHB extends tHB
|
||||
class oM0 extends pe6
|
||||
class BDB extends ie6
|
||||
class FDB
|
||||
class LDB
|
||||
class XO0
|
||||
class FO0
|
||||
class VO0
|
||||
class KO0
|
||||
class yDB
|
||||
class vDB extends ZA5
|
||||
class lCB
|
||||
class Og1
|
||||
class Rg1
|
||||
class Tg1
|
||||
class Pg1
|
||||
class jg1
|
||||
class Sg1
|
||||
class kg1
|
||||
class IwB
|
||||
class PwB extends TwB
|
||||
class kwB extends ywB
|
||||
class sO0 extends P35
|
||||
class Bl
|
||||
class SqB
|
||||
class GH
|
||||
class cPB
|
||||
class dT0
|
||||
class p21
|
||||
class Vm1
|
||||
class FjB
|
||||
class pT0
|
||||
class i21
|
||||
class iT0 extends i21
|
||||
class nT0 extends i21
|
||||
class aT0 extends i21
|
||||
class sT0 extends i21
|
||||
class JX1
|
||||
class rT0 extends JX1
|
||||
class oT0 extends JX1
|
||||
class tT0 extends JX1
|
||||
class PjB
|
||||
class GP0
|
||||
class ujB
|
||||
class tjB
|
||||
class BSB
|
||||
class GSB
|
||||
class JSB
|
||||
class wP0
|
||||
class qP0
|
||||
class LP0
|
||||
class iSB
|
||||
class TP0
|
||||
class SP0
|
||||
class xP0
|
||||
class vP0
|
||||
class SyB
|
||||
class _yB
|
||||
class uP0
|
||||
class wm1 extends Error
|
||||
class ZkB
|
||||
class VX1
|
||||
class WkB
|
||||
class pP0
|
||||
class iP0
|
||||
class NkB
|
||||
class PkB
|
||||
class o21
|
||||
class Nm1
|
||||
class gkB
|
||||
class rkB
|
||||
class A_B
|
||||
class kmB
|
||||
class Xj0
|
||||
class imB
|
||||
class ym1 extends Error
|
||||
class EdB
|
||||
class OdB
|
||||
class ddB
|
||||
class Tl
|
||||
class idB
|
||||
class xm1
|
||||
class wX1
|
||||
class vm1
|
||||
class bm1
|
||||
class Hj0
|
||||
class Dj0
|
||||
class Cj0
|
||||
class DcB
|
||||
class wcB extends Rk5
|
||||
class McB
|
||||
class qj0
|
||||
class NX1
|
||||
class pcB
|
||||
class wlB
|
||||
class OlB
|
||||
class jlB
|
||||
class _lB
|
||||
class kj0
|
||||
class clB
|
||||
class QB1
|
||||
class olB extends QB1
|
||||
class tlB extends QB1
|
||||
class elB extends QB1
|
||||
class ApB extends QB1
|
||||
class ZB1
|
||||
class BpB extends ZB1
|
||||
class QpB extends ZB1
|
||||
class ZpB extends ZB1
|
||||
class IpB
|
||||
class FpB
|
||||
class vj0
|
||||
class zpB extends vj0
|
||||
class CpB
|
||||
class RX1
|
||||
class EpB extends Yx5
|
||||
class gj0
|
||||
class bpB
|
||||
class mpB
|
||||
class dpB
|
||||
class apB
|
||||
class tpB extends qx5
|
||||
class QiB
|
||||
class ZiB
|
||||
class GiB
|
||||
class YiB
|
||||
class JiB
|
||||
class KiB
|
||||
class CiB
|
||||
class uj0
|
||||
class qiB
|
||||
class MiB
|
||||
class PiB
|
||||
class xiB
|
||||
class hiB
|
||||
class piB
|
||||
class siB extends Error
|
||||
class ZnB
|
||||
class FnB
|
||||
class PsB
|
||||
class _sB
|
||||
class IrB extends Kh5
|
||||
class CrB extends Lh5
|
||||
class Vd1
|
||||
class XB1
|
||||
class Kd1 extends XB1
|
||||
class uS0 extends XB1
|
||||
class mS0 extends XB1
|
||||
class VB1
|
||||
class aS0 extends VB1
|
||||
class lrB
|
||||
class Dd1 extends VB1
|
||||
class vX1 extends VB1
|
||||
class Cd1 extends VB1
|
||||
class BoB
|
||||
class QoB
|
||||
class Ed1
|
||||
class WoB
|
||||
class VoB
|
||||
class EoB
|
||||
class oS0
|
||||
class MoB extends oS0
|
||||
class OoB
|
||||
class RoB
|
||||
class ToB extends RoB
|
||||
class PoB extends ToB
|
||||
class joB extends OoB
|
||||
class eE extends joB
|
||||
class SoB extends PoB
|
||||
class voB extends Gm5
|
||||
class boB extends tS0
|
||||
class foB extends tS0
|
||||
class hoB extends tS0
|
||||
class doB
|
||||
class pX1 extends Error
|
||||
class soB
|
||||
class roB
|
||||
class ooB
|
||||
class Ay0
|
||||
class toB extends Ay0
|
||||
class eoB extends Ay0
|
||||
class QtB
|
||||
class Z extends iX1
|
||||
class K1Q
|
||||
class z1Q
|
||||
class oy0
|
||||
class H1Q extends oy0
|
||||
class ty0
|
||||
class D1Q extends ty0
|
||||
class L1Q
|
||||
class _1Q
|
||||
class u1Q
|
||||
class c1Q
|
||||
class a1Q
|
||||
class s1Q
|
||||
class Yc1
|
||||
class Vk0
|
||||
class Kk0
|
||||
class W0Q
|
||||
class XF1
|
||||
class jB1 extends XF1
|
||||
class K0Q extends XF1
|
||||
class z0Q extends XF1
|
||||
class H0Q extends XF1
|
||||
class Ck0 extends np5
|
||||
class D0Q
|
||||
class L0Q
|
||||
class P0Q
|
||||
class k0Q
|
||||
class _0Q
|
||||
class x0Q
|
||||
class h0Q
|
||||
class d0Q extends hi5
|
||||
class c0Q
|
||||
class l0Q
|
||||
class p0Q
|
||||
class s0Q
|
||||
class e0Q extends ii5
|
||||
class AAQ extends Lk0
|
||||
class BAQ extends Lk0
|
||||
class QAQ extends Lk0
|
||||
class SB1
|
||||
class Tk0 extends SB1
|
||||
class Pk0 extends SB1
|
||||
class jk0 extends SB1
|
||||
class Sk0 extends SB1
|
||||
class DAQ
|
||||
class CAQ
|
||||
class UAQ
|
||||
class xk0
|
||||
class jAQ
|
||||
class vB1
|
||||
class fAQ
|
||||
class uAQ
|
||||
class cAQ
|
||||
class tAQ
|
||||
class nk0
|
||||
class sk0
|
||||
class F2Q
|
||||
class rk0
|
||||
class CF1
|
||||
class C2Q extends Ra5
|
||||
class U2Q
|
||||
class Q_0
|
||||
class I_0
|
||||
class QBQ extends ts5
|
||||
class XBQ
|
||||
class ef extends H_0
|
||||
class CBQ
|
||||
class wBQ
|
||||
class RBQ
|
||||
class SBQ
|
||||
class _BQ
|
||||
class gBQ
|
||||
class lBQ
|
||||
class aBQ
|
||||
class eBQ
|
||||
class ZQQ
|
||||
class WQQ extends yr5
|
||||
class RQQ extends Ao5
|
||||
class vQQ extends Zo5
|
||||
class __0 extends Error
|
||||
class F9Q extends __0
|
||||
class V9Q
|
||||
class K9Q
|
||||
class z9Q
|
||||
class H9Q
|
||||
class g_0 extends Kt5
|
||||
class hg0
|
||||
class jQ1
|
||||
class zu0 extends mVQ
|
||||
class Du0
|
||||
class Uu0 extends sVQ
|
||||
class mQ1
|
||||
class Bi1
|
||||
class lJ
|
||||
class fC
|
||||
class W91 extends Array
|
||||
class ni
|
||||
class iw
|
||||
class Ln1
|
||||
class aa0 extends Ln1
|
||||
class wg extends Nn1
|
||||
class Tn1 extends iw
|
||||
class Is0 extends iw
|
||||
class EV
|
||||
class uz1 extends EV
|
||||
class mz1 extends EV
|
||||
class Pn1
|
||||
class C91 extends Pn1
|
||||
class U91 extends Pn1
|
||||
class dz1 extends U91
|
||||
class ri
|
||||
class jn1
|
||||
class Xs0
|
||||
class Fs0
|
||||
class w91
|
||||
class Sn1
|
||||
class cz1 extends Sn1
|
||||
class lz1 extends Sn1
|
||||
class pN
|
||||
class oQA
|
||||
class Lr1
|
||||
class tQA extends Lr1
|
||||
class eQA extends Lr1
|
||||
class Rr1 extends Error
|
||||
class i91 extends Error
|
||||
class tN extends Error
|
||||
class XF extends Error
|
||||
class cC extends Error
|
||||
class eN extends Error
|
||||
class e3 extends Error
|
||||
class rK extends Error
|
||||
class oJ
|
||||
class Bq
|
||||
class b4
|
||||
class ew extends b4
|
||||
class ak extends b4
|
||||
class sk extends b4
|
||||
class rn extends b4
|
||||
class _g extends b4
|
||||
class Z41 extends b4
|
||||
class on extends b4
|
||||
class tn extends b4
|
||||
class xg extends b4
|
||||
class nk extends b4
|
||||
class BL extends b4
|
||||
class G41 extends b4
|
||||
class Aq extends b4
|
||||
class pZ extends b4
|
||||
class en extends b4
|
||||
class XD1 extends b4
|
||||
class Aa extends b4
|
||||
class QL extends b4
|
||||
class Y41 extends b4
|
||||
class I41 extends b4
|
||||
class vg extends b4
|
||||
class sn extends b4
|
||||
class Ba extends b4
|
||||
class Qa extends b4
|
||||
class rk extends b4
|
||||
class Za extends b4
|
||||
class bg extends b4
|
||||
class Qq extends b4
|
||||
class gH extends b4
|
||||
class PT extends b4
|
||||
class Ga extends b4
|
||||
class Ya extends b4
|
||||
class W41 extends b4
|
||||
class FD1 extends b4
|
||||
class J41 extends b4
|
||||
class Ia extends b4
|
||||
class v41
|
||||
class _C1 extends VL
|
||||
class xC1
|
||||
class g41
|
||||
class Oa
|
||||
class q5
|
||||
class pC1
|
||||
class S7A
|
||||
class PNGf
|
||||
class furl
|
||||
class _IA extends FeQ
|
||||
class de1
|
||||
class aIA
|
||||
class sIA
|
||||
class pe1 extends geQ
|
||||
class uU1 extends Map
|
||||
class MQ extends Error
|
||||
class Z4 extends MQ
|
||||
class iZ extends Z4
|
||||
class iH extends Z4
|
||||
class aT extends iH
|
||||
class H61 extends Z4
|
||||
class Iu extends Z4
|
||||
class D61 extends Z4
|
||||
class Wu extends Z4
|
||||
class C61 extends Z4
|
||||
class U61 extends Z4
|
||||
class w61 extends Z4
|
||||
class N_
|
||||
class TV
|
||||
class gWA
|
||||
class Ju
|
||||
class bV extends Error
|
||||
class R31
|
||||
class QO1 extends R31
|
||||
class P31
|
||||
class O30
|
||||
class T30 extends Error
|
||||
class P30 extends Event
|
||||
class co extends EventTarget
|
||||
class ZW extends Error
|
||||
class XO1 extends ZW
|
||||
class lo extends ZW
|
||||
class po extends ZW
|
||||
class io extends ZW
|
||||
class FO1 extends ZW
|
||||
class VO1 extends ZW
|
||||
class KO1 extends ZW
|
||||
class xx extends ZW
|
||||
class zO1 extends ZW
|
||||
class HO1 extends ZW
|
||||
class DO1 extends ZW
|
||||
class CO1 extends ZW
|
||||
class UO1 extends ZW
|
||||
class wO1 extends ZW
|
||||
class qO1 extends ZW
|
||||
class OF extends Error
|
||||
class VA2 extends Error
|
||||
class EO1
|
||||
class i30 extends TransformStream
|
||||
class NO1 extends Error
|
||||
class n30
|
||||
class no
|
||||
class dA2
|
||||
class xO1
|
||||
class uq extends dA2
|
||||
class GW
|
||||
class d31 extends GW
|
||||
class c31 extends GW
|
||||
class ro
|
||||
class l31 extends GW
|
||||
class oo extends GW
|
||||
class zD extends GW
|
||||
class bx extends GW
|
||||
class r31
|
||||
class o31 extends GW
|
||||
class mq extends GW
|
||||
class eo extends GW
|
||||
class C3
|
||||
class bP extends C3
|
||||
class WS1 extends TV
|
||||
class JS1 extends C3
|
||||
class eS1 extends C3
|
||||
class vZ1 extends Error
|
||||
class Vy1
|
||||
class Oy1 extends Error
|
||||
class Zd
|
||||
class hV0
|
||||
class Lk2 extends i91
|
||||
class QE
|
||||
class cj extends Error
|
||||
class Yx1 extends Error
|
||||
class _U0
|
||||
class Px1 extends Error
|
||||
class XY1
|
||||
class tV
|
||||
class FY1
|
||||
class fx1
|
||||
class P
|
||||
class JY1
|
||||
class yQB
|
||||
class dw0 extends Error
|
||||
class cw0 extends Error
|
||||
class Yb1 extends i91
|
||||
class WI1
|
||||
class s01
|
||||
class JN0
|
||||
class xI1
|
||||
class definition
|
||||
class Foo
|
||||
class tf1
|
||||
class xc
|
||||
class qR0 extends kLB
|
||||
class eLB
|
||||
class qu1
|
||||
class PR0
|
||||
class pS
|
||||
class QMB extends pS
|
||||
class ZMB extends pS
|
||||
class GMB extends pS
|
||||
class YMB extends pS
|
||||
class IMB extends pS
|
||||
class WMB extends pS
|
||||
class jR0 extends pS
|
||||
class SR0 extends pS
|
||||
class JMB
|
||||
class e
|
||||
class TTB
|
||||
class HPB
|
||||
class fT0
|
||||
class R_0
|
||||
class P_0
|
||||
class c_0 extends R31
|
||||
class l_0
|
||||
class jF1
|
||||
class a_0
|
||||
class s_0 extends jF1
|
||||
class r_0
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
name:"sharp",description:"High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images"
|
||||
name:"add-dir",description:"Add a new working directory"
|
||||
name:"feedback",description:"Submit feedback about Claude Code"
|
||||
name:"clear",description:"Clear conversation history and free up context"
|
||||
name:"compact",description:"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]"
|
||||
name:"config",description:"Open config panel"
|
||||
name:"context",description:"Visualize current context usage as a colored grid"
|
||||
name:"cost",description:"Show the total cost and duration of the current session"
|
||||
name:"doctor",description:"Diagnose and verify your Claude Code installation and settings"
|
||||
name:"memory",description:"Edit Claude memory files"
|
||||
name:"help",description:"Show help and available commands"
|
||||
name:"ide",description:"Manage IDE integrations and show status"
|
||||
name:"init",description:"Initialize a new CLAUDE.md file with codebase documentation"
|
||||
name:"logout",description:"Sign out from your Anthropic account"
|
||||
name:"install-github-app",description:"Set up Claude GitHub Actions for a repository"
|
||||
name:"migrate-installer",description:"Migrate from global npm installation to local installation"
|
||||
name:"mcp",description:"Manage MCP servers"
|
||||
name:"pr-comments",description:"Get comments from a GitHub pull request"
|
||||
name:"resume",description:"Resume a conversation"
|
||||
name:"review",description:"Review a pull request"
|
||||
name:"status",description:"Show Claude Code status including version, model, account, API connectivity, and tool statuses"
|
||||
name:"bashes",description:"List and manage background tasks"
|
||||
name:"todos",description:"List current todo items"
|
||||
name:"security-review",description:"Complete a security review of the pending changes on the current branch"
|
||||
name:"vim",description:"Toggle between Vim and Normal editing modes"
|
||||
name:"privacy-settings",description:"View and update your privacy settings"
|
||||
name:"hooks",description:"Manage hook configurations for tool events"
|
||||
name:"files",description:"List all files currently in context"
|
||||
name:"agents",description:"Manage agent configurations"
|
||||
name:"export",description:"Export the current conversation to a file or clipboard"
|
||||
name:"upgrade",description:"Upgrade to Max for higher rate limits and more Opus"
|
||||
name:"install",description:"Install Claude Code native build"
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
if(Array.isArray(Q.content)&&Q.content.some((Z)=>Z.type==="image"))return xA({content:Q.content,isMeta:!0});return xA({content:`Result of calling the ${A.name} tool: ${JSON.stringify(Q.content)}`,isMeta:!0})}catch{return xA({content:`Result of calling the ${A.name} tool: Error`,isMeta:!0})}}function fY1(A,B){return xA({content:`Called the ${A} tool with the following input: ${JSON.stringify(B)}`,isMeta:!0})}function A7(A,B,Q,Z){return{type:"system",subtype:"informational",content:A,isMeta:!1,timestamp:new Date().toISOString(),uuid:NE(),toolUseID:Q,level:B,...Z&&{preventContinuation:Z}}}function kv1(A,B){return{type:"system",subtype:"post_tool_hook_feedback",content:B,toolName:A,level:"info",timestamp:new Date().toISOString(),uuid:NE(),isMeta:!1}}function Z8B(A,B){return{type:"system",subtype:"compact_boundary",content:"Conversation compacted",isMeta:!1,timestamp:new Date().toISOString(),uuid:NE(),level:"info",compactMetadata:{trigger:A,preTokens:B}}}function K2B(A,B,Q,Z){return{type:"system",subtype:"api_error",level:"error",cause:A.cause instanceof Error?A.cause:void 0,error:A,retryInMs:B,retryAttempt:Q,maxRetries:Z,timestamp:new Date().toISOString(),uuid:NE()}}function td(A){return A?.type==="system"&&A.subtype==="compact_boundary"}function lT6(A){for(let B=A.length-1;B>=0;B--){let Q=A[B];if(Q&&td(Q))return B}return-1}function Mb(A){let B=lT6(A);if(B===-1)return A;return A.slice(B)}function G8B(A,B){if(A.type!=="user")return!0;if(A.isMeta)return!1;if(A.isVisibleInTranscriptOnly&&!B)return!1;return!0}async function*Y8B(A){let B=[];for await(let Q of A)if(dT6(Q.message))B.push(Q);else yield Q;for(let Q of B)yield Q}function I8B(A){if(A.type!=="assistant")return!1;if(!Array.isArray(A.message.content))return!1;return A.message.content.every((B)=>B.type==="thinking")}import{join as g21}from"path";import{basename as DH5}from"path";import{randomUUID as pT6}from"crypto";var iT6=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function mz(A){if(typeof A!=="string")return null
|
||||
|
||||
return{boundaryMarker:f,summaryMessages:y,attachments:O,hookResults:P,userDisplayMessage:F,preCompactTokenCount:Y,postCompactTokenCount:b}}catch(Y){throw cP6(Y,B),Y}finally{B.setStreamMode?.("requesting"),B.setResponseLength?.(()=>0),B.setSpinnerMessage?.(null),B.setSpinnerColor?.(null),B.setSpinnerShimmerColor?.(null)}}function cP6(A,B){if(!n91(A,nY1)&&!n91(A,iY1))B.addNotification?.({key:"error-compacting-conversation",text:"Error compacting conversation",priority:"immediate",color:"error"})}async function lP6(A,B,Q){let Z=Object.entries(A).map(([I,W])=>({filename:I,...W})).filter((I)=>!iP6(I.filename,B.agentId)).sort((I,W)=>W.timestamp-I.timestamp).slice(0,Q),G=await Promise.all(Z.map(async(I)=>{let W=await Vq0(I.filename,{...B,fileReadingLimits:{maxTokens:mP6}},"tengu_post_compact_file_restore_success","tengu_post_compact_file_restore_error","compact");return W?c01(W):null})),Y=0;return G.filter((I)=>{if(I===null)return!1;let W=J7(JSON.stringify(I));if(Y+W<=uP6)return Y+=W,!0;return!1})}function pP6(A){let B=AS(A);if(B.length===0)return null;return c01({type:"todo",content:B,itemCount:B.length,context:"post-compact"})}function iP6(A,B){let Q=hd(A);try{let Z=hd(Tb(B));if(Q===Z)return!0}catch{}try{if(new Set(x8B.map((G)=>hd(Ac(G)))).has(Q))return!0}catch{}return!1}function h8B(){let A=wZ(),B=RU0(A);return gN(A)-B}var nP6=13000,aP6=20000,sP6=20000;function BS(A){let B=h8B()-nP6,Q=Qc()?B:h8B(),Z=Math.max(0,Math.round((Q-A)/Q*100)),G=Q-aP6,Y=Q-sP6,I=A>=G,W=A>=Y,J=Qc()&&A>=B;return{percentLeft:Z,isAboveWarningThreshold:I,isAboveErrorThreshold:W,isAboveAutoCompactThreshold:J}}function Qc(){return X0().autoCompactEnabled}async function rP6(A,B){if(B==="session_memory")return!1;if(!Qc())return!1;let Q=RX(A),{isAboveAutoCompactThreshold:Z}=BS(Q);return Z}async function g8B(A,B,Q){if(!await rP6(A,Q))return{wasCompacted:!1};try{return{wasCompacted:!0,compactionResult:await pv1(A,B,!0,void 0,!0)}}catch(G){if(!n91(G,nY1))F1(G instanceof Error?G:new Error(String(G)),Nl0);return{wasCompacted:!1}}}var av1=e(J1(),1)
|
||||
|
||||
K.push({...z,message:{...z.message,content:H}})}}if(Q&&F.size>0){let z=new Map,H=new Set;for(let D of A)if((D.type==="user"||D.type==="assistant")&&Array.isArray(D.message.content)){for(let C of D.message.content)if(C.type==="tool_use"&&C.name===IZ){let w=C.input?.file_path;if(typeof w==="string")if(F.has(C.id))z.set(w,C.id);else H.add(w)}}for(let[D]of z)if(!H.has(D))Q.readFileState.delete(D)}for(let z of F)zq0.add(z);if(F.size>0)return Q1("tengu_microcompact",{toolsCompacted:F.size,totalUncompactedTokens:J,tokensAfterCompaction:J-X,tokensSaved:X,triggerType:Z?"manual":"auto"}),nv1=!0,Ij6(),{messages:K};return{messages:K}}function m8B(){let[A,B]=av1.useState(nv1);return av1.useEffect(()=>{return Yj6(()=>{B(nv1)})},[]),A}var Wj6={type:"local",name:"compact",description:"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]",isEnabled:()=>!0,isHidden:!1,supportsNonInteractive:!0,argumentHint:"<optional custom summarization instructions>",async call(A,B){let{abortController:Q,messages:Z}=B;if(Z.length===0)throw new Error("No messages to compact");let G=A.trim();try{let I=(await Pb(Z,void 0,B)).messages,W=await pv1(I,B,!1,G);GK.cache.clear?.(),OI.cache.clear?.();let J=[...B.options.verbose?[]:["(ctrl+o to see full summary)"],...W.userDisplayMessage?[W.userDisplayMessage]:[]];return{type:"compact",compactionResult:W,displayText:c1.dim("Compacted "+J.join(`
|
||||
`))}}catch(Y){if(Q.signal.aborted)throw new Error("Compaction canceled.");else if(Y instanceof Error&&Y.message===iY1)throw new Error(iY1);else throw F1(Y instanceof Error?Y:new Error(String(Y)),Sc0),new Error(`Error during compaction: ${Y}`)}},userFacingName(){return"compact"}},d8B=Wj6;var T2=e(J1(),1),Gc=e(J1(),1);var G4=e(J1(),1)
|
||||
|
||||
EA(j),Y(j),Q1("tengu_auto_compact_setting_changed",{enabled:m})}},{id:"todoFeatureEnabled",label:"Use todo list",value:C,type:"boolean",onChange:g},{id:"spinnerTipsEnabled",label:"Show tips",value:W?.spinnerTipsEnabled??!0,type:"boolean",onChange(m){B4("localSettings",{spinnerTipsEnabled:m}),J((j)=>({...j,spinnerTipsEnabled:m})),Q1("tengu_tips_setting_changed",{enabled:m})}},...f?[{id:"fileCheckpointingEnabled",label:"Checkpointing (Rewind)",value:G.fileCheckpointingEnabled,type:"boolean",onChange(m){let j={...X0(),fileCheckpointingEnabled:m};EA(j),Y(j),Q1("tengu_file_history_snapshots_setting_changed",{enabled:m})}}]:[],{id:"verbose",label:"Verbose output",value:w,type:"boolean",onChange:c},{id:"theme",label:"Theme",value:Q,type:"managedEnum",onChange:Z},{id:"notifChannel",label:"Notifications",value:G.preferredNotifChannel,options:["auto","iterm2","terminal_bell","iterm2_with_bell","kitty","ghostty","notifications_disabled"],type:"enum",onChange(m){let j={...X0(),preferredNotifChannel:m};EA(j),Y(j)}},{id:"outputStyle",label:"Output style",value:X,type:"managedEnum",onChange:()=>{}},{id:"editorMode",label:"Editor mode",value:G.editorMode==="emacs"?"normal":G.editorMode||"normal",options:["normal","vim"],type:"enum",onChange(m){let j={...X0(),editorMode:m};EA(j),Y(j),Q1("tengu_editor_mode_changed",{mode:m,source:"config_panel"})}},{id:"model",label:"Model",value:D===null?"Default (recommended)":D,type:"managedEnum",onChange:y},...B?[{id:"diffTool",label:"Diff tool",value:G.diffTool??"auto",options:["terminal","auto"],type:"enum",onChange(m){let j={...X0(),diffTool:m};EA(j),Y(j),Q1("tengu_diff_tool_changed",{tool:m,source:"config_panel"})}}]:[],...!zI()?[{id:"autoConnectIde",label:"Auto-connect to IDE (external terminal)",value:G.autoConnectIde??!1,type:"boolean",onChange(m){let j={...X0(),autoConnectIde:m}
|
||||
|
||||
if(Array.isArray(A.message.content)&&A.message.content[0]?.type==="tool_result")return!1;if(Array.isArray(A.message.content)){for(let B of A.message.content)if(B.type==="text"){let Q=B.text;if(Q.indexOf("<local-command-stdout>")!==-1||Q.indexOf("<local-command-stderr>")!==-1||Q.indexOf("<bash-stdout>")!==-1||Q.indexOf("<bash-stderr>")!==-1)return!1}}return!0}var ZXB=e(J1(),1);function Zf({message:A,messages:B,addMargin:Q,tools:Z,verbose:G,erroredToolUseIDs:Y,inProgressToolUseIDs:I,resolvedToolUseIDs:W,progressMessagesForMessage:J,shouldAnimate:X,shouldShowDot:F,style:V,width:K,isTranscriptMode:z}){let H=ZXB.useMemo(()=>{if(!hU1().alwaysThinking)return!1;let C=B.findIndex((b)=>b===A);if(C===-1)return!1;let L=B.slice(0,C).filter(QXB).at(-1),E=L?.thinkingMetadata?.level,T=!L?.thinkingMetadata?.disabled&&E&&E!=="none",P=!!process.env.MAX_THINKING_TOKENS;return!T&&!P},[B,A]);switch(A.type){case"attachment":return O8.createElement(aJB,{addMargin:Q,attachment:A.attachment,verbose:G});case"assistant":return O8.createElement(S,{flexDirection:"column",width:"100%"},A.message.content.map((D,C)=>O8.createElement(af6,{key:C,param:D,addMargin:Q,tools:Z,verbose:G,erroredToolUseIDs:Y,inProgressToolUseIDs:I,resolvedToolUseIDs:W,progressMessagesForMessage:J,shouldAnimate:X,shouldShowDot:F,width:K,inProgressToolCallCount:I.size,isTranscriptMode:z,shouldHideExperimentThinking:H})));case"user":return O8.createElement(S,{flexDirection:"column",width:"100%"},A.message.content.map((D,C)=>O8.createElement(nf6,{key:C,message:A,messages:B,addMargin:Q,tools:Z,progressMessagesForMessage:J,param:D,style:V,verbose:G})));case"system":if(A.subtype==="compact_boundary")return O8.createElement(rJB,null);if(A.subtype==="post_tool_hook_feedback")return O8.createElement(oJB,{message:A,verbose:G});if(A.subtype==="local_command")return O8.createElement(FW1,{addMargin:Q,param:{type:"text",text:A.content},verbose:G})
|
||||
|
||||
return O8.createElement(if1,{message:A,addMargin:Q,verbose:G})}}function nf6({message:A,messages:B,addMargin:Q,tools:Z,progressMessagesForMessage:G,param:Y,style:I,verbose:W}){let{columns:J}=IB();switch(Y.type){case"text":return O8.createElement(FW1,{addMargin:Q,param:Y,verbose:W,thinkingMetadata:A.thinkingMetadata});case"tool_result":return O8.createElement(yJB,{param:Y,message:A,messages:B,progressMessagesForMessage:G,style:I,tools:Z,verbose:W,width:J-5});default:return}}function af6({param:A,addMargin:B,tools:Q,verbose:Z,erroredToolUseIDs:G,inProgressToolUseIDs:Y,resolvedToolUseIDs:I,progressMessagesForMessage:W,shouldAnimate:J,shouldShowDot:X,width:F,inProgressToolCallCount:V,isTranscriptMode:K,shouldHideExperimentThinking:z}){switch(A.type){case"tool_use":return O8.createElement(vJB,{param:A,addMargin:B,tools:Q,verbose:Z,erroredToolUseIDs:G,inProgressToolUseIDs:Y,resolvedToolUseIDs:I,progressMessagesForMessage:W,shouldAnimate:J,shouldShowDot:X,inProgressToolCallCount:V});case"text":return O8.createElement(bJB,{param:A,addMargin:B,shouldShowDot:X,width:F});case"redacted_thinking":if(z)return null;return O8.createElement(iJB,{addMargin:B});case"thinking":if(z)return null;return O8.createElement(pJB,{addMargin:B,param:A,isTranscriptMode:K});default:return F1(new Error(`Unable to render message type: ${A.type}`),Al0),null}}import{randomUUID as sf6}from"crypto";function vE(A){return A.flatMap((B)=>{switch(B.type){case"assistant":return[{type:"assistant",message:B.message,uuid:B.uuid,requestId:void 0,timestamp:new Date().toISOString()}];case"user":return[{type:"user",message:B.message,uuid:B.uuid??sf6(),timestamp:new Date().toISOString(),isMeta:B.isSynthetic}];case"system":if(B.subtype==="compact_boundary"){let Q=B;return[{type:"system",content:"Conversation compacted",level:"info",subtype:"compact_boundary",compactMetadata:{trigger:Q.compact_metadata.trigger,preTokens:Q.compact_metadata.pre_tokens},uuid:B.uuid,timestamp:new Date().toISOString()}]}return[]
|
||||
|
||||
default:return[]}})}function GXB(A){return A.flatMap((B)=>{switch(B.type){case"assistant":return[{type:"assistant",message:B.message,session_id:W2(),parent_tool_use_id:null,uuid:B.uuid}];case"user":return[{type:"user",message:B.message,session_id:W2(),parent_tool_use_id:null,uuid:B.uuid,isSynthetic:B.isMeta||B.isVisibleInTranscriptOnly}];case"system":if(B.subtype==="compact_boundary"&&B.compactMetadata)return[{type:"system",subtype:"compact_boundary",session_id:W2(),uuid:B.uuid,compact_metadata:{trigger:B.compactMetadata.trigger,pre_tokens:B.compactMetadata.preTokens}}];return[];default:return[]}})}function YXB({session:A,toolUseContext:B,onDone:Q}){let[Z,G]=KW1.useState(!1),[Y,I]=KW1.useState(null);i0((K,z)=>{if(z.escape||z.return||K===" ")Q("Remote session details dismissed",{display:"system"});else if(K==="t"&&!Z)J()});let W=pA();async function J(){G(!0),I(null);try{await ZW1(A.id,async(K)=>{I(K.message),G(!1)})}catch(K){I(K instanceof Error?K.message:String(K)),G(!1)}}let X=(K)=>{let z=Math.floor((Date.now()-K)/1000),H=Math.floor(z/3600),D=Math.floor((z-H*3600)/60),C=z-H*3600-D*60;return`${H>0?`${H}h `:""}${D>0||H>0?`${D}m `:""}${C}s`},F=KW1.useMemo(()=>{return MI(vE(A.log.slice(-3))).filter((K)=>K.type!=="progress")},[A]),V=A.title.length>50?A.title.substring(0,47)+"...":A.title
|
||||
|
||||
function xXB({selectedHook:A,eventSupportsMatcher:B,onDelete:Q,onCancel:Z}){return L3.createElement(L3.Fragment,null,L3.createElement(S,{flexDirection:"column",borderStyle:"round",paddingLeft:1,paddingRight:1,borderColor:"error",gap:1},L3.createElement(M,{bold:!0,color:"error"},"Delete hook?"),L3.createElement(S,{flexDirection:"column",marginX:2},L3.createElement(M,{bold:!0},A.config.command),L3.createElement(M,{dimColor:!0},"Event: ",A.event),B&&L3.createElement(M,{dimColor:!0},"Matcher: ",A.matcher),L3.createElement(M,{dimColor:!0},LXB(A.source))),L3.createElement(M,null,"This will remove the hook configuration from your settings."),L3.createElement(jA,{onChange:(G)=>G==="yes"?Q():Z(),onCancel:Z,options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]})),L3.createElement(S,{marginLeft:3},L3.createElement(M,{dimColor:!0},"Enter to confirm · Esc to cancel")))}var HW1=AA(function(A){return{PreToolUse:{summary:"Before tool execution",description:`Input to command is JSON of tool call arguments.
|
||||
Exit code 0 - stdout/stderr not shown
|
||||
Exit code 2 - show stderr to model and block tool call
|
||||
Other exit codes - show stderr to user only but continue with tool call`,matcherMetadata:{fieldToMatch:"tool_name",values:A}},PostToolUse:{summary:"After tool execution",description:`Input to command is JSON with fields "inputs" (tool call arguments) and "response" (tool call response).
|
||||
Exit code 0 - stdout shown in transcript mode (Ctrl-O)
|
||||
Exit code 2 - show stderr to model immediately
|
||||
Other exit codes - show stderr to user only`,matcherMetadata:{fieldToMatch:"tool_name",values:A}},Notification:{summary:"When notifications are sent",description:""},UserPromptSubmit:{summary:"When the user submits a prompt",description:`Input to command is JSON with original user prompt text.
|
||||
Exit code 0 - stdout shown to Claude
|
||||
Exit code 2 - block processing, erase original prompt, and show stderr to user only
|
||||
Other exit codes - show stderr to user only`},SessionStart:{summary:"When a new session is started",description:`Input to command is JSON with session start source.
|
||||
Exit code 0 - stdout shown to Claude
|
||||
Blocking errors are ignored
|
||||
Other exit codes - show stderr to user only`,matcherMetadata:{fieldToMatch:"source",values:["startup","resume","clear","compact"]}},Stop:{summary:"Right before Claude concludes its response",description:`Exit code 0 - stdout/stderr not shown
|
||||
Exit code 2 - show stderr to model and continue conversation
|
||||
Other exit codes - show stderr to user only`},SubagentStop:{summary:"Right before a subagent (Task tool call) concludes its response",description:`Exit code 0 - stdout/stderr not shown
|
||||
Exit code 2 - show stderr to subagent and continue having it run
|
||||
Other exit codes - show stderr to user only`},PreCompact:{summary:"Before conversation compaction",description:`Input to command is JSON with compaction details.
|
||||
Exit code 0 - stdout appended as custom compact instructions
|
||||
Exit code 2 - block compaction
|
||||
Other exit codes - show stderr to user only but continue with compaction`,matcherMetadata:{fieldToMatch:"trigger",values:["manual","auto"]}},SessionEnd:{summary:"When a session is ending",description:`Input to command is JSON with session end reason.
|
||||
Exit code 0 - command completes successfully
|
||||
Other exit codes - show stderr to user only`,matcherMetadata:{fieldToMatch:"reason",values:["clear","logout","prompt_input_exit","other"]}}}})
|
||||
|
||||
case"local":{let F=xA({content:uz({inputString:ML0(X,B),precedingInputBlocks:G}),autocheckpoint:I});try{let V=aF(),K=await X.call(B,Z);if(!Z.options.isNonInteractiveSession)process.stdout.write("\x1B[?25l");if(K.type==="compact"){let{boundaryMarker:z,summaryMessages:H,attachments:D,hookResults:C}=K.compactionResult;return{messages:[z,...H,V,F,...K.displayText?[xA({content:`<local-command-stdout>${K.displayText}</local-command-stdout>`,autocheckpoint:I,timestampOverride:new Date(Date.now()+100)})]:[],...D,...C],shouldQuery:!1,command:X}}return{messages:[F,xA({content:`<local-command-stdout>${K.value}</local-command-stdout>`})],shouldQuery:!1,command:X}}catch(V){return F1(V,zi0),{messages:[F,xA({content:`<local-command-stderr>${String(V)}</local-command-stderr>`})],shouldQuery:!1,command:X}}}case"prompt":try{return await sFB(X,B,Z,G,Y,I,J)}catch(F){return{messages:[xA({content:uz({inputString:ML0(X,B),precedingInputBlocks:G}),autocheckpoint:I}),xA({content:`<local-command-stderr>${String(F)}</local-command-stderr>`})],shouldQuery:!1,command:X}}}}catch(F){if(F instanceof tN)return{messages:[xA({content:uz({inputString:F.message,precedingInputBlocks:G}),autocheckpoint:I})],shouldQuery:!1,command:X};throw F}}function ML0(A,B){return`<command-name>/${A.userFacingName()}</command-name>
|
||||
<command-message>${A.userFacingName()}</command-message>
|
||||
<command-args>${B}</command-args>`}async function aFB(A,B,Q,Z,G=[]){if(!MW1(A,Q))throw new tN(`Unknown command: ${A}`);let Y=bc(A,Q);if(Y.type!=="prompt")throw new Error(`Unexpected ${Y.type} command. Expected 'prompt' command. Use /${A} directly in the main conversation.`)
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
var cB4=_.object({type:_.literal("ref/prompt"),name:_.string()}).passthrough(),lB4=wz.extend({method:_.literal("completion/complete"),params:yU.extend({ref:_.union([cB4,dB4]),argument:_.object({name:_.string(),value:_.string()}).passthrough(),context:_.optional(_.object({arguments:_.optional(_.record(_.string(),_.string()))}))})}),o80=kU.extend({completion:_.object({values:_.array(_.string()).max(100),total:_.optional(_.number().int()),hasMore:_.optional(_.boolean())}).passthrough()}),pB4=_.object({uri:_.string().startsWith("file://"),name:_.optional(_.string()),_meta:_.optional(_.object({}).passthrough())}).passthrough(),t80=wz.extend({method:_.literal("roots/list")}),e80=kU.extend({roots:_.array(pB4)}),iB4=XM.extend({method:_.literal("notifications/roots/list_changed")}),_a8=_.union([_M1,g80,lB4,SB4,NB4,EB4,KB4,zB4,HB4,CB4,UB4,a80,n80]),xa8=_.union([yM1,xM1,kM1,iB4]),va8=_.union([kP,s80,r80,e80]),ba8=_.union([_M1,vB4,mB4,t80]),fa8=_.union([yM1,xM1,yB4,$B4,DB4,jB4,RB4]),ha8=_.union([kP,u80,o80,i80,M31,zm,d80,L31,bo,O31]);class bV extends Error{constructor(A,B,Q){super(`MCP error ${A}: ${B}`);this.code=A,this.data=Q,this.name="McpError"}}var nB4=60000;class R31{constructor(A){this._options=A,this._requestMessageId=0,this._requestHandlers=new Map,this._requestHandlerAbortControllers=new Map,this._notificationHandlers=new Map,this._responseHandlers=new Map,this._progressHandlers=new Map,this._timeoutInfo=new Map,this._pendingDebouncedNotifications=new Set,this.setNotificationHandler(yM1,(B)=>{let Q=this._requestHandlerAbortControllers.get(B.params.requestId);Q===null||Q===void 0||Q.abort(B.params.reason)}),this.setNotificationHandler(xM1,(B)=>{this._onprogress(B)}),this.setRequestHandler(_M1,(B)=>({}))}_setupTimeout(A,B,Q,Z,G=!1){this._timeoutInfo.set(A,{timeoutId:setTimeout(Z,B),startTime:Date.now(),timeout:B,maxTotalTimeout:Q,resetTimeoutOnProgress:G,onTimeout:Z})}_resetTimeout(A){let B=this._timeoutInfo.get(A);if(!B)return!1;let Q=Date.now()-B.startTime
|
||||
|
||||
case"notifications/progress":break}}assertRequestHandlerCapability(A){switch(A){case"sampling/createMessage":if(!this._capabilities.sampling)throw new Error(`Client does not support sampling capability (required for ${A})`);break;case"elicitation/create":if(!this._capabilities.elicitation)throw new Error(`Client does not support elicitation capability (required for ${A})`);break;case"roots/list":if(!this._capabilities.roots)throw new Error(`Client does not support roots capability (required for ${A})`);break;case"ping":break}}async ping(A){return this.request({method:"ping"},kP,A)}async complete(A,B){return this.request({method:"completion/complete",params:A},o80,B)}async setLoggingLevel(A,B){return this.request({method:"logging/setLevel",params:{level:A}},kP,B)}async getPrompt(A,B){return this.request({method:"prompts/get",params:A},i80,B)}async listPrompts(A,B){return this.request({method:"prompts/list",params:A},M31,B)}async listResources(A,B){return this.request({method:"resources/list",params:A},zm,B)}async listResourceTemplates(A,B){return this.request({method:"resources/templates/list",params:A},d80,B)}async readResource(A,B){return this.request({method:"resources/read",params:A},L31,B)}async subscribeResource(A,B){return this.request({method:"resources/subscribe",params:A},kP,B)}async unsubscribeResource(A,B){return this.request({method:"resources/unsubscribe",params:A},kP,B)}async callTool(A,B=bo,Q){let Z=await this.request({method:"tools/call",params:A},B,Q),G=this.getToolOutputValidator(A.name);if(G){if(!Z.structuredContent&&!Z.isError)throw new bV(vV.InvalidRequest,`Tool ${A.name} has an output schema but did not return structured content`);if(Z.structuredContent)try{if(!G(Z.structuredContent))throw new bV(vV.InvalidParams,`Structured content does not match the tool's output schema: ${this._ajv.errorsText(G.errors)}`)}catch(Y){if(Y instanceof bV)throw Y
|
||||
|
||||
throw new bV(vV.InvalidParams,`Failed to validate structured content: ${Y instanceof Error?Y.message:String(Y)}`)}}return Z}cacheToolOutputSchemas(A){this._cachedToolOutputValidators.clear();for(let B of A)if(B.outputSchema)try{let Q=this._ajv.compile(B.outputSchema);this._cachedToolOutputValidators.set(B.name,Q)}catch(Q){}}getToolOutputValidator(A){return this._cachedToolOutputValidators.get(A)}async listTools(A,B){let Q=await this.request({method:"tools/list",params:A},O31,B);return this.cacheToolOutputSchemas(Q.tools),Q}async sendRootsListChanged(){return this.notification({method:"notifications/roots/list_changed"})}}var t02=e(Dr1(),1);import GO1 from"node:process";import{PassThrough as T94}from"node:stream";class P31{append(A){this._buffer=this._buffer?Buffer.concat([this._buffer,A]):A}readMessage(){if(!this._buffer)return null;let A=this._buffer.indexOf(`
|
||||
`);if(A===-1)return null;let B=this._buffer.toString("utf8",0,A).replace(/\r$/,"");return this._buffer=this._buffer.subarray(A+1),R94(B)}clear(){this._buffer=void 0}}function R94(A){return FM.parse(JSON.parse(A))}function ZO1(A){return JSON.stringify(A)+`
|
||||
`}var P94=GO1.platform==="win32"?["APPDATA","HOMEDRIVE","HOMEPATH","LOCALAPPDATA","PATH","PROCESSOR_ARCHITECTURE","SYSTEMDRIVE","SYSTEMROOT","TEMP","USERNAME","USERPROFILE","PROGRAMFILES"]:["HOME","LOGNAME","PATH","SHELL","TERM","USER"];function j94(){let A={};for(let B of P94){let Q=GO1.env[B];if(Q===void 0)continue;if(Q.startsWith("()"))continue;A[B]=Q}return A}class O30{constructor(A){if(this._abortController=new AbortController,this._readBuffer=new P31,this._stderrStream=null,this._serverParams=A,A.stderr==="pipe"||A.stderr==="overlapped")this._stderrStream=new T94}async start(){if(this._process)throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");return new Promise((A,B)=>{var Q,Z,G,Y,I
|
||||
|
||||
return delete Q[B],Q}function eS2(A){return`mcp__${RD(A)}__`}function NV0(A){return A.name?.startsWith("mcp__")||A.isMcp===!0}function Ov(A){let B=A.split("__"),[Q,Z,...G]=B;if(Q!=="mcp"||!Z)return null;let Y=G.length>0?G.join("__"):void 0;return{serverName:Z,toolName:Y}}function Xy1(A,B){let Q=`mcp__${RD(B)}__`;return A.replace(Q,"")}function Fy1(A){let B=A.replace(/\s*\(MCP\)\s*$/,"");B=B.trim();let Q=B.indexOf(" - ");if(Q!==-1)return B.substring(Q+3).trim();return B}function TD(A){let B=H1();switch(A){case"user":{let Q=sJ(),Z=B.existsSync(Q);return`${Q}${Z?"":" (file does not exist)"}`}case"project":{let Q=Bs4(e0(),".mcp.json"),Z=B.existsSync(Q);return`${Q}${Z?"":" (file does not exist)"}`}case"local":return`${sJ()} [project: ${e0()}]`;case"dynamic":return"Dynamically configured";case"enterprise":{let Q=Iy1(),Z=B.existsSync(Q);return`${Q}${Z?"":" (file does not exist)"}`}default:return A}}function Bd(A){switch(A){case"local":return"Local config (private to you in this project)";case"project":return"Project config (shared via .mcp.json)";case"user":return"User config (available in all your projects)";case"dynamic":return"Dynamic config (from command line)";case"enterprise":return"Enterprise config (managed by your organization)";default:return A}}function dZ1(A){if(!A)return"local";if(!zV0.options.includes(A))throw new Error(`Invalid scope: ${A}. Must be one of: ${zV0.options.join(", ")}`);return A}function Ay2(A){if(!A)return"stdio";if(A!=="stdio"&&A!=="sse"&&A!=="http")throw new Error(`Invalid transport type: ${A}. Must be one of: stdio, sse, http`);return A}function LV0(A){let B={};for(let Q of A){let Z=Q.indexOf(":");if(Z===-1)throw new Error(`Invalid header format: "${Q}". Expected format: "Header-Name: value"`);let G=Q.substring(0,Z).trim(),Y=Q.substring(Z+1).trim();if(!G)throw new Error(`Invalid header: "${Q}". Header name cannot be empty.`);B[G]=Y}return B}function Wy1(A){let B=U2(),Q=RD(A);if(B?.disabledMcpjsonServers?.some((Z)=>RD(Z)===Q))return"rejected"
|
||||
|
||||
if(B?.enabledMcpjsonServers?.some((Z)=>RD(Z)===Q)||B?.enableAllProjectMcpServers)return"approved";return"pending"}_41();class Vy1{ws;started=!1;opened;constructor(A){this.ws=A;this.opened=new Promise((B,Q)=>{if(this.ws.readyState===FL.OPEN)B();else this.ws.on("open",()=>{B()}),this.ws.on("error",(Z)=>{Q(Z)})}),this.ws.on("message",this.onMessageHandler),this.ws.on("error",this.onErrorHandler),this.ws.on("close",this.onCloseHandler)}onclose;onerror;onmessage;onMessageHandler=(A)=>{try{let B=JSON.parse(A.toString("utf-8")),Q=FM.parse(B);this.onmessage?.(Q)}catch(B){this.onErrorHandler(B)}};onErrorHandler=(A)=>{this.onerror?.(A instanceof Error?A:new Error("Failed to process message"))};onCloseHandler=()=>{this.onclose?.(),this.ws.off("message",this.onMessageHandler),this.ws.off("error",this.onErrorHandler),this.ws.off("close",this.onCloseHandler)};async start(){if(this.started)throw new Error("Start can only be called once per transport.");if(await this.opened,this.ws.readyState!==FL.OPEN)throw new Error("WebSocket is not open. Cannot start transport.");this.started=!0}async close(){if(this.ws.readyState===FL.OPEN||this.ws.readyState===FL.CONNECTING)this.ws.close();this.onCloseHandler()}async send(A){if(this.ws.readyState!==FL.OPEN)throw new Error("WebSocket is not open. Cannot send message.");let B=JSON.stringify(A);try{await new Promise((Q,Z)=>{this.ws.send(B,(G)=>{if(G)Z(G);else Q()})})}catch(Q){throw this.onErrorHandler(Q),Q}}}var By2="",Qy2="";var o8=e(J1(),1);var cZ1=e(J1(),1);var hM=e(J1(),1);function gM(){return hM.createElement(hM.Fragment,null,hM.createElement(M,{color:"error"},"Interrupted "),hM.createElement(M,{dimColor:!0},"· What should Claude do instead?"))}function r8(){return cZ1.createElement(qA,{height:1},cZ1.createElement(gM,null))}var LX=e(J1(),1);var lZ1=e(J1(),1),Vy2=e(J1(),1);var Gy2=e(J1(),1);var Ky1=[],MV0={columns:process.stdout.columns||80,rows:process.stdout.rows||24},Zy2=!1;function Qs4(){if(Zy2||!process.stdout.isTTY)return
|
||||
|
||||
if(typeof Z!=="object"||Z===null||Array.isArray(Z))throw new Error(`headersHelper for MCP server '${A}' must return a JSON object with string key-value pairs`);for(let[G,Y]of Object.entries(Z))if(typeof Y!=="string")throw new Error(`headersHelper for MCP server '${A}' returned non-string value for key "${G}": ${typeof Y}`);return JA(A,`Successfully retrieved ${Object.keys(Z).length} headers from headersHelper`),Z}catch(Q){return QG(A,`Error getting headers from headersHelper: ${Q instanceof Error?Q.message:String(Q)}`),F1(new Error(`Error getting MCP headers from headersHelper for server '${A}': ${Q instanceof Error?Q.message:String(Q)}`),Kn0),null}}function Ry1(A,B){let Q=B.headers||{},Z=ar4(A,B)||{};return{...Q,...Z}}class hV0{serverName;sendMcpMessage;isClosed=!1;onclose;onerror;onmessage;constructor(A,B){this.serverName=A;this.sendMcpMessage=B}async start(){}async send(A){if(this.isClosed)throw new Error("Transport is closed");let B=await this.sendMcpMessage(this.serverName,A);if(this.onmessage)this.onmessage(B)}async close(){if(this.isClosed)return;this.isClosed=!0,this.onclose?.()}}var sr4=new Set(["image/jpeg","image/png","image/gif","image/webp"]);function rr4(){return parseInt(process.env.MCP_TOOL_TIMEOUT||"",10)||1e8}function Ty1(){return parseInt(process.env.MCP_TIMEOUT||"",10)||30000}function or4(){return parseInt(process.env.MCP_SERVER_CONNECTION_BATCH_SIZE||"",10)||3}var tr4=["mcp__ide__executeCode","mcp__ide__getDiagnostics"];function er4(A){return!A.name.startsWith("mcp__ide__")||tr4.includes(A.name)}function Ck2(A,B){return`${A}-${JSON.stringify(B)}`}var te=AA(async(A,B,Q)=>{let Z=Date.now();try{let G,Y=Um();if(B.type==="sse"){let E=new Zd(A,B),O=Ry1(A,B),T={authProvider:E,requestInit:{headers:{"User-Agent":Jm(),...O},signal:AbortSignal.timeout(60000)}};if(Object.keys(O).length>0)T.eventSourceInit={fetch:async(P,b)=>{let f={},y=await E.tokens();if(y)f.Authorization=`Bearer ${y.access_token}`;let c=Ym()
|
||||
|
||||
if(Z.type==="connected")await Z.cleanup()}catch{}te.cache.delete(Q)}var gV0=AA(async(A)=>{if(A.type!=="connected")return[];try{if(!A.capabilities?.tools)return[];let B=await A.client.request({method:"tools/list"},O31);return(await $I("claude_code_unicode_sanitize")?so(B.tools):B.tools).map((G)=>({...Uy2,name:`mcp__${RD(A.name)}__${RD(G.name)}`,isMcp:!0,async description(){return G.description??""},async prompt(){return G.description??""},isConcurrencySafe(){return G.annotations?.readOnlyHint??!1},isReadOnly(){return G.annotations?.readOnlyHint??!1},isDestructive(){return G.annotations?.destructiveHint??!1},isOpenWorld(){return G.annotations?.openWorldHint??!1},inputJSONSchema:G.inputSchema,async*call(Y,I,W,J){let X=Bo4(J),F=X?{"claudecode/toolUseId":X}:{};yield{type:"result",data:await Ek2({client:A,tool:G.name,args:Y,meta:F,signal:I.abortController.signal})}},userFacingName(){let Y=G.annotations?.title||G.name;return`${A.name} - ${Y} (MCP)`}})).filter(er4)}catch(B){return QG(A.name,`Failed to fetch tools: ${B instanceof Error?B.message:String(B)}`),[]}}),Uk2=AA(async(A)=>{if(A.type!=="connected")return[];try{if(!A.capabilities?.resources)return[];let B=await A.client.request({method:"resources/list"},zm);if(!B.resources)return[];return B.resources.map((Q)=>({...Q,server:A.name}))}catch(B){return QG(A.name,`Failed to fetch resources: ${B instanceof Error?B.message:String(B)}`),[]}}),$k2=AA(async(A)=>{if(A.type!=="connected")return[];let B=A;try{if(!A.capabilities?.prompts)return[];let Q=await A.client.request({method:"prompts/list"},M31);if(!Q.prompts)return[];return(await $I("claude_code_unicode_sanitize")?so(Q.prompts):Q.prompts).map((Y)=>{let I=Object.values(Y.arguments??{}).map((W)=>W.name);return{type:"prompt",name:"mcp__"+RD(B.name)+"__"+Y.name,description:Y.description??"",hasUserSpecifiedDescription:!!Y.description,isEnabled:()=>!0,isHidden:!1,isMcp:!0,progressMessage:"running",userFacingName(){let W=Y.title||Y.name
|
||||
|
||||
A({client:z,tools:[...D,...L],commands:C,resources:w.length>0?w:void 0})}catch(K){QG(F,`Error fetching tools/commands/resources: ${K instanceof Error?K.message:String(K)}`),A({client:{name:F,type:"failed",config:V},tools:[],commands:[]})}})}var wk2=AA(async(A)=>{return new Promise((B)=>{let Q=0,Z=0;if(Q=Object.keys(A).length,Q===0){B({clients:[],tools:[],commands:[]});return}let G=[],Y=[],I=[];mV0((W)=>{if(G.push(W.client),Y.push(...W.tools),I.push(...W.commands),Z++,Z>=Q){let J=I.reduce((X,F)=>{let V=F.name.length+(F.description??"").length+(F.argumentHint??"").length;return X+V},0);Q1("tengu_mcp_tools_commands_loaded",{tools_count:Y.length,commands_count:I.length,commands_metadata_length:J}),B({clients:G,tools:Y,commands:I})}},A).catch((W)=>{QG("prefetchAllMcpResources",`Failed to get MCP resources: ${W instanceof Error?W.message:String(W)}`),B({clients:[],tools:[],commands:[]})})})});function qk2(A,B){switch(A.type){case"text":return[{type:"text",text:A.text}];case"image":return[{type:"image",source:{data:String(A.data),media_type:A.mimeType||"image/jpeg",type:"base64"}}];case"resource":{let Q=A.resource,Z=`[Resource from ${B} at ${Q.uri}] `;if("text"in Q)return[{type:"text",text:`${Z}${Q.text}`}];else if("blob"in Q)if(sr4.has(Q.mimeType??"")){let Y=[];if(Z)Y.push({type:"text",text:Z});return Y.push({type:"image",source:{data:Q.blob,media_type:Q.mimeType||"image/jpeg",type:"base64"}}),Y}else return[{type:"text",text:`${Z}Base64 data (${Q.mimeType||"unknown type"}) ${Q.blob}`}];return[]}case"resource_link":{let Q=A,Z=`[Resource link: ${Q.name}] ${Q.uri}`;if(Q.description)Z+=` (${Q.description})`;return[{type:"text",text:Z}]}default:return[]}}async function Ek2({client:{client:A,name:B},tool:Q,args:Z,meta:G,signal:Y}){let I=Date.now(),W;try{JA(B,`Calling MCP tool: ${Q}`),W=setInterval(()=>{let K=Date.now()-I,H=`${Math.floor(K/1000)}s`;JA(B,`Tool '${Q}' still running (${H} elapsed)`)},30000);let J=await A.callTool({name:Q,arguments:Z,_meta:G},bo,{signal:Y,timeout:rr4()})
|
||||
|
||||
Z((V)=>({...V,mcp:{...V.mcp,clients:Object.entries(G).map(([K,z])=>({name:K,type:"pending",config:z})),tools:[],commands:[],resources:{}}}))},[G,I,Z]);let J=yE.useCallback((V,K=[],z=[],H)=>{Z((D)=>{let C=eS2(V.name);return{...D,mcp:{...D.mcp,clients:D.mcp.clients.map((w)=>w.name===V.name?V:w),tools:[...BK1(D.mcp.tools,(w)=>w.name?.startsWith(C)),...K],commands:[...BK1(D.mcp.commands,(w)=>w.name?.startsWith(C)),...z],resources:{...D.mcp.resources,...H&&H.length>0?{[V.name]:H}:nl1(D.mcp.resources,V.name)}}}})},[Z]),X=yE.useCallback(({client:V,tools:K,commands:z,resources:H})=>{switch(J(V,K,z,H),V.type){case"connected":{V.client.onclose=()=>{if(nZ1(V.name,V.config).catch(()=>{o(`Failed to invalidate the server cache: ${V.name}`)}),V.config.type==="sse"||V.config.type==="http"||V.config.type==="sse-ide"){let D=V.config.type==="http"?"HTTP":"SSE";JA(V.name,`${D} transport closed/disconnected, attempting automatic reconnection`),J({...V,type:"pending"});let C=Date.now();uV0(V.name,V.config).then((w)=>{let L=Date.now()-C;if(w.client.type==="connected")JA(V.name,`${D} reconnection successful after ${L}ms`);else JA(V.name,`${D} reconnection attempt completed with status: ${w.client.type}`);X(w)}).catch((w)=>{let L=Date.now()-C;QG(V.name,`${D} reconnection failed after ${L}ms: ${w}`),J({...V,type:"failed"})})}else J({...V,type:"failed"})};break}case"needs-auth":case"failed":case"pending":break}},[J]);return yE.useEffect(()=>{if(!I||Object.keys(G).length===0)return;mV0(X,G).catch((V)=>{QG("useManageMcpConnections",`Failed to get MCP resources: ${V instanceof Error?V.message:String(V)}`)})},[G,I,X]),{reconnectMcpServer:yE.useCallback(async(V)=>{let K=Q.mcp.clients.find((H)=>H.name===V);if(!K)throw new Error(`MCP server ${V} not found`);let z=await uV0(V,K.config);return X(z),z},[Q.mcp.clients,X])}}var nWB=Bf.createContext(null);function fA1(){let A=Bf.useContext(nWB);if(!A)throw new Error("useMcpReconnect must be used within MCPConnectionManager")
|
||||
|
||||
return A.reconnectMcpServer}function vf1({children:A,dynamicMcpConfig:B,isStrictMcpConfig:Q}){let{reconnectMcpServer:Z}=iWB(B,Q),G=Bf.useMemo(()=>({reconnectMcpServer:Z}),[Z]);return Bf.default.createElement(nWB.Provider,{value:G},A)}function bf1(A,B){switch(A.client.type){case"connected":return{message:`Reconnected to ${B}.`,success:!0};case"needs-auth":return{message:`${B} requires authentication. Use the 'Authenticate' option.`,success:!1};case"failed":return{message:`Failed to reconnect to ${B}.`,success:!1};default:return{message:`Unknown result when reconnecting to ${B}.`,success:!1}}}function ff1(A,B){let Q=A instanceof Error?A.message:String(A);return`Error reconnecting to ${B}: ${Q}`}function cN0({server:A,serverToolsCount:B,onViewTools:Q,onCancel:Z,onComplete:G}){let[Y]=NB(),I=pA(),[W]=o2(),J=fA1(),[X,F]=p9.useState(!1),V=String(A.name).charAt(0).toUpperCase()+String(A.name).slice(1),K=Jy1(W.mcp.commands,A.name).length,z=[];if(A.client.type==="connected"&&B>0)z.push({label:"View tools",value:"tools"});if(z.push({label:"Reconnect",value:"reconnectMcpServer"}),z.length===0)z.push({label:"Back",value:"back"});if(X)return p9.default.createElement(S,{flexDirection:"column",gap:1,padding:1},p9.default.createElement(M,{color:"text"},"Reconnecting to ",p9.default.createElement(M,{bold:!0},A.name)),p9.default.createElement(S,null,p9.default.createElement(h6,null),p9.default.createElement(M,null," Restarting MCP server process")),p9.default.createElement(M,{dimColor:!0},"This may take a few moments."))
|
||||
|
||||
return p9.default.createElement(p9.default.Fragment,null,p9.default.createElement(S,{flexDirection:"column",paddingX:1,borderStyle:"round"},p9.default.createElement(S,{marginBottom:1},p9.default.createElement(M,{bold:!0},V," MCP Server")),p9.default.createElement(S,{flexDirection:"column",gap:0},p9.default.createElement(S,null,p9.default.createElement(M,{bold:!0},"Status: "),A.client.type==="connected"?p9.default.createElement(M,null,SB("success",Y)(o0.tick)," connected"):A.client.type==="pending"?p9.default.createElement(p9.default.Fragment,null,p9.default.createElement(M,{dimColor:!0},o0.radioOff),p9.default.createElement(M,null," connecting…")):p9.default.createElement(M,null,SB("error",Y)(o0.cross)," failed")),p9.default.createElement(S,null,p9.default.createElement(M,{bold:!0},"Command: "),p9.default.createElement(M,{dimColor:!0},A.config.command)),A.config.args&&A.config.args.length>0&&p9.default.createElement(S,null,p9.default.createElement(M,{bold:!0},"Args: "),p9.default.createElement(M,{dimColor:!0},A.config.args.join(" "))),p9.default.createElement(S,null,p9.default.createElement(M,{bold:!0},"Config location: "),p9.default.createElement(M,{dimColor:!0},TD(ne(A.name)?.scope??"dynamic"))),A.client.type==="connected"&&p9.default.createElement(xf1,{serverToolsCount:B,serverPromptsCount:K,serverResourcesCount:W.mcp.resources[A.name]?.length||0}),A.client.type==="connected"&&B>0&&p9.default.createElement(S,null,p9.default.createElement(M,{bold:!0},"Tools: "),p9.default.createElement(M,{dimColor:!0},B," tools"))),z.length>0&&p9.default.createElement(S,{marginTop:1},p9.default.createElement(jA,{options:z,onChange:async(H)=>{if(H==="tools")Q();else if(H==="reconnectMcpServer"){F(!0);try{let D=await J(A.name),{message:C}=bf1(D,A.name)
|
||||
|
||||
return{...y,mcp:{clients:c,tools:g,commands:r,resources:m}}}),G?.(`Authentication cleared for ${A.name}.`)};if(W)return rB.default.createElement(S,{flexDirection:"column",gap:1,padding:1},rB.default.createElement(M,{color:"claude"},"Authenticating with ",A.name,"…"),rB.default.createElement(S,null,rB.default.createElement(h6,null),rB.default.createElement(M,null," A browser window will open for authentication")),z&&rB.default.createElement(S,{flexDirection:"column"},rB.default.createElement(M,{dimColor:!0},"If your browser doesn't open automatically, copy this URL manually:"),rB.default.createElement(y4,{url:z})),rB.default.createElement(S,{marginLeft:3},rB.default.createElement(M,{dimColor:!0},"Return here after authenticating in your browser. Press Esc to go back.")));if(D)return rB.default.createElement(S,{flexDirection:"column",gap:1,padding:1},rB.default.createElement(M,{color:"text"},"Reconnecting to ",rB.default.createElement(M,{bold:!0},A.name),"…"),rB.default.createElement(S,null,rB.default.createElement(h6,null),rB.default.createElement(M,null," Establishing connection to MCP server")),rB.default.createElement(M,{dimColor:!0},"This may take a few moments."));let f=[];if(A.client.type==="connected"&&B>0)f.push({label:"View tools",value:"tools"});if(A.isAuthenticated)f.push({label:"Re-authenticate",value:"reauth"}),f.push({label:"Clear authentication",value:"clear-auth"});if(!A.isAuthenticated)f.push({label:"Authenticate",value:"auth"});if(A.client.type!=="needs-auth")f.push({label:"Reconnect",value:"reconnectMcpServer"});if(f.length===0)f.push({label:"Back",value:"back"})
|
||||
|
||||
return rB.default.createElement(rB.default.Fragment,null,rB.default.createElement(S,{flexDirection:"column",paddingX:1,borderStyle:"round"},rB.default.createElement(S,{marginBottom:1},rB.default.createElement(M,{bold:!0},E," MCP Server")),rB.default.createElement(S,{flexDirection:"column",gap:0},rB.default.createElement(S,null,rB.default.createElement(M,{bold:!0},"Status: "),A.client.type==="connected"?rB.default.createElement(rB.default.Fragment,null,rB.default.createElement(M,null,SB("success",Y)(o0.tick)," connected"),A.isAuthenticated&&rB.default.createElement(M,null," ",SB("success",Y)(o0.tick)," authenticated")):A.client.type==="pending"?rB.default.createElement(rB.default.Fragment,null,rB.default.createElement(M,{dimColor:!0},o0.radioOff),rB.default.createElement(M,null," connecting…")):A.client.type==="needs-auth"?rB.default.createElement(M,null,SB("warning",Y)(o0.triangleUpOutline)," needs authentication"):rB.default.createElement(M,null,SB("error",Y)(o0.cross)," failed")),rB.default.createElement(S,null,rB.default.createElement(M,{bold:!0},"URL: "),rB.default.createElement(M,{dimColor:!0},A.config.url)),rB.default.createElement(S,null,rB.default.createElement(M,{bold:!0},"Config location: "),rB.default.createElement(M,{dimColor:!0},TD(ne(A.name)?.scope??"dynamic"))),A.client.type==="connected"&&rB.default.createElement(xf1,{serverToolsCount:B,serverPromptsCount:O,serverResourcesCount:V.mcp.resources[A.name]?.length||0}),A.client.type==="connected"&&B>0&&rB.default.createElement(S,null,rB.default.createElement(M,{bold:!0},"Tools: "),rB.default.createElement(M,{dimColor:!0},B," tools"))),X&&rB.default.createElement(S,{marginTop:1},rB.default.createElement(M,{color:"error"},"Error: ",X)),f.length>0&&rB.default.createElement(S,{marginTop:1},rB.default.createElement(jA,{options:f,onChange:async(y)=>{switch(y){case"tools":Q();break;case"auth":case"reauth":await P();break;case"clear-auth":await b();break;case"reconnectMcpServer":C(!0);try{let c=await T(A.name),{message:g}=bf1(c,A.name)
|
||||
|
||||
O.push({id:"toggle-individual",label:F?"Hide advanced options":"Show advanced options",action:()=>{if(V(!F),F&&J>b)X(b)},isToggle:!0});let f=xI.useMemo(()=>kz5(G),[G]);if(F){if(f.length>0)O.push({id:"mcp-servers-header",label:"MCP Servers:",action:()=>{},isHeader:!0}),f.forEach(({serverName:y,tools:c})=>{let r=c.filter((m)=>z.has(m.name)).length===c.length;O.push({id:`mcp-server-${y}`,label:`${r?o0.checkboxOn:o0.checkboxOff} ${y} (${c.length} tool${c.length===1?"":"s"})`,action:()=>{let m=c.map((j)=>j.name);C(m,!r)}})}),O.push({id:"tools-header",label:"Individual Tools:",action:()=>{},isHeader:!0});G.forEach((y)=>{let c=y.name;if(y.name.startsWith("mcp__")){let g=Ov(y.name);c=g?`${g.toolName} (${g.serverName})`:y.name}O.push({id:`tool-${y.name}`,label:`${z.has(y.name)?o0.checkboxOn:o0.checkboxOff} ${c}`,action:()=>D(y.name)})})}return i0((y,c)=>{if(c.return){let g=O[J];if(g&&!g.isHeader)g.action()}else if(c.escape)if(Z)Z();else Q(B);else if(c.upArrow){let g=J-1;while(g>0&&O[g]?.isHeader)g--;X(Math.max(0,g))}else if(c.downArrow){let g=J+1;while(g<O.length-1&&O[g]?.isHeader)g++;X(Math.min(O.length-1,g))}}),xI.default.createElement(S,{flexDirection:"column",marginTop:1},xI.default.createElement(M,{color:J===0?"suggestion":void 0,bold:J===0},J===0?`${o0.pointer} `:" ","[ Continue ]"),xI.default.createElement(M,{dimColor:!0},"─".repeat(40)),O.slice(1).map((y,c)=>{let g=c+1===J,r=y.isToggle,m=y.isHeader
|
||||
|
||||
if(Z.length===1)return`${Z[0]} and ${G} more`;return`${Z.join(", ")}, and ${G} more`}function h9Q(A){return!!A?.otelHeadersHelper}function m9Q(){let A=[],B=z8("projectSettings");if(h9Q(B))A.push(".claude/settings.json");let Q=z8("localSettings");if(h9Q(Q))A.push(".claude/settings.local.json");return A}function c9Q({onDone:A,commands:B}){let{servers:Q}=BG("project"),Z=Object.keys(Q).length>0,G=g9Q(),Y=G.length>0,I=u9Q(),W=m9Q(),J=W.length>0,X=[...new Set([...G,...I,...W])],F=B?.filter((P)=>P.type==="prompt"&&P.source==="projectSettings"&&P.allowedTools?.some((b)=>b===j8||b.startsWith(j8+"(")))??[],V=F.length>0,K=F.map((P)=>P.name),z=I.length>0||V,H=eK(Y||z||J),C=[{name:"MCP servers",shouldShowWarning:()=>Z,onChange:()=>{let P={enabledMcpjsonServers:Object.keys(Q),enableAllProjectMcpServers:!0};B4("localSettings",P)}},{name:"hooks",shouldShowWarning:()=>Y},{name:"bash commands",shouldShowWarning:()=>z},{name:"OpenTelemetry headers helper commands",shouldShowWarning:()=>J}].filter((P)=>P.shouldShowWarning()),w=new Set(C.map((P)=>P.name)),L=Object.keys(Q);function E(){let P=["files"];if(w.has("MCP servers"))P.push("MCP servers");if(w.has("hooks"))P.push("hooks");if(w.has("bash commands"))P.push("bash commands");if(w.has("OpenTelemetry headers helper commands"))P.push("OpenTelemetry headers helper commands");return hc1(P)}C5.default.useEffect(()=>{let P=d9Q()===e0();Q1("tengu_trust_dialog_shown",{isHomeDir:P,hasMcpServers:Z,hasHooks:Y,hasBashExecution:z,hasOtelHeadersHelper:J})},[Z,Y,z,J]);function O(P){let b=G9();if(P==="exit"){T6(1);return}let f=d9Q()===e0();if(Q1("tengu_trust_dialog_accept",{isHomeDir:f,hasMcpServers:Z,hasHooks:Y,hasBashExecution:z,hasOtelHeadersHelper:J,enableMcp:!0}),!f)S8({...b,hasTrustDialogAccepted:!0});C.forEach((y)=>{if(y.onChange!==void 0)y.onChange()}),A()}let T=pA();if(i0((P,b)=>{if(b.escape){T6(0);return}}),H)return setTimeout(A),null
|
||||
|
||||
Q().then(()=>{B()})}),Q1("tengu_forced_migration_success",{gateControlled:!0}),console.log(c1.green("✅ Migration complete!")),console.log("Please restart Claude CLI to use the new installation."),process.exit(0)}catch(B){let Q=B instanceof Error?B:new Error(String(B));F1(Q,ip0),Q1("tengu_forced_migration_failure",{gateControlled:!0}),console.log(c1.red("⚠️ Migration encountered an error, continuing with global installation."))}}function X4Q(){let A=G9(),B=A.enableAllProjectMcpServers!==void 0,Q=A.enabledMcpjsonServers&&A.enabledMcpjsonServers.length>0,Z=A.disabledMcpjsonServers&&A.disabledMcpjsonServers.length>0;if(!B&&!Q&&!Z)return;try{let G=z8("localSettings")||{},Y={},I=[];if(B&&G.enableAllProjectMcpServers===void 0)Y.enableAllProjectMcpServers=A.enableAllProjectMcpServers,I.push("enableAllProjectMcpServers");else if(B)I.push("enableAllProjectMcpServers");if(Q&&A.enabledMcpjsonServers){let W=G.enabledMcpjsonServers||[];Y.enabledMcpjsonServers=[...new Set([...W,...A.enabledMcpjsonServers])],I.push("enabledMcpjsonServers")}if(Z&&A.disabledMcpjsonServers){let W=G.disabledMcpjsonServers||[];Y.disabledMcpjsonServers=[...new Set([...W,...A.disabledMcpjsonServers])],I.push("disabledMcpjsonServers")}if(Object.keys(Y).length>0)B4("localSettings",Y);if(I.length>0){let W=G9(),{enableAllProjectMcpServers:J,enabledMcpjsonServers:X,disabledMcpjsonServers:F,...V}=W;if(I.includes("enableAllProjectMcpServers")||I.includes("enabledMcpjsonServers")||I.includes("disabledMcpjsonServers"))S8(V)}Q1("tengu_migrate_mcp_approval_fields_success",{migratedCount:I.length})}catch{Q1("tengu_migrate_mcp_approval_fields_error",{})}}import{randomUUID as et5}from"crypto"
|
||||
|
||||
S8({...Z,enabledMcpjsonServers:[],disabledMcpjsonServers:[],enableAllProjectMcpServers:!1}),console.log("All project-scoped (.mcp.json) server approvals and rejections have been reset."),console.log("You will be prompted for approval next time you start Claude Code."),process.exit(0)}),A.command("migrate-installer").description("Migrate from global npm installation to local installation").helpOption("-h, --help","Display help for command").action(async()=>{if(yb())console.log("Already running from local installation. No migration needed."),process.exit(0);Q1("tengu_migrate_installer_command",{}),await new Promise((Z)=>{let{waitUntilExit:G}=i6(P3.default.createElement(K3,null,P3.default.createElement(bA1,null)));G().then(()=>{Z()})}),process.exit(0)}),A.command("setup-token").description("Set up a long-lived authentication token (requires Claude subscription)").helpOption("-h, --help","Display help for command").action(async()=>{if(Q1("tengu_setup_token_command",{}),await h3(),!mD())process.stderr.write(c1.yellow(`Warning: You already have authentication configured via environment variable or API key helper.
|
||||
`)),process.stderr.write(c1.yellow(`The setup-token command will create a new OAuth token which you can use instead.
|
||||
`))
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"version": "3.12.1",
|
||||
"sizeBytes": 9360004,
|
||||
"lines": 3783,
|
||||
"functions": 16593,
|
||||
"asyncFunctions": 623,
|
||||
"arrowFunctions": 19160,
|
||||
"classes": 1390,
|
||||
"extends": 879,
|
||||
"sourceFile": "cli.js",
|
||||
"extractedAt": "2026-04-02T23:28:44.993Z",
|
||||
"modules": {
|
||||
"permission-system": {
|
||||
"fragments": 198,
|
||||
"sizeBytes": 473765
|
||||
},
|
||||
"tool-dispatch": {
|
||||
"fragments": 24,
|
||||
"sizeBytes": 159793
|
||||
},
|
||||
"agent-loop": {
|
||||
"fragments": 44,
|
||||
"sizeBytes": 91903
|
||||
},
|
||||
"streaming-handler": {
|
||||
"fragments": 9,
|
||||
"sizeBytes": 17514
|
||||
},
|
||||
"mcp-client": {
|
||||
"fragments": 17,
|
||||
"sizeBytes": 30858
|
||||
},
|
||||
"context-manager": {
|
||||
"fragments": 9,
|
||||
"sizeBytes": 17916
|
||||
},
|
||||
"telemetry": {
|
||||
"fragments": 319,
|
||||
"sizeBytes": 10122
|
||||
},
|
||||
"commands": {
|
||||
"fragments": 32,
|
||||
"sizeBytes": 2406
|
||||
},
|
||||
"class-hierarchy": {
|
||||
"fragments": 810,
|
||||
"sizeBytes": 12627
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,22 @@
|
|||
function dW(A){let B=A.logger,Q=A.logLevel??"off";if(!B)return o19;let Z=hWA.get(B);if(Z&&Z[0]===Q)return Z[1];let G={error:lU1("error",B,Q),warn:lU1("warn",B,Q),info:lU1("info",B,Q),debug:lU1("debug",B,Q)};return hWA.set(B,[Q,G]),G}var sT=(A)=>{if(A.options)A.options={...A.options},delete A.options.headers;if(A.headers)A.headers=Object.fromEntries((A.headers instanceof Headers?[...A.headers]:Object.entries(A.headers)).map(([B,Q])=>[B,B.toLowerCase()==="x-api-key"||B.toLowerCase()==="authorization"||B.toLowerCase()==="cookie"||B.toLowerCase()==="set-cookie"?"***":Q]));if("retryOfRequestLogID"in A){if(A.retryOfRequestLogID)A.retryOf=A.retryOfRequestLogID;delete A.retryOfRequestLogID}return A};var L61;class TV{constructor(A,B,Q){this.iterator=A,L61.set(this,void 0),this.controller=B,Y9(this,L61,Q,"f")}static fromSSEResponse(A,B,Q){let Z=!1,G=Q?dW(Q):console;async function*Y(){if(Z)throw new MQ("Cannot iterate over a consumed stream, use `.tee()` to split the stream.");Z=!0;let I=!1;try{for await(let W of t19(A,B)){if(W.event==="completion")try{yield JSON.parse(W.data)}catch(J){throw G.error("Could not parse message into JSON:",W.data),G.error("From chunk:",W.raw),J}if(W.event==="message_start"||W.event==="message_delta"||W.event==="message_stop"||W.event==="content_block_start"||W.event==="content_block_delta"||W.event==="content_block_stop")try{yield JSON.parse(W.data)}catch(J){throw G.error("Could not parse message into JSON:",W.data),G.error("From chunk:",W.raw),J}if(W.event==="ping")continue;if(W.event==="error")throw new Z4(void 0,cU1(W.data)??W.data,void 0,A.headers)}I=!0}catch(W){if(nT(W))return;throw W}finally{if(!I)B.abort()}}return new TV(Y,B,Q)}static fromReadableStream(A,B,Q){let Z=!1;async function*G(){let I=new N_,W=q61(A);for await(let J of W)for(let X of I.decode(J))yield X;for(let J of I.flush())yield J}async function*Y(){if(Z)throw new MQ("Cannot iterate over a consumed stream, use `.tee()` to split the stream.");Z=!0;let I=!1;try{for await(let W of G()){if(I)continue
|
||||
|
||||
if(!vA(this,ta,"f")&&!Q?.length)Promise.reject(Z);vA(this,O61,"f").call(this,Z),vA(this,T61,"f").call(this,Z),this._emit("end");return}if(A==="error"){let Z=B[0];if(!vA(this,ta,"f")&&!Q?.length)Promise.reject(Z);vA(this,O61,"f").call(this,Z),vA(this,T61,"f").call(this,Z),this._emit("end")}}_emitFinal(){if(this.receivedMessages.at(-1))this._emit("finalMessage",vA(this,eC,"m",I10).call(this))}async _fromReadableStream(A,B){let Q=B?.signal,Z;if(Q){if(Q.aborted)this.controller.abort();Z=this.controller.abort.bind(this.controller),Q.addEventListener("abort",Z)}try{vA(this,eC,"m",W10).call(this),this._connected(null);let G=TV.fromReadableStream(A,this.controller);for await(let Y of G)vA(this,eC,"m",J10).call(this,Y);if(G.controller.signal?.aborted)throw new iZ;vA(this,eC,"m",X10).call(this)}finally{if(Q&&Z)Q.removeEventListener("abort",Z)}}[(L_=new WeakMap,M61=new WeakMap,nU1=new WeakMap,O61=new WeakMap,R61=new WeakMap,aU1=new WeakMap,T61=new WeakMap,rT=new WeakMap,P61=new WeakMap,sU1=new WeakMap,rU1=new WeakMap,ta=new WeakMap,oU1=new WeakMap,tU1=new WeakMap,eU1=new WeakMap,eC=new WeakSet,I10=function A(){if(this.receivedMessages.length===0)throw new MQ("stream ended without producing a Message with role=assistant");return this.receivedMessages.at(-1)},uWA=function A(){if(this.receivedMessages.length===0)throw new MQ("stream ended without producing a Message with role=assistant");let B=this.receivedMessages.at(-1).content.filter((Q)=>Q.type==="text").map((Q)=>Q.text);if(B.length===0)throw new MQ("stream ended without producing a content block with type=text");return B.join(" ")},W10=function A(){if(this.ended)return;Y9(this,L_,void 0,"f")},J10=function A(B){if(this.ended)return;let Q=vA(this,eC,"m",mWA).call(this,B);switch(this._emit("streamEvent",B,Q),B.type){case"content_block_delta":{let Z=Q.content.at(-1);switch(B.delta.type){case"text_delta":{if(Z.type==="text")this._emit("text",B.delta.text,Z.text||"");break}case"citations_delta":{if(Z.type==="text")this._emit("citation",B.delta.citation,Z.citations??[])
|
||||
|
||||
break}case"input_json_delta":{if(cWA(Z)&&Z.input)this._emit("inputJson",B.delta.partial_json,Z.input);break}case"thinking_delta":{if(Z.type==="thinking")this._emit("thinking",B.delta.thinking,Z.thinking);break}case"signature_delta":{if(Z.type==="thinking")this._emit("signature",Z.signature);break}default:lWA(B.delta)}break}case"message_stop":{this._addMessageParam(Q),this._addMessage(Q,!0);break}case"content_block_stop":{this._emit("contentBlock",Q.content.at(-1));break}case"message_start":{Y9(this,L_,Q,"f");break}case"content_block_start":case"message_delta":break}},X10=function A(){if(this.ended)throw new MQ("stream has ended, this shouldn't happen");let B=vA(this,L_,"f");if(!B)throw new MQ("request ended without sending any chunks");return Y9(this,L_,void 0,"f"),B},mWA=function A(B){let Q=vA(this,L_,"f");if(B.type==="message_start"){if(Q)throw new MQ(`Unexpected event order, got ${B.type} before receiving "message_stop"`);return B.message}if(!Q)throw new MQ(`Unexpected event order, got ${B.type} before "message_start"`);switch(B.type){case"message_stop":return Q;case"message_delta":if(Q.container=B.delta.container,Q.stop_reason=B.delta.stop_reason,Q.stop_sequence=B.delta.stop_sequence,Q.usage.output_tokens=B.usage.output_tokens,B.usage.input_tokens!=null)Q.usage.input_tokens=B.usage.input_tokens;if(B.usage.cache_creation_input_tokens!=null)Q.usage.cache_creation_input_tokens=B.usage.cache_creation_input_tokens;if(B.usage.cache_read_input_tokens!=null)Q.usage.cache_read_input_tokens=B.usage.cache_read_input_tokens;if(B.usage.server_tool_use!=null)Q.usage.server_tool_use=B.usage.server_tool_use;return Q;case"content_block_start":return Q.content.push(B.content_block),Q;case"content_block_delta":{let Z=Q.content.at(B.index);switch(B.delta.type){case"text_delta":{if(Z?.type==="text")Q.content[B.index]={...Z,text:(Z.text||"")+B.delta.text};break}case"citations_delta":{if(Z?.type==="text")Q.content[B.index]={...Z,citations:[...Z.citations??[],B.delta.citation]}
|
||||
|
||||
break}case"input_json_delta":{if(Z&&cWA(Z)){let G=Z[dWA]||"";G+=B.delta.partial_json;let Y={...Z};if(Object.defineProperty(Y,dWA,{value:G,enumerable:!1,writable:!0}),G)try{Y.input=iU1(G)}catch(I){let W=new MQ(`Unable to parse tool parameter JSON from model. Please retry your request or adjust your prompt. Error: ${I}. JSON: ${G}`);vA(this,eU1,"f").call(this,W)}Q.content[B.index]=Y}break}case"thinking_delta":{if(Z?.type==="thinking")Q.content[B.index]={...Z,thinking:Z.thinking+B.delta.thinking};break}case"signature_delta":{if(Z?.type==="thinking")Q.content[B.index]={...Z,signature:B.delta.signature};break}default:lWA(B.delta)}return Q}case"content_block_stop":return Q}},Symbol.asyncIterator)](){let A=[],B=[],Q=!1;return this.on("streamEvent",(Z)=>{let G=B.shift();if(G)G.resolve(Z);else A.push(Z)}),this.on("end",()=>{Q=!0;for(let Z of B)Z.resolve(void 0);B.length=0}),this.on("abort",(Z)=>{Q=!0;for(let G of B)G.reject(Z);B.length=0}),this.on("error",(Z)=>{Q=!0;for(let G of B)G.reject(Z);B.length=0}),{next:async()=>{if(!A.length){if(Q)return{value:void 0,done:!0};return new Promise((G,Y)=>B.push({resolve:G,reject:Y})).then((G)=>G?{value:G,done:!1}:{value:void 0,done:!0})}return{value:A.shift(),done:!1}},return:async()=>{return this.abort(),{value:void 0,done:!0}}}}toReadableStream(){return new TV(this[Symbol.asyncIterator].bind(this),this.controller).toReadableStream()}}function lWA(A){}var qL="Glob",F10=`- Fast file pattern matching tool that works with any codebase size
|
||||
- Supports glob patterns like "**/*.js" or "src/**/*.ts"
|
||||
- Returns matching file paths sorted by modification time
|
||||
- Use this tool when you need to find files by name patterns
|
||||
- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead
|
||||
- You have the capability to call multiple tools in a single response. It is always better to speculatively perform multiple searches as a batch that are potentially useful.`;var b7="Task";var AU="Grep"
|
||||
|
||||
return this.receivedMessages.at(-1)},rA2=function A(){if(this.receivedMessages.length===0)throw new MQ("stream ended without producing a Message with role=assistant");let B=this.receivedMessages.at(-1).content.filter((Q)=>Q.type==="text").map((Q)=>Q.text);if(B.length===0)throw new MQ("stream ended without producing a content block with type=text");return B.join(" ")},V70=function A(){if(this.ended)return;Y9(this,fx,void 0,"f")},K70=function A(B){if(this.ended)return;let Q=vA(this,_U,"m",oA2).call(this,B);switch(this._emit("streamEvent",B,Q),B.type){case"content_block_delta":{let Z=Q.content.at(-1);switch(B.delta.type){case"text_delta":{if(Z.type==="text")this._emit("text",B.delta.text,Z.text||"");break}case"citations_delta":{if(Z.type==="text")this._emit("citation",B.delta.citation,Z.citations??[]);break}case"input_json_delta":{if(eA2(Z)&&Z.input)this._emit("inputJson",B.delta.partial_json,Z.input);break}case"thinking_delta":{if(Z.type==="thinking")this._emit("thinking",B.delta.thinking,Z.thinking);break}case"signature_delta":{if(Z.type==="thinking")this._emit("signature",Z.signature);break}default:A22(B.delta)}break}case"message_stop":{this._addMessageParam(Q),this._addMessage(Q,!0);break}case"content_block_stop":{this._emit("contentBlock",Q.content.at(-1));break}case"message_start":{Y9(this,fx,Q,"f");break}case"content_block_start":case"message_delta":break}},z70=function A(){if(this.ended)throw new MQ("stream has ended, this shouldn't happen");let B=vA(this,fx,"f");if(!B)throw new MQ("request ended without sending any chunks");return Y9(this,fx,void 0,"f"),B},oA2=function A(B){let Q=vA(this,fx,"f");if(B.type==="message_start"){if(Q)throw new MQ(`Unexpected event order, got ${B.type} before receiving "message_stop"`);return B.message}if(!Q)throw new MQ(`Unexpected event order, got ${B.type} before "message_start"`);switch(B.type){case"message_stop":return Q
|
||||
|
||||
case"message_delta":if(Q.stop_reason=B.delta.stop_reason,Q.stop_sequence=B.delta.stop_sequence,Q.usage.output_tokens=B.usage.output_tokens,B.usage.input_tokens!=null)Q.usage.input_tokens=B.usage.input_tokens;if(B.usage.cache_creation_input_tokens!=null)Q.usage.cache_creation_input_tokens=B.usage.cache_creation_input_tokens;if(B.usage.cache_read_input_tokens!=null)Q.usage.cache_read_input_tokens=B.usage.cache_read_input_tokens;if(B.usage.server_tool_use!=null)Q.usage.server_tool_use=B.usage.server_tool_use;return Q;case"content_block_start":return Q.content.push({...B.content_block}),Q;case"content_block_delta":{let Z=Q.content.at(B.index);switch(B.delta.type){case"text_delta":{if(Z?.type==="text")Q.content[B.index]={...Z,text:(Z.text||"")+B.delta.text};break}case"citations_delta":{if(Z?.type==="text")Q.content[B.index]={...Z,citations:[...Z.citations??[],B.delta.citation]};break}case"input_json_delta":{if(Z&&eA2(Z)){let G=Z[tA2]||"";G+=B.delta.partial_json;let Y={...Z};if(Object.defineProperty(Y,tA2,{value:G,enumerable:!1,writable:!0}),G)Y.input=iU1(G);Q.content[B.index]=Y}break}case"thinking_delta":{if(Z?.type==="thinking")Q.content[B.index]={...Z,thinking:Z.thinking+B.delta.thinking};break}case"signature_delta":{if(Z?.type==="thinking")Q.content[B.index]={...Z,signature:B.delta.signature};break}default:A22(B.delta)}return Q}case"content_block_stop":return Q}},Symbol.asyncIterator)](){let A=[],B=[],Q=!1;return this.on("streamEvent",(Z)=>{let G=B.shift();if(G)G.resolve(Z);else A.push(Z)}),this.on("end",()=>{Q=!0;for(let Z of B)Z.resolve(void 0);B.length=0}),this.on("abort",(Z)=>{Q=!0;for(let G of B)G.reject(Z);B.length=0}),this.on("error",(Z)=>{Q=!0;for(let G of B)G.reject(Z);B.length=0}),{next:async()=>{if(!A.length){if(Q)return{value:void 0,done:!0}
|
||||
|
||||
return B}async function*LU0(A){for(let B of A)yield B}function xZ1(A){let B={},Q=process.env.CLAUDE_CODE_EXTRA_BODY,Z={};if(Q)try{let Y=t3(Q);if(Y&&typeof Y==="object"&&!Array.isArray(Y))Z=Y;else o(`CLAUDE_CODE_EXTRA_BODY env var must be a JSON object, but was given ${Q}`,{level:"error"})}catch(Y){o(`Error parsing CLAUDE_CODE_EXTRA_BODY: ${Y instanceof Error?Y.message:String(Y)}`,{level:"error"})}let G={...B,...Z};if(A&&A.length>0)if(G.anthropic_beta&&Array.isArray(G.anthropic_beta)){let Y=G.anthropic_beta,I=A.filter((W)=>!Y.includes(W));G.anthropic_beta=[...Y,...I]}else G.anthropic_beta=A;return G}function _d(A){if(hA(process.env.DISABLE_PROMPT_CACHING))return!1;if(hA(process.env.DISABLE_PROMPT_CACHING_HAIKU)){let B=$z();if(A===B)return!1}if(hA(process.env.DISABLE_PROMPT_CACHING_SONNET)){let B=To();if(A===B)return!1}if(hA(process.env.DISABLE_PROMPT_CACHING_OPUS)){let B=$M1();if(A===B)return!1}return!0}var d$6=1;function zj(){let A=Mo(),B=sZ()?.accountUuid??"",Q=W2();return{user_id:`user_${A}_account_${B}_session_${Q}`}}async function $2B(A,B){if(B)return!0;try{let Q=$z(),Z=Pz(Q);return await NU0(rG1(()=>xF({apiKey:A,maxRetries:3,model:Q}),async(G)=>{let Y=[{role:"user",content:"test"}];return await G.beta.messages.create({model:Q,max_tokens:1,messages:Y,temperature:0,...Z.length>0?{betas:Z}:{},metadata:zj(),...xZ1()}),!0},{maxRetries:2,model:Q}))}catch(Q){let Z=Q;if(Q instanceof cj)Z=Q.originalError;if(F1(Z,hl0),Z instanceof Error&&Z.message.includes('{"type":"error","error":{"type":"authentication_error","message":"invalid x-api-key"}}'))return!1;throw Z}}async function c$6(A){let B=Date.now(),Q=null,Z=null,G=Nj;for await(let I of A)switch(I.type){case"message_start":Z=Date.now()-B,G=xd(G,I.message.usage);break;case"message_delta":G=xd(G,I.usage),Q=I.delta.stop_reason;break
|
||||
|
||||
let K=Date.now(),z=Date.now(),H=0,D=void 0,C=(c)=>{let g=tWA(),r=c.maxTokensOverride?Math.min(Q,c.maxTokensOverride-1):Q,m=xZ1(i8()==="bedrock"?XV0(c.model):[]),j=Q>0?{budget_tokens:r,type:"enabled"}:void 0,p=c?.maxTokensOverride||Y.maxOutputTokensOverride||Math.max(Q+1,RU0(Y.model));return{model:Tx(Y.model),messages:i$6(V,c.model),temperature:F,system:J,tools:[...I,...Y.extraToolSchemas??[]],tool_choice:Y.toolChoice,...X?{betas:W}:{},metadata:zj(),max_tokens:p,thinking:j,...g&&X&&W.includes(xS2)?{context_management:g}:{},...m}},w=[],L=0,E=void 0,O=[],T=Nj,P=null,b=!1,f=0,y=void 0;try{let c=rG1(()=>xF({maxRetries:0,model:Y.model}),async(r,m,j)=>{H=m,z=Date.now();let p=C(j);return OU0(p,Y.querySource),f=p.max_tokens,r.beta.messages.stream(p,{signal:G})},{model:Y.model,fallbackModel:Y.fallbackModel,maxThinkingTokens:Q,signal:G}),g;do if(g=await c.next(),!(g.value instanceof Ju))yield g.value;while(!g.done);D=g.value,w.length=0,L=0,E=void 0,O.length=0,T=Nj;try{let r=!0;for await(let j of D){if(r)o("Stream started - received first chunk"),r=!1;switch(j.type){case"message_start":E=j.message,L=Date.now()-z,T=xd(T,j.message.usage);break;case"content_block_start":switch(j.content_block.type){case"tool_use":O[j.index]={...j.content_block,input:""};break;case"server_tool_use":O[j.index]={...j.content_block,input:""};break;case"text":O[j.index]={...j.content_block,text:""};break;case"thinking":O[j.index]={...j.content_block,thinking:""};break;default:O[j.index]={...j.content_block};break}break;case"content_block_delta":{let p=O[j.index];if(!p)throw Q1("tengu_streaming_error",{error_type:"content_block_not_found_delta",part_type:j.type,part_index:j.index}),new RangeError("Content block not found");switch(j.delta.type){case"citations_delta":break;case"input_json_delta":if(p.type!=="tool_use"&&p.type!=="server_tool_use")throw Q1("tengu_streaming_error",{error_type:"content_block_type_mismatch_input_json",expected_type:"tool_use",actual_type:p.type}),new Error("Content block is not a input_json block")
|
||||
|
||||
if(typeof p.input!=="string")throw Q1("tengu_streaming_error",{error_type:"content_block_input_not_string",input_type:typeof p.input}),new Error("Content block input is not a string");p.input+=j.delta.partial_json;break;case"text_delta":if(p.type!=="text")throw Q1("tengu_streaming_error",{error_type:"content_block_type_mismatch_text",expected_type:"text",actual_type:p.type}),new Error("Content block is not a text block");p.text+=j.delta.text;break;case"signature_delta":if(p.type!=="thinking")throw Q1("tengu_streaming_error",{error_type:"content_block_type_mismatch_thinking_signature",expected_type:"thinking",actual_type:p.type}),new Error("Content block is not a thinking block");p.signature=j.delta.signature;break;case"thinking_delta":if(p.type!=="thinking")throw Q1("tengu_streaming_error",{error_type:"content_block_type_mismatch_thinking_delta",expected_type:"thinking",actual_type:p.type}),new Error("Content block is not a thinking block");p.thinking+=j.delta.thinking;break}break}case"content_block_stop":{let p=O[j.index];if(!p)throw Q1("tengu_streaming_error",{error_type:"content_block_not_found_stop",part_type:j.type,part_index:j.index}),new RangeError("Content block not found");if(!E)throw Q1("tengu_streaming_error",{error_type:"partial_message_not_found",part_type:j.type}),new Error("Message not found");let A1={message:{...E,content:oG1([p],Z)},requestId:D.request_id??void 0,type:"assistant",uuid:MU0(),timestamp:new Date().toISOString()};w.push(A1),yield A1;break}case"message_delta":{T=xd(T,j.usage),P=j.delta.stop_reason;let p=NH0(j.delta.stop_reason,Y.model);if(p)yield p;if(P==="max_tokens")Q1("tengu_max_tokens_reached",{max_tokens:f}),yield CY({content:`${TX}: Claude's response exceeded the ${f} output token maximum. To configure this behavior, set the CLAUDE_CODE_MAX_OUTPUT_TOKENS environment variable.`});break}case"message_stop":break}yield{type:"stream_event",event:j}}let m=(await D.withResponse()).response
|
||||
|
|
@ -0,0 +1,319 @@
|
|||
"tengu_ripgrep_availability"
|
||||
"tengu_run_hook"
|
||||
"tengu_repl_hook_finished"
|
||||
"tengu_thinking"
|
||||
"tengu_typing_without_terminal_focus"
|
||||
"tengu_opusplan_default"
|
||||
"tengu_external_model_override"
|
||||
"tengu_subscription_upsell_shown"
|
||||
"tengu_file_changed"
|
||||
"tengu_ext_jetbrains_extension_install_unknown_ide"
|
||||
"tengu_ext_jetbrains_extension_install_source_missing"
|
||||
"tengu_ext_jetbrains_extension_install_error_reading_version"
|
||||
"tengu_ext_jetbrains_extension_install_no_plugin_directories"
|
||||
"tengu_ext_jetbrains_extension_install_error_installing"
|
||||
"tengu_ext_installed"
|
||||
"tengu_ext_install_error"
|
||||
"tengu_ant_prompts"
|
||||
"tengu_mcp_servers"
|
||||
"tengu_mcp_oauth_flow_start"
|
||||
"tengu_mcp_oauth_flow_success"
|
||||
"tengu_mcp_oauth_flow_error"
|
||||
"tengu_mcp_headersHelper_missing_trust"
|
||||
"tengu_mcp_server_needs_auth"
|
||||
"tengu_mcp_ide_server_connection_failed"
|
||||
"tengu_mcp_ide_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_failed"
|
||||
"tengu_mcp_tools_commands_loaded"
|
||||
"tengu_use_file_checkpoints"
|
||||
"tengu_file_history_track_edit_failed"
|
||||
"tengu_file_history_track_edit_success"
|
||||
"tengu_file_history_backup_deleted_file"
|
||||
"tengu_file_history_backup_file_failed"
|
||||
"tengu_file_history_snapshot_success"
|
||||
"tengu_file_history_snapshot_failed"
|
||||
"tengu_file_history_rewind_failed"
|
||||
"tengu_file_history_rewind_success"
|
||||
"tengu_file_history_rewind_restore_file_failed"
|
||||
"tengu_file_history_backup_file_created"
|
||||
"tengu_file_history_resume_copy_failed"
|
||||
"tengu_write_claudemd"
|
||||
"tengu_sysprompt_block"
|
||||
"tengu_context_size"
|
||||
"tengu_bash_tool_simple_echo"
|
||||
"tengu_claudeai_limits_status_changed"
|
||||
"tengu_claude_ai_limits_enable_fallback"
|
||||
"tengu_claude_ai_limits_disable_fallback"
|
||||
"tengu_data_sharing_response_err"
|
||||
"tengu_unknown_model_cost"
|
||||
"tengu_model_cost_discount"
|
||||
"tengu_api_query"
|
||||
"tengu_api_error"
|
||||
"tengu_api_success"
|
||||
"tengu_refusal_api_response"
|
||||
"tengu_api_opus_fallback_triggered"
|
||||
"tengu_api_custom_529_overloaded_error"
|
||||
"tengu_max_tokens_context_overflow_adjustment"
|
||||
"tengu_api_retry"
|
||||
"tengu_off_switch_query"
|
||||
"tengu_streaming_error"
|
||||
"tengu_max_tokens_reached"
|
||||
"tengu_shell_snapshot_failed"
|
||||
"tengu_shell_unknown_error"
|
||||
"tengu_shell_snapshot_error"
|
||||
"tengu_shell_set_cwd"
|
||||
"tengu_bash_tool_reset_to_original_dir"
|
||||
"tengu_bash_prefix"
|
||||
"tengu_git_operation"
|
||||
"tengu_sandbox_disabled_commands"
|
||||
"tengu_git_index_lock_error"
|
||||
"tengu_bash_tool_haiku_file_paths_read"
|
||||
"tengu_bash_tool_command_executed"
|
||||
"tengu_bash_command_auto_backgrounded"
|
||||
"tengu_disable_bypass_permissions_mode"
|
||||
"tengu_dir_search"
|
||||
"tengu_empty_model_response"
|
||||
"tengu_bug_report_submitted"
|
||||
"tengu_claude_md_permission_error"
|
||||
"tengu_attachment_compute_duration"
|
||||
"tengu_at_mention_extracting_directory_success"
|
||||
"tengu_at_mention_extracting_filename_success"
|
||||
"tengu_at_mention_extracting_filename_error"
|
||||
"tengu_at_mention_agent_not_found"
|
||||
"tengu_at_mention_agent_success"
|
||||
"tengu_at_mention_mcp_resource_error"
|
||||
"tengu_at_mention_mcp_resource_success"
|
||||
"tengu_watched_file_changed"
|
||||
"tengu_watched_file_stat_error"
|
||||
"tengu_attachments"
|
||||
"tengu_compact_failed"
|
||||
"tengu_compact"
|
||||
"tengu_post_compact_file_restore_success"
|
||||
"tengu_post_compact_file_restore_error"
|
||||
"tengu_microcompact"
|
||||
"tengu_claude_md_includes_dialog_shown"
|
||||
"tengu_claude_md_external_includes_dialog_declined"
|
||||
"tengu_claude_md_external_includes_dialog_accepted"
|
||||
"tengu_config_model_changed"
|
||||
"tengu_auto_compact_setting_changed"
|
||||
"tengu_tips_setting_changed"
|
||||
"tengu_file_history_snapshots_setting_changed"
|
||||
"tengu_editor_mode_changed"
|
||||
"tengu_diff_tool_changed"
|
||||
"tengu_auto_connect_ide_changed"
|
||||
"tengu_auto_install_ide_extension_changed"
|
||||
"tengu_config_changed"
|
||||
"tengu_output_style_changed"
|
||||
"tengu_local_install_migration"
|
||||
"tengu_version_config"
|
||||
"tengu_auto_updater_lock_contention"
|
||||
"tengu_auto_updater_windows_npm_in_wsl"
|
||||
"tengu_native_installation"
|
||||
"tengu_native_staging_cleanup"
|
||||
"tengu_native_temp_files_cleanup"
|
||||
"tengu_native_version_cleanup"
|
||||
"tengu_spinner_words"
|
||||
"tengu_ext_ide_command"
|
||||
"tengu_oauth_token_refresh_success"
|
||||
"tengu_oauth_token_refresh_failure"
|
||||
"tengu_oauth_roles_stored"
|
||||
"tengu_oauth_api_key"
|
||||
"tengu_oauth_automatic_redirect"
|
||||
"tengu_oauth_automatic_redirect_error"
|
||||
"tengu_preflight_check_failed"
|
||||
"tengu_began_setup"
|
||||
"tengu_onboarding_step"
|
||||
"tengu_notification_method_used"
|
||||
"tengu_show_all_subscription_types"
|
||||
"tengu_oauth_claudeai_forced"
|
||||
"tengu_oauth_console_forced"
|
||||
"tengu_oauth_success"
|
||||
"tengu_oauth_manual_entry"
|
||||
"tengu_oauth_token_exchange_error"
|
||||
"tengu_oauth_storage_warning"
|
||||
"tengu_oauth_user_roles_error"
|
||||
"tengu_oauth_api_key_error"
|
||||
"tengu_oauth_error"
|
||||
"tengu_oauth_claudeai_selected"
|
||||
"tengu_oauth_console_selected"
|
||||
"tengu_setup_github_actions_failed"
|
||||
"tengu_setup_github_actions_started"
|
||||
"tengu_setup_github_actions_completed"
|
||||
"tengu_gha_v1"
|
||||
"tengu_install_github_app_started"
|
||||
"tengu_install_github_app_step_completed"
|
||||
"tengu_install_github_app_error"
|
||||
"tengu_install_github_app_completed"
|
||||
"tengu_mcp_auth_config_authenticate"
|
||||
"tengu_mcp_auth_config_clear"
|
||||
"tengu_checkpoint_save_success"
|
||||
"tengu_checkpoint_save_failed"
|
||||
"tengu_checkpoint_cleanup"
|
||||
"tengu_teleport_error_git_not_clean"
|
||||
"tengu_teleport_error_branch_checkout_failed"
|
||||
"tengu_teleport_error_repo_not_in_git_dir_legacy"
|
||||
"tengu_teleport_error_repo_validation_failed_legacy"
|
||||
"tengu_teleport_error_repo_mismatch_legacy"
|
||||
"tengu_teleport_error_repo_not_in_git_dir_sessions_api"
|
||||
"tengu_teleport_error_repo_validation_failed_sessions_api"
|
||||
"tengu_teleport_error_repo_mismatch_sessions_api"
|
||||
"tengu_teleport_resume_error"
|
||||
"tengu_teleport_error_invalid_teleport_headers_json"
|
||||
"tengu_teleport_error_failed_to_load_conversation"
|
||||
"tengu_teleport_resume_success"
|
||||
"tengu_teleport_errors_detected"
|
||||
"tengu_teleport_errors_resolved"
|
||||
"tengu_teleport_error_session_not_found_404"
|
||||
"tengu_message_selector_opened"
|
||||
"tengu_message_selector_selected"
|
||||
"tengu_message_selector_restore_option_selected"
|
||||
"tengu_message_selector_cancelled"
|
||||
"tengu_grove_policy_viewed"
|
||||
"tengu_grove_policy_submitted"
|
||||
"tengu_grove_policy_dismissed"
|
||||
"tengu_grove_policy_escaped"
|
||||
"tengu_grove_privacy_settings_viewed"
|
||||
"tengu_grove_print_viewed"
|
||||
"tengu_grove_policy_toggled"
|
||||
"tengu_auto_compact_succeeded"
|
||||
"tengu_model_fallback_triggered"
|
||||
"tengu_query_error"
|
||||
"tengu_post_autocompact_turn"
|
||||
"tengu_fallback_system_msg"
|
||||
"tengu_steering_attachment_resending"
|
||||
"tengu_pre_stop_hooks_cancelled"
|
||||
"tengu_stop_hook_error"
|
||||
"tengu_tool_use_error"
|
||||
"tengu_tool_use_cancelled"
|
||||
"tengu_pre_tool_hooks_cancelled"
|
||||
"tengu_pre_tool_hook_error"
|
||||
"tengu_tool_use_can_use_tool_rejected"
|
||||
"tengu_tool_use_can_use_tool_allowed"
|
||||
"tengu_tool_use_success"
|
||||
"tengu_tool_use_progress"
|
||||
"tengu_post_tool_hooks_cancelled"
|
||||
"tengu_post_tool_hook_error"
|
||||
"tengu_unary_event"
|
||||
"tengu_tool_use_show_permission_request"
|
||||
"tengu_ext_will_show_diff"
|
||||
"tengu_ext_diff_accepted"
|
||||
"tengu_ext_diff_rejected"
|
||||
"tengu_input_slash_missing"
|
||||
"tengu_input_slash_invalid"
|
||||
"tengu_input_prompt"
|
||||
"tengu_input_command"
|
||||
"tengu_auto_updater_success"
|
||||
"tengu_auto_updater_fail"
|
||||
"tengu_native_auto_updater_success"
|
||||
"tengu_native_auto_updater_fail"
|
||||
"tengu_auto_migrate_to_native_attempt"
|
||||
"tengu_auto_migrate_to_native_success"
|
||||
"tengu_auto_migrate_to_native_partial"
|
||||
"tengu_auto_migrate_to_native_failure"
|
||||
"tengu_auto_migrate_to_native_ui_shown"
|
||||
"tengu_auto_migrate_to_native_ui_success"
|
||||
"tengu_auto_migrate_to_native_ui_error"
|
||||
"tengu_external_editor_hint_shown"
|
||||
"tengu_input_background"
|
||||
"tengu_status_line_mount"
|
||||
"tengu_input_bash"
|
||||
"tengu_add_memory_start"
|
||||
"tengu_add_memory_success"
|
||||
"tengu_add_memory_failure"
|
||||
"tengu_input_memory"
|
||||
"tengu_help_toggled"
|
||||
"tengu_thinking_toggled"
|
||||
"tengu_paste_text"
|
||||
"tengu_paste_image"
|
||||
"tengu_ext_at_mentioned"
|
||||
"tengu_mode_cycle"
|
||||
"tengu_timer"
|
||||
"tengu_toggle_todos"
|
||||
"tengu_cancel"
|
||||
"tengu_tool_use_granted_in_config"
|
||||
"tengu_tool_use_denied_in_config"
|
||||
"tengu_tool_use_rejected_in_prompt"
|
||||
"tengu_tool_use_granted_in_prompt_permanent"
|
||||
"tengu_tool_use_granted_in_prompt_temporary"
|
||||
"tengu_sonnet_1m_notice_shown"
|
||||
"tengu_opusplan_notice_shown"
|
||||
"tengu_switch_to_subscription_notice_shown"
|
||||
"tengu_cache_warming_request"
|
||||
"tengu_feedback_survey_config"
|
||||
"tengu_feedback_survey_event"
|
||||
"tengu_tip_shown"
|
||||
"tengu_cost_threshold_reached"
|
||||
"tengu_concurrent_onquery_detected"
|
||||
"tengu_concurrent_onquery_blocked"
|
||||
"tengu_cost_threshold_acknowledged"
|
||||
"tengu_agent_tool_selected"
|
||||
"tengu_agent_tool_completed"
|
||||
"tengu_agent_parse_error"
|
||||
"tengu_agent_definition_generated"
|
||||
"tengu_agent_created"
|
||||
"tengu_model_command_menu"
|
||||
"tengu_model_command_inline_help"
|
||||
"tengu_model_command_inline"
|
||||
"tengu_output_style_command_menu"
|
||||
"tengu_output_style_command_inline_help"
|
||||
"tengu_output_style_command_inline"
|
||||
"tengu_session_persistence_failed"
|
||||
"tengu_apiKeyHelper_missing_trust"
|
||||
"tengu_atomic_write_error"
|
||||
"tengu_node_warning"
|
||||
"tengu_session_quality_classification"
|
||||
"tengu_trust_dialog_shown"
|
||||
"tengu_trust_dialog_accept"
|
||||
"tengu_mcp_multidialog_choice"
|
||||
"tengu_mcp_dialog_choice"
|
||||
"tengu_bypass_permissions_mode_dialog_shown"
|
||||
"tengu_bypass_permissions_mode_dialog_accept"
|
||||
"tengu_migrate_apikeyhelper_success"
|
||||
"tengu_migrate_apikeyhelper_error"
|
||||
"tengu_migrate_globalconfig_env_success"
|
||||
"tengu_migrate_globalconfig_env_error"
|
||||
"tengu_migrate_autoupdates_to_settings"
|
||||
"tengu_migrate_autoupdates_error"
|
||||
"tengu_forced_migration_start"
|
||||
"tengu_forced_migration_success"
|
||||
"tengu_forced_migration_failure"
|
||||
"tengu_migrate_mcp_approval_fields_success"
|
||||
"tengu_migrate_mcp_approval_fields_error"
|
||||
"tengu_continue_print"
|
||||
"tengu_teleport_print"
|
||||
"tengu_resume_print"
|
||||
"tengu_update_check"
|
||||
"tengu_claude_install_command"
|
||||
"tengu_teleport_resume_session"
|
||||
"tengu_teleport_cancelled"
|
||||
"tengu_grove_policy_exited"
|
||||
"tengu_startup_telemetry"
|
||||
"tengu_exit"
|
||||
"tengu_flicker"
|
||||
"tengu_stdin_interactive"
|
||||
"tengu_code_prompt_ignored"
|
||||
"tengu_single_word_prompt"
|
||||
"tengu_mcp_tools_tokens_count"
|
||||
"tengu_init"
|
||||
"tengu_startup_manual_model_config"
|
||||
"tengu_continue"
|
||||
"tengu_remote_create_session"
|
||||
"tengu_remote_create_session_error"
|
||||
"tengu_remote_create_session_success"
|
||||
"tengu_teleport_interactive_mode"
|
||||
"tengu_config_get"
|
||||
"tengu_config_set"
|
||||
"tengu_config_remove"
|
||||
"tengu_config_delete"
|
||||
"tengu_config_list"
|
||||
"tengu_config_add"
|
||||
"tengu_mcp_start"
|
||||
"tengu_mcp_add"
|
||||
"tengu_mcp_delete"
|
||||
"tengu_mcp_list"
|
||||
"tengu_mcp_get"
|
||||
"tengu_mcp_reset_mcpjson_choices"
|
||||
"tengu_migrate_installer_command"
|
||||
"tengu_setup_token_command"
|
||||
"tengu_doctor_command"
|
||||
File diff suppressed because one or more lines are too long
42
docs/research/claude-code-rvsource/versions/v2.0.x/README.md
Normal file
42
docs/research/claude-code-rvsource/versions/v2.0.x/README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Claude Code v2.0.77 (2.0 series)
|
||||
|
||||
## Binary RVF Container
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Version | 2.0.77 |
|
||||
| Series | 2.0 |
|
||||
| Bundle size | 10.5MB |
|
||||
| RVF size | 405.3KB |
|
||||
| Vectors | 785 |
|
||||
| RVF File ID | `6c9f5dde1ca78a28ea90df777cfa50b8` |
|
||||
| Classes | 1612 |
|
||||
| Functions | 20395 |
|
||||
| Modules | 9 |
|
||||
| Extracted | 2026-04-02T23:29:01+00:00 |
|
||||
|
||||
## Files
|
||||
|
||||
- `claude-code-v2.0.rvf` - Binary RVF container with HNSW index + witness chain
|
||||
- `claude-code-v2.0.rvf.manifest.json` - Container manifest (vector ID map, metadata)
|
||||
- `source/` - Extracted JavaScript module fragments
|
||||
|
||||
## RVF Container Details
|
||||
|
||||
The `.rvf` file is a real binary container created with the `@ruvector/rvf-node`
|
||||
native backend. It contains:
|
||||
|
||||
- **128-dimensional fingerprint vectors** for each code fragment
|
||||
- **HNSW index** (M=16, ef_construction=200) for fast similarity search
|
||||
- **Cosine distance** metric
|
||||
- **Witness chain** for provenance verification
|
||||
|
||||
To query this container:
|
||||
|
||||
```typescript
|
||||
import { RvfDatabase } from '@ruvector/rvf';
|
||||
|
||||
const db = await RvfDatabase.openReadonly('./claude-code-v2.0.rvf');
|
||||
const results = await db.query(queryVector, 10);
|
||||
await db.close();
|
||||
```
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,45 @@
|
|||
name:"sharp",description:"High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images"
|
||||
name:"logout",description:"Sign out from your Anthropic account"
|
||||
name:"extra-usage",description:"Configure extra usage to keep working when limits are hit"
|
||||
name:"clear",description:"Clear conversation history and free up context"
|
||||
name:"navigate",description:"Navigate to a URL, or go forward/back in browser history. If you don't have a valid tab ID, use tabs_context_mcp first to get available tabs."
|
||||
name:"add-dir",description:"Add a new working directory"
|
||||
name:"feedback",description:"Submit feedback about Claude Code"
|
||||
name:"compact",description:"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]"
|
||||
name:"config",description:"Open config panel"
|
||||
name:"context",description:"Visualize current context usage as a colored grid"
|
||||
name:"cost",description:"Show the total cost and duration of the current session"
|
||||
name:"discover",description:"Explore Claude Code features and track your progress"
|
||||
name:"doctor",description:"Diagnose and verify your Claude Code installation and settings"
|
||||
name:"memory",description:"Edit Claude memory files"
|
||||
name:"help",description:"Show help and available commands"
|
||||
name:"ide",description:"Manage IDE integrations and show status"
|
||||
name:"init",description:"Initialize a new CLAUDE.md file with codebase documentation"
|
||||
name:"install-github-app",description:"Set up Claude GitHub Actions for a repository"
|
||||
name:"install-slack-app",description:"Install the Claude Slack app"
|
||||
name:"mcp",description:"Manage MCP servers"
|
||||
name:"pr-comments",description:"Get comments from a GitHub pull request"
|
||||
name:"rename",description:"Rename the current conversation"
|
||||
name:"resume",description:"Resume a conversation"
|
||||
name:"review",description:"Review a pull request"
|
||||
name:"skills",description:"List available skills"
|
||||
name:"status",description:"Show Claude Code status including version, model, account, API connectivity, and tool statuses"
|
||||
name:"todos",description:"List current todo items"
|
||||
name:"security-review",description:"Complete a security review of the pending changes on the current branch"
|
||||
name:"usage",description:"Show plan usage limits"
|
||||
name:"theme",description:"Change the theme"
|
||||
name:"vim",description:"Toggle between Vim and Normal editing modes"
|
||||
name:"think-back",description:"Your 2025 Claude Code Year in Review"
|
||||
name:"thinkback-play",description:"Play the thinkback animation"
|
||||
name:"plan",description:"Enable plan mode or view the current session plan"
|
||||
name:"passes",description:"Share a free week of Claude Code with friends"
|
||||
name:"privacy-settings",description:"View and update your privacy settings"
|
||||
name:"hooks",description:"Manage hook configurations for tool events"
|
||||
name:"files",description:"List all files currently in context"
|
||||
name:"agents",description:"Manage agent configurations"
|
||||
name:"chrome",description:"Claude in Chrome (Beta) settings"
|
||||
name:"stickers",description:"Order Claude Code stickers"
|
||||
name:"export",description:"Export the current conversation to a file or clipboard"
|
||||
name:"upgrade",description:"Upgrade to Max for higher rate limits and more Opus"
|
||||
name:"stats",description:"Show your Claude Code usage statistics and activity"
|
||||
name:"install",description:"Install Claude Code native build"
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
if(B){let Z=B[1]||"";Q=Q.replace(/<analysis>[\s\S]*?<\/analysis>/,`Analysis:
|
||||
${Z.trim()}`)}let G=Q.match(/<summary>([\s\S]*?)<\/summary>/);if(G){let Z=G[1]||"";Q=Q.replace(/<summary>[\s\S]*?<\/summary>/,`Summary:
|
||||
${Z.trim()}`)}return Q=Q.replace(/\n\n+/g,`
|
||||
|
||||
`),Q.trim()}function i31(A,Q,B){let Z=`This session is being continued from a previous conversation that ran out of context. The conversation is summarized below:
|
||||
${el8(A)}.`;if(B)Z+=`
|
||||
|
||||
If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: ${B}`;if(Q)return`${Z}
|
||||
Please continue the conversation from where we left it off without asking the user any further questions. Continue with the last task that you were asked to work on.`;return Z}var ZrB="https://claude.com/claude-code";var zC="command-name",qz="command-message",v50="local-command-caveat",oH="task-notification",_L="task-id",n31="task-type",jL="output-file",Nz="status",wz="summary",k50="reason",pWA,cWA;var _K=w(()=>{pWA=["help","-h","--help"],cWA=["list","show","display","current","view","get","check","describe","print","version","about","status","?"]});function a31(){if(LuA()==="remote")return{commit:"",pr:""};let A=goQ(J3()),Q=`\uD83E\uDD16 Generated with [Claude Code](${ZrB})`,B=`Co-Authored-By: ${A} <noreply@anthropic.com>`,G=q8();if(G.attribution)return{commit:G.attribution.commit??B,pr:G.attribution.pr??Q};if(G.includeCoAuthoredBy===!1)return{commit:"",pr:""};return{commit:B,pr:Q}}var o31=w(()=>{j0();AB();u2();l4();YI();rQA();k1();h1();_K()});function r31(){let A=process.env.BASH_DEFAULT_TIMEOUT_MS;if(A){let Q=parseInt(A,10);if(!isNaN(Q)&&Q>0)return Q}return 120000}function YrB(){let A=process.env.BASH_MAX_TIMEOUT_MS;if(A){let Q=parseInt(A,10);if(!isNaN(Q)&&Q>0)return Math.max(Q,r31())}return Math.max(600000,r31())}function mTA(){let A=VuA.validate(process.env.BASH_MAX_OUTPUT_LENGTH);if(A.status==="capped")k(`BASH_MAX_OUTPUT_LENGTH ${A.message}`)
|
||||
|
||||
else if(L.startsWith(ea))throw l("tengu_compact_failed",{reason:"prompt_too_long",preCompactTokenCount:Y}),Error(hm5);let O=qsB(Q.readFileState);Q.readFileState.clear();let[M,j]=await Promise.all([um5(O,Q,km5),pm5(Q)]),_=[...M,...j],P=mm5(Q.agentId??q0());if(P)_.push(P);let v=Hz0(Q.agentId);if(v)_.push(v);let x=dm5();if(x)_.push(x);Q.setSpinnerMessage?.("Running SessionStart hooks...");let m=await yL("compact"),u=OI([$]),e=Qo($);l("tengu_compact",{preCompactTokenCount:Y,postCompactTokenCount:u,compactionInputTokens:e?.input_tokens,compactionOutputTokens:e?.output_tokens,compactionCacheReadTokens:e?.cache_read_input_tokens??0,compactionCacheCreationTokens:e?.cache_creation_input_tokens??0,compactionTotalTokens:e?e.input_tokens+(e.cache_creation_input_tokens??0)+(e.cache_read_input_tokens??0)+e.output_tokens:0,...X});let t=YW1(Z?"auto":"manual",Y??0),b=Es(q0()),p=[N0({content:i31(L,B,b),isCompactSummary:!0,isVisibleInTranscriptOnly:!0})];return{boundaryMarker:t,summaryMessages:p,attachments:_,hookResults:m,userDisplayMessage:K,preCompactTokenCount:Y,postCompactTokenCount:u,compactionUsage:e}}catch(Y){throw gm5(Y,Q),Y}finally{Q.setStreamMode?.("requesting"),Q.setResponseLength?.(()=>0),Q.setSpinnerMessage?.(null),Q.setSDKStatus?.(null),Q.setSpinnerColor?.(null),Q.setSpinnerShimmerColor?.(null)}}function gm5(A,Q){if(!ZCA(A,AkA)&&!ZCA(A,evA))Q.addNotification?.({key:"error-compacting-conversation",text:"Error compacting conversation",priority:"immediate",color:"error"})}async function um5(A,Q,B){let G=Object.entries(A).map(([J,X])=>({filename:J,...X})).filter((J)=>!cm5(J.filename,Q.agentId)).sort((J,X)=>X.timestamp-J.timestamp).slice(0,B),Z=await Promise.all(G.map(async(J)=>{let X=await Wz0(J.filename,{...Q,fileReadingLimits:{maxTokens:fm5}},"tengu_post_compact_file_restore_success","tengu_post_compact_file_restore_error","compact");return X?o9(X):null})),Y=0;return Z.filter((J)=>{if(J===null)return!1;let X=PG(Q1(J));if(Y+X<=bm5)return Y+=X,!0;return!1})}function mm5(A){let Q=Nm(A);if(Q.length===0)return null
|
||||
|
||||
function am5(){return`IMPORTANT: This message and these instructions are NOT part of the actual user conversation. Do NOT include any references to "note-taking", "session notes extraction", or these update instructions in the notes content.
|
||||
|
||||
Based on the user conversation above (EXCLUDING this note-taking instruction message as well as system prompt, claude.md entries, or any past session summaries), update the session notes file.
|
||||
|
||||
The file {{notesPath}} has already been read for you. Here are its current contents:
|
||||
<current_notes_content>
|
||||
{{currentNotes}}
|
||||
</current_notes_content>
|
||||
|
||||
Your ONLY task is to use the Edit tool to update the notes file, then stop. You can make multiple edits (update every section as needed) - make all Edit tool calls in parallel in a single message. Do not call any other tools.
|
||||
|
||||
CRITICAL RULES FOR EDITING:
|
||||
- The file must maintain its exact structure with all sections, headers, and italic descriptions intact
|
||||
-- NEVER modify, delete, or add section headers (the lines starting with '#' like # Task specification)
|
||||
-- NEVER modify or delete the italic _section description_ lines (these are the lines in italics immediately following each header - they start and end with underscores)
|
||||
-- The italic _section descriptions_ are TEMPLATE INSTRUCTIONS that must be preserved exactly as-is - they guide what content belongs in each section
|
||||
-- ONLY update the actual content that appears BELOW the italic _section descriptions_ within each existing section
|
||||
-- Do NOT add any new sections, summaries, or information outside the existing structure
|
||||
- Do NOT reference this note-taking process or instructions anywhere in the notes
|
||||
- It's OK to skip updating a section if there are no substantial new insights to add. Do not add filler content like "No info yet", just leave sections blank/unedited if appropriate.
|
||||
- Write DETAILED, INFO-DENSE content for each section - include specifics like file paths, function names, error messages, exact commands, technical details, etc.
|
||||
- For "Key results", include the complete, exact output the user requested (e.g., full table, full answer, etc.)
|
||||
- Do not include information that's already in the CLAUDE.md files included in the context
|
||||
- Keep each section under ~${gx2} tokens/words - if a section is approaching this limit, condense it by cycling out less important details while preserving the most critical information
|
||||
- Focus on actionable, specific information that would help someone understand or recreate the work discussed in the conversation
|
||||
- IMPORTANT: Always update "Current State" to reflect the most recent work - this is critical for continuity after compaction
|
||||
|
||||
Use the Edit tool with file_path: {{notesPath}}
|
||||
|
||||
STRUCTURE PRESERVATION REMINDER:
|
||||
Each section has TWO parts that must be preserved exactly as they appear in the current file:
|
||||
1. The section header (line starting with #)
|
||||
2. The italic description line (the _italicized text_ immediately after the header - this is a template instruction)
|
||||
|
||||
You ONLY update the actual content that comes AFTER these two preserved lines. The italic description lines starting and ending with underscores are part of the template structure, NOT content to be edited or removed.
|
||||
|
||||
REMEMBER: Use the Edit tool in parallel and stop. Do not continue after the edits. Only include insights from the actual user conversation, never from these note-taking instructions. Do not delete or change section headers or italic _section descriptions_.`}async function Ez0(){let A=jA(),Q=hx2(yQ(),"session-memory","config","template.md")
|
||||
|
||||
else Q+=PG(Q1(G))}return Math.ceil(Q*1.3333333333333333)}function Yd5(A){return XW1.push(A),()=>{XW1=XW1.filter((Q)=>Q!==A)}}function Jd5(){XW1.forEach((A)=>A())}async function kd(A,Q,B){if(IW1=!1,G0(process.env.DISABLE_MICROCOMPACT))return{messages:A};G0(process.env.USE_API_CONTEXT_MANAGEMENT);let G=Q!==void 0,Z=G?Q:Qd5,Y=[],J=new Map;for(let D of A)if((D.type==="user"||D.type==="assistant")&&Array.isArray(D.message.content)){for(let F of D.message.content)if(F.type==="tool_use"&&Gd5.has(F.name)){if(!$z0.has(F.id))Y.push(F.id)}else if(F.type==="tool_result"&&Y.includes(F.tool_use_id)){let E=Zd5(F.tool_use_id,F);J.set(F.tool_use_id,E)}}let X=Y.slice(-Bd5),I=Array.from(J.values()).reduce((D,F)=>D+F,0),W=0,K=new Set;for(let D of Y){if(X.includes(D))continue;if(I-W>Z)K.add(D),W+=J.get(D)||0}if(!G){let D=OI(A);if(!bd(D).isAboveWarningThreshold||W<Ad5)K.clear(),W=0}let V=(D)=>{return $z0.has(D)||K.has(D)};if(K.size>0,K.size>0)A.filter((F)=>F&&F.type==="attachment"&&F.attachment.type==="memory"&&!Cz0.has(F.uuid)).map((F)=>({uuid:F.uuid})).forEach((F)=>Cz0.add(F.uuid));let H=[];for(let D of A){if(D.type==="attachment"&&Cz0.has(D.uuid))continue;if(D.type!=="user"&&D.type!=="assistant"){H.push(D);continue}if(!Array.isArray(D.message.content)){H.push(D);continue}if(D.type==="user"){let F=[],E=!1;for(let z of D.message.content)if(z.type==="tool_result"&&V(z.tool_use_id)&&z.content&&!em5(z.content)){E=!0;let $=mZ0;if(kH("tengu_compact_mc_files")){let L=await i2A(z.content,z.tool_use_id);if(!n2A(L))$=`${Y71}Tool result saved to: ${L.filepath}
|
||||
|
||||
Use ${m6} to view${uZ0}`}F.push({...z,content:$})}else F.push(z);if(F.length>0){let z=E?void 0:D.toolUseResult;H.push({...D,message:{...D.message,content:F},toolUseResult:z})}}else{let F=[];for(let E of D.message.content)F.push(E);H.push({...D,message:{...D.message,content:F}})}}if(B&&K.size>0){let D=new Map,F=new Set
|
||||
|
||||
for(let E of A)if((E.type==="user"||E.type==="assistant")&&Array.isArray(E.message.content)){for(let z of E.message.content)if(z.type==="tool_use"&&z.name===m6){let $=z.input?.file_path;if(typeof $==="string")if(K.has(z.id))D.set($,z.id);else F.add($)}}for(let[E]of D)if(!F.has(E))B.readFileState.delete(E)}for(let D of K)$z0.add(D);if(K.size>0)return l("tengu_microcompact",{toolsCompacted:K.size,totalUncompactedTokens:I,tokensAfterCompaction:I-W,tokensSaved:W,triggerType:G?"manual":"auto"}),IW1=!0,Jd5(),{messages:H};return{messages:H}}function lx2(){let[A,Q]=WW1.useState(IW1);return WW1.useEffect(()=>{return Yd5(()=>{Q(IW1)})},[]),A}var WW1,Ad5=20000,Qd5=40000,Bd5=3,px2=2000,Gd5,$z0,Cz0,dx2,IW1=!1,XW1;var f4A=w(()=>{lR();S3();C0();cQ();oQ();EC();Fs();CK();bT();MQA();KL();Sm();B0();WW1=c(XA(),1);Gd5=new Set([m6,H9,SX,UI,VR,EI,x3,yZ]),$z0=new Set,Cz0=new Set,dx2=new Map,XW1=[]});function KW1(){return kH("tengu_session_memory")&&kH("tengu_sm_compact")}function Xd5(A,Q,B,G){let Z=OI(A),Y=YW1("auto",Z??0),J=[N0({content:i31(Q,!0),isCompactSummary:!0,isVisibleInTranscriptOnly:!0})],X=Hz0(G);return{boundaryMarker:Y,summaryMessages:J,attachments:X?[X]:[],hookResults:[],messagesToKeep:B,preCompactTokenCount:Z,postCompactTokenCount:Uz0(J)}}async function VW1(A,Q,B){if(!KW1())return null;await Rx2();let G=Lx2(),Z=_x2();if(!Z)return null;if(await ux2(Z))return l("tengu_sm_compact_empty_template",{}),null;try{let Y;if(G){let W=A.findIndex((K)=>K.uuid===G);if(W===-1)Y=[],l("tengu_sm_compact_summarized_id_not_found",{});else Y=A.slice(W+1)}else Y=[],l("tengu_sm_compact_resumed_session",{});let J=Xd5(A,Z,Y,Q),X=[J.boundaryMarker,...J.summaryMessages,...J.attachments,...J.hookResults,...Y],I=Uz0(X);if(B!==void 0&&I>=B)return l("tengu_sm_compact_threshold_exceeded",{postCompactTokenCount:I,autoCompactThreshold:B}),null;return{...J,postCompactTokenCount:I}}catch{return null}}var HW1=w(()=>{QkA();EC();oQ();GkA();zz0();S3();C0();f4A()});function _DA(){let A=J3(),Q=wz0(A)
|
||||
|
||||
return R$(A,Vw())-Q}function ix2(){let A=_DA(),Q=A-qz0,B=process.env.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE;if(B){let G=parseFloat(B);if(!isNaN(G)&&G>0&&G<=100){let Z=Math.floor(A*(G/100));return Math.min(Z,Q)}}return Q}function bd(A){let Q=ix2(),B=fd()?Q:_DA(),G=Math.max(0,Math.round((B-A)/B*100)),Z=B-Id5,Y=B-Wd5,J=A>=Z,X=A>=Y,I=fd()&&A>=Q,W=J3(),V=R$(W,Vw())-Nz0,H=process.env.CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE,D=H?parseInt(H,10):NaN,F=!isNaN(D)&&D>0?D:V,E=A>=F;return{percentLeft:G,isAboveWarningThreshold:J,isAboveErrorThreshold:X,isAboveAutoCompactThreshold:I,isAtBlockingLimit:E}}function fd(){if(G0(process.env.DISABLE_COMPACT))return!1;if(G0(process.env.DISABLE_AUTO_COMPACT))return!1;return T1().autoCompactEnabled}async function Kd5(A,Q){if(Q==="session_memory")return!1;if(!fd())return!1;let B=OI(A),{isAboveAutoCompactThreshold:G}=bd(B);return G}async function nx2(A,Q,B){if(G0(process.env.DISABLE_COMPACT))return{wasCompacted:!1};if(!await Kd5(A,B))return{wasCompacted:!1};let Z=await VW1(A,Q.agentId,ix2());if(Z)return{wasCompacted:!0,compactionResult:Z};try{let Y=await ZW1(A,Q,!0,void 0,!0);return PDA(void 0),{wasCompacted:!0,compactionResult:Y}}catch(Y){if(!ZCA(Y,AkA))r(Y instanceof Error?Y:Error(String(Y)));return{wasCompacted:!1}}}var qz0=13000,Id5=20000,Wd5=20000,Nz0=3000;var Fs=w(()=>{EC();QkA();k1();KQ();kJ();u2();IZ();cx();j0();cQ();HW1();GkA()});function Lz0(A){return Number.isInteger(A)}function ax2(A){if(typeof A==="string"&&A!=="unset")return A;if(typeof A==="number"){if(A<=30)return"low";if(A<=60)return"medium";return"high"}return"medium"}function h4A(){let A=process.env.CLAUDE_CODE_EFFORT_LEVEL;if(A){if(A==="unset")return;let G=parseInt(A,10);if(!isNaN(G)&&Lz0(G))return G;if(["low","medium","high"].includes(A))return A}let B=UQ().effortLevel;if(B==="unset")return;if(B!==void 0){if(typeof B==="number"&&Lz0(B))return B;if(typeof B==="string"&&["low","medium","high"].includes(B))return B}return}var YkA=w(()=>{AB()});var SDA=U((sx2)=>{Object.defineProperty(sx2,"__esModule",{value:!0})
|
||||
|
||||
return n8.createElement(_B7,{key:j,message:A,addMargin:B,tools:G,progressMessagesForMessage:W,param:M,style:H,verbose:Y,imageIndex:_??O,isUserContinuation:$,messages:Q})}))}case"system":if(A.subtype==="compact_boundary")return n8.createElement(Pa2,null);if(A.subtype==="local_command")return n8.createElement(F6A,{addMargin:B,param:{type:"text",text:A.content},verbose:Y});return n8.createElement(ja2,{message:A,addMargin:B,verbose:Y});case"grouped_tool_use":return n8.createElement(xa2,{message:A,tools:G,normalizedMessages:Q,resolvedToolUseIDs:I,erroredToolUseIDs:J,inProgressToolUseIDs:X,shouldAnimate:K});case"collapsed_read_search":return n8.createElement(da2,{message:A,resolvedToolUseIDs:I,erroredToolUseIDs:J,inProgressToolUseIDs:X,shouldAnimate:K,verbose:Y,tools:G,normalizedMessages:Q,isActiveGroup:z})}}function _B7({message:A,addMargin:Q,tools:B,progressMessagesForMessage:G,param:Z,style:Y,verbose:J,imageIndex:X,isUserContinuation:I,messages:W}){let{columns:K}=QB();switch(Z.type){case"text":return n8.createElement(F6A,{addMargin:Q,param:Z,verbose:J,thinkingMetadata:A.thinkingMetadata,planContent:A.planContent});case"image":return n8.createElement(jV1,{imageId:X,addMargin:Q&&!I});case"tool_result":return n8.createElement(uc2,{param:Z,message:A,messages:W,progressMessagesForMessage:G,style:Y,tools:B,verbose:J,width:K-5});default:return}}function jB7({param:A,addMargin:Q,tools:B,commands:G,verbose:Z,erroredToolUseIDs:Y,inProgressToolUseIDs:J,resolvedToolUseIDs:X,progressMessagesForMessage:I,shouldAnimate:W,shouldShowDot:K,width:V,inProgressToolCallCount:H,isTranscriptMode:D,messages:F,onOpenRateLimitOptions:E,thinkingBlockId:z,lastThinkingBlockId:$}){switch(A.type){case"tool_use":return n8.createElement(lc2,{param:A,addMargin:Q,tools:B,commands:G,verbose:Z,erroredToolUseIDs:Y,inProgressToolUseIDs:J,resolvedToolUseIDs:X,progressMessagesForMessage:I,shouldAnimate:W,shouldShowDot:K,inProgressToolCallCount:H,messages:F})
|
||||
|
||||
if(_.plugin_repository=x,_.plugin_name=v.name,v.version)_.plugin_version=v.version}l("tengu_input_command",_);let P=E.length>0&&E[0]&&Wp(E[0]);return{messages:z||E.every(Wo2)||P?E:[IE(),...E],shouldQuery:z,allowedTools:$,maxThinkingTokens:L,model:O,resultText:j}}async function mB7(A,Q,B,G,Z,Y,J,X){let I=nS(A,G.options.commands);if(I.type==="prompt"&&I.userInvocable!==!1)hV1(A);if(I.userInvocable===!1)return{messages:[N0({content:cC({inputString:`/${A}`,precedingInputBlocks:Z})}),N0({content:`This slash command can only be invoked by Claude, not directly by users. Ask Claude to run /${A} for you.`})],shouldQuery:!1,command:I};try{switch(I.type){case"local-jsx":return new Promise((W)=>{I.call((K,V)=>{if(B(null),V?.display==="skip"){W({messages:[],shouldQuery:!1,command:I});return}W({messages:V?.display==="system"?[GN0(wbA(I,Q)),GN0(`<local-command-stdout>${K}</local-command-stdout>`)]:[N0({content:cC({inputString:wbA(I,Q),precedingInputBlocks:Z})}),K?N0({content:`<local-command-stdout>${K}</local-command-stdout>`}):N0({content:`<local-command-stdout>${ML}</local-command-stdout>`})],shouldQuery:V?.shouldQuery??!1,command:I})},G,Q).then((K)=>{if(G.options.isNonInteractiveSession){W({messages:[],shouldQuery:!1,command:I});return}B({jsx:K,shouldHidePromptInput:!0,showSpinner:!1,isLocalJSXCommand:!1})})});case"local":{let W=N0({content:cC({inputString:wbA(I,Q),precedingInputBlocks:Z})});try{let K=IE(),V=await I.call(Q,G);if(V.type==="skip")return{messages:[],shouldQuery:!1,command:I};if(!G.options.isNonInteractiveSession)process.stdout.write("\x1B[?25l");if(V.type==="compact"){let{boundaryMarker:H,summaryMessages:D,attachments:F,hookResults:E}=V.compactionResult
|
||||
|
||||
var dt2=w(()=>{PA();$4();X9();CC();U9();O2A();i4();A8();f7=c(XA(),1),pbA=c(XA(),1)});function pH1({session:A}){if(A.status==="completed")return cbA.default.createElement(C,{bold:!0,color:"success",dimColor:!0},"done");if(A.status==="failed")return cbA.default.createElement(C,{bold:!0,color:"error",dimColor:!0},"error");if(!A.todoList.length)return cbA.default.createElement(C,{dimColor:!0},A.status,"…");let Q=A.todoList.filter((G)=>G.status==="completed").length,B=A.todoList.length;return cbA.default.createElement(C,{dimColor:!0},Q,"/",B)}var cbA;var zw0=w(()=>{PA();cbA=c(XA(),1)});import{randomUUID as Q67}from"crypto";function pt2(A){return A.flatMap((Q)=>{switch(Q.type){case"assistant":return[{type:"assistant",message:Q.message,uuid:Q.uuid,requestId:void 0,timestamp:new Date().toISOString()}];case"user":return[{type:"user",message:Q.message,uuid:Q.uuid??Q67(),timestamp:new Date().toISOString(),isMeta:Q.isSynthetic}];case"system":if(Q.subtype==="compact_boundary"){let B=Q;return[{type:"system",content:"Conversation compacted",level:"info",subtype:"compact_boundary",compactMetadata:{trigger:B.compact_metadata.trigger,preTokens:B.compact_metadata.pre_tokens},uuid:Q.uuid,timestamp:new Date().toISOString()}]}return[];default:return[]}})}function ct2(A){return A.flatMap((Q)=>{switch(Q.type){case"assistant":return[{type:"assistant",message:Q.message,session_id:q0(),parent_tool_use_id:null,uuid:Q.uuid,error:Q.error}];case"user":return[{type:"user",message:Q.message,session_id:q0(),parent_tool_use_id:null,uuid:Q.uuid,isSynthetic:Q.isMeta||Q.isVisibleInTranscriptOnly}];case"system":if(Q.subtype==="compact_boundary"&&Q.compactMetadata)return[{type:"system",subtype:"compact_boundary",session_id:q0(),uuid:Q.uuid,compact_metadata:{trigger:Q.compactMetadata.trigger,pre_tokens:Q.compactMetadata.preTokens}}];return[]
|
||||
|
||||
if(M?.lastShownTime){if(Date.now()-M.lastShownTime<X.minTimeBetweenGlobalFeedbackMs)return!1}return!0},[F,Q,L,Y.feedbackSurvey.timeLastShown,Y.feedbackSurvey.submitCountAtLastAppearance,B,X.minTimeBetweenGlobalFeedbackMs,X.minUserTurnsBetweenFeedback,X.minTimeBeforeFeedbackMs,X.minUserTurnsBeforeFeedback,X.probability]);return vN.useEffect(()=>{if(O)E()},[O,E]),{state:F,handleSelect:z}}var vN,G87;var u09=w(()=>{S3();C0();ii();KQ();u2();cQ();pB();oQ();xL0();vN=c(XA(),1),G87={minTimeBeforeFeedbackMs:600000,minTimeBetweenGlobalFeedbackMs:1e8,minUserTurnsBeforeFeedback:5,minUserTurnsBetweenFeedback:10,hideThanksAfterMs:3000,onForModels:["*"],probability:0.005}});function X87(A,Q){let B=A.findIndex((G)=>G.uuid===Q);if(B===-1)return!1;for(let G=B+1;G<A.length;G++){let Z=A[G];if(Z&&(Z.type==="user"||Z.type==="assistant"))return!0}return!1}function m09(A,Q){let[B,G]=FO.useState(null),Z=FO.useRef(new Set),Y=FO.useRef(null),J=FO.useCallback((H)=>{let D=KW1();l("tengu_post_compact_survey_event",{event_type:"appeared",appearance_id:H,session_memory_compaction_enabled:D})},[]),X=FO.useCallback((H,D)=>{let F=KW1();l("tengu_post_compact_survey_event",{event_type:"responded",appearance_id:H,response:D,session_memory_compaction_enabled:F})},[]),{state:I,open:W,handleSelect:K}=gD1({hideThanksAfterMs:Z87,onOpen:J,onSelect:X});FO.useEffect(()=>{Yz(Y87).then(G)},[]);let V=FO.useMemo(()=>new Set(A.filter((H)=>Wp(H)).map((H)=>H.uuid)),[A]);return FO.useEffect(()=>{if(I!=="closed"||Q)return;if(B!==!0)return;if(JW())return;if(G0(process.env.CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY))return;if(Y.current!==null){if(X87(A,Y.current)){if(Y.current=null,Math.random()<J87)W();return}}let H=Array.from(V).filter((D)=>!Z.current.has(D));if(H.length>0)Z.current=new Set(V),Y.current=H[H.length-1]},[V,I,Q,B,A,W]),{state:I,handleSelect:K}}var FO,Z87=3000,Y87="tengu_post_compact_survey",J87=0.2;var d09=w(()=>{S3();C0();ii();cQ();oQ();xL0();HW1();FO=c(XA(),1)});function p09({onSelect:A,inputValue:Q,setInputValue:B,message:G=K87}){let Z=bI.useRef(Q)
|
||||
|
||||
continue}if(RA.type==="assistant"||RA.type==="user"||RA.type==="progress"||RA.type==="system"&&RA.subtype==="compact_boundary")v.push(RA),await LO0([RA],H,MA).catch((kA)=>k(`Failed to record sidechain transcript: ${kA}`)),MA=RA.uuid,yield RA}if(x.signal.aborted)throw new cY;if(T_(A)&&A.callback)A.callback()}finally{if(await b(),A.hooks)Xp(B.setAppState,H)}}function OO0(A){let Q=new Set;for(let B of A)if(B?.type==="user"){let Z=B.message.content;if(Array.isArray(Z)){for(let Y of Z)if(Y.type==="tool_result"&&Y.tool_use_id)Q.add(Y.tool_use_id)}}return A.filter((B)=>{if(B?.type==="assistant"){let Z=B.message.content;if(Array.isArray(Z))return!Z.some((J)=>J.type==="tool_use"&&J.id&&!Q.has(J.id))}return!0})}async function B77(A,Q,B,G){try{let Z=A.getSystemPrompt({toolUseContext:Q});return await ifA([Z],B,G)}catch(Z){return await ifA([c39],B,G)}}var C6A=w(()=>{Ht();kJ();ZO();bS();id();u2();wR();o4A();fS();cq();VF1();vL();p39();tb();G_();l4();h1();UbA();U9();oF();B2();oQ();mV1();rs();QZ();sq();gC()});function I77(A){let Q=0,B=N7(A);for(let G of B)if(G.type==="assistant"){for(let Z of G.message.content)if(Z.type==="tool_use")Q++}return Q}function RO0(A,Q,B){let{prompt:G,resolvedAgentModel:Z,isBuiltInAgent:Y,startTime:J}=B,X=Ff(A);if(X===void 0)throw Error("No assistant messages found");let I=X.message.content.filter((V)=>V.type==="text"),W=p31(X.message.usage),K=I77(A);return l("tengu_agent_tool_completed",{model:Z,prompt_char_count:G.length,response_char_count:I.length,assistant_message_count:A.length,total_tool_uses:K,duration_ms:Date.now()-J,total_tokens:W,is_built_in_agent:Y}),{agentId:Q,content:I,totalDurationMs:Date.now()-J,totalTokens:W,totalToolUseCount:K,usage:X.message.usage}}var jO0,G77=2000,AN0,Z77,Y77,J77,X77,Ts;var RkA=w(()=>{m5A();r2();tG();oQ();th2();AS();u2();kJ();C0();C6A();EC();oQ();xV1();pKA();CC();fS();o4A();CK();YL0();ZO();l4();CD0();h1();id();Dd1()
|
||||
|
||||
wZ7={aliases:["bug"],type:"local-jsx",name:"feedback",description:"Submit feedback about Claude Code",argumentHint:"[report]",isEnabled:()=>!(G0(process.env.CLAUDE_CODE_USE_BEDROCK)||G0(process.env.CLAUDE_CODE_USE_VERTEX)||G0(process.env.CLAUDE_CODE_USE_FOUNDRY)||process.env.DISABLE_FEEDBACK_COMMAND||process.env.DISABLE_BUG_COMMAND||process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC),isHidden:!1,async call(A,{abortController:Q,messages:B},G){let Z=G||"";return NZ7(A,Q.signal,B,Z)},userFacingName(){return"feedback"}},t79=wZ7});var AG9=w(()=>{hHA();o31()});var QG9=w(()=>{hHA();o31()});var LZ7,BG9;var GG9=w(()=>{bS();rF();QkA();f4A();HW1();GkA();k1();x6();DV1();cQ();QZ();LZ7={type:"local",name:"compact",description:"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]",isEnabled:()=>!G0(process.env.DISABLE_COMPACT),isHidden:!1,supportsNonInteractive:!0,argumentHint:"<optional custom summarization instructions>",async call(A,Q){M9("compact");let{abortController:B,messages:G}=Q;if(G.length===0)throw Error("No messages to compact");let Z=A.trim();try{if(!Z){let K=await VW1(G,Q.agentId);if(K){fV.cache.clear?.(),cK.cache.clear?.();let V=W6A("tip"),H=[...Q.options.verbose?[]:["(ctrl+o to see full summary)"],...V?[V]:[]];return{type:"compact",compactionResult:K,displayText:V1.dim("Compacted "+H.join(`
|
||||
`))}}}let J=(await kd(G,void 0,Q)).messages,X=await ZW1(J,Q,!1,Z);PDA(void 0),fV.cache.clear?.(),cK.cache.clear?.();let I=W6A("tip"),W=[...Q.options.verbose?[]:["(ctrl+o to see full summary)"],...X.userDisplayMessage?[X.userDisplayMessage]:[],...I?[I]:[]];return{type:"compact",compactionResult:X,displayText:V1.dim("Compacted "+W.join(`
|
||||
`))}}catch(Y){if(B.signal.aborted)throw Error("Compaction canceled.");else if(Y instanceof Error&&Y.message===evA)throw Error(evA);else throw r(Y instanceof Error?Y:Error(String(Y))),Error(`Error during compaction: ${Y}`)}},userFacingName(){return"compact"}},BG9=LZ7});function ZG9({context:A,flat:Q}={}){let B=cK(),G=[]
|
||||
|
||||
return N0({content:`Result of calling the ${A.name} tool: ${Q1(B.content)}`,isMeta:!0})}catch{return N0({content:`Result of calling the ${A.name} tool: Error`,isMeta:!0})}}function shA(A,Q){return N0({content:`Called the ${A} tool with the following input: ${Q1(Q)}`,isMeta:!0})}function ZS(A,Q,B,G){return{type:"system",subtype:"informational",content:A,isMeta:!1,timestamp:new Date().toISOString(),uuid:OO(),toolUseID:B,level:Q,...G&&{preventContinuation:G}}}function e59(A,Q,B,G,Z,Y,J,X){return{type:"system",subtype:"stop_hook_summary",hookCount:A,hookInfos:Q,hookErrors:B,preventedContinuation:G,stopReason:Z,hasOutput:Y,level:J,timestamp:new Date().toISOString(),uuid:OO(),toolUseID:X}}function u39(A){return{type:"system",subtype:"turn_duration",durationMs:A,timestamp:new Date().toISOString(),uuid:OO(),isMeta:!1}}function GN0(A){return{type:"system",subtype:"local_command",content:A,level:"info",timestamp:new Date().toISOString(),uuid:OO(),isMeta:!1}}function YW1(A,Q){return{type:"system",subtype:"compact_boundary",content:"Conversation compacted",isMeta:!1,timestamp:new Date().toISOString(),uuid:OO(),level:"info",compactMetadata:{trigger:A,preTokens:Q}}}function ArB(A,Q,B,G){return{type:"system",subtype:"api_error",level:"error",cause:A.cause instanceof Error?A.cause:void 0,error:A,retryInMs:Q,retryAttempt:B,maxRetries:G,timestamp:new Date().toISOString(),uuid:OO()}}function Wp(A){return A?.type==="system"&&A.subtype==="compact_boundary"}function rD7(A){for(let Q=A.length-1;Q>=0;Q--){let B=A[Q];if(B&&Wp(B))return Q}return-1}function TS(A){let Q=rD7(A);if(Q===-1)return A;return A.slice(Q)}function hw0(A,Q){if(A.type!=="user")return!0;if(A.isMeta)return!1;if(A.isVisibleInTranscriptOnly&&!Q)return!1;return!0}function GW1(A){if(A.type!=="assistant")return!1;if(!Array.isArray(A.message.content))return!1;return A.message.content.every((Q)=>Q.type==="thinking")}function OL0(A,Q,B){let G=0;for(let Z of A){if(!Z)continue
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
return}yield*B}async function jrB(A,Q,B){return(await vi8({messages:A,tools:Q},"token-count",async()=>({tokenCount:await B()}))).tokenCount}var i50=w(()=>{a3();B2();cQ();CQ();B0();luA();$dA();oQ();isA();mM();B0()});function n50(A){let Q=A.filter((G)=>G.isMcp);if(Q.length===0)return`Search for or select MCP tools to make them available for use.
|
||||
|
||||
**MANDATORY PREREQUISITE - THIS IS A HARD REQUIREMENT**
|
||||
|
||||
You MUST use this tool to load MCP tools BEFORE calling them directly.
|
||||
|
||||
This is a BLOCKING REQUIREMENT - MCP tools listed below are NOT available until you load them using this tool.
|
||||
|
||||
**Why this is non-negotiable:**
|
||||
- MCP tools are deferred and not loaded until discovered via this tool
|
||||
- Calling an MCP tool without first loading it will fail
|
||||
|
||||
**Query modes:**
|
||||
|
||||
1. **Direct selection** - Use \`select:<tool_name>\` when you know exactly which tool you need:
|
||||
- "select:mcp__slack__read_channel"
|
||||
- "select:mcp__filesystem__list_directory"
|
||||
- Returns just that tool if it exists
|
||||
|
||||
2. **Keyword search** - Use keywords when you're unsure which tool to use:
|
||||
- "list directory" - find tools for listing directories
|
||||
- "read file" - find tools for reading files
|
||||
- "slack message" - find slack messaging tools
|
||||
- Returns up to 5 matching tools ranked by relevance
|
||||
|
||||
**CORRECT Usage Patterns:**
|
||||
|
||||
<example>
|
||||
User: List files in the src directory
|
||||
Assistant: I can see mcp__filesystem__list_directory in the available tools. Let me select it.
|
||||
[Calls MCPSearch with query: "select:mcp__filesystem__list_directory"]
|
||||
[Calls the MCP tool]
|
||||
</example>
|
||||
|
||||
<example>
|
||||
User: I need to work with slack somehow
|
||||
Assistant: Let me search for slack tools.
|
||||
[Calls MCPSearch with query: "slack"]
|
||||
Assistant: Found several options including mcp__slack__read_channel.
|
||||
[Calls the MCP tool]
|
||||
</example>
|
||||
|
||||
**INCORRECT Usage Pattern - NEVER DO THIS:**
|
||||
|
||||
<bad-example>
|
||||
User: Read my slack messages
|
||||
Assistant: [Directly calls mcp__slack__read_channel without loading it first]
|
||||
WRONG - You must load the tool FIRST using this tool
|
||||
</bad-example>`
|
||||
|
||||
return`Search for or select MCP tools to make them available for use.
|
||||
|
||||
**MANDATORY PREREQUISITE - THIS IS A HARD REQUIREMENT**
|
||||
|
||||
You MUST use this tool to load MCP tools BEFORE calling them directly.
|
||||
|
||||
This is a BLOCKING REQUIREMENT - MCP tools listed below are NOT available until you load them using this tool.
|
||||
|
||||
**Why this is non-negotiable:**
|
||||
- MCP tools are deferred and not loaded until discovered via this tool
|
||||
- Calling an MCP tool without first loading it will fail
|
||||
|
||||
**Query modes:**
|
||||
|
||||
1. **Direct selection** - Use \`select:<tool_name>\` when you know exactly which tool you need:
|
||||
- "select:mcp__slack__read_channel"
|
||||
- "select:mcp__filesystem__list_directory"
|
||||
- Returns just that tool if it exists
|
||||
|
||||
2. **Keyword search** - Use keywords when you're unsure which tool to use:
|
||||
- "list directory" - find tools for listing directories
|
||||
- "read file" - find tools for reading files
|
||||
- "slack message" - find slack messaging tools
|
||||
- Returns up to 5 matching tools ranked by relevance
|
||||
|
||||
**CORRECT Usage Patterns:**
|
||||
|
||||
<example>
|
||||
User: List files in the src directory
|
||||
Assistant: I can see mcp__filesystem__list_directory in the available tools. Let me select it.
|
||||
[Calls MCPSearch with query: "select:mcp__filesystem__list_directory"]
|
||||
[Calls the MCP tool]
|
||||
</example>
|
||||
|
||||
<example>
|
||||
User: I need to work with slack somehow
|
||||
Assistant: Let me search for slack tools.
|
||||
[Calls MCPSearch with query: "slack"]
|
||||
Assistant: Found several options including mcp__slack__read_channel.
|
||||
[Calls the MCP tool]
|
||||
</example>
|
||||
|
||||
**INCORRECT Usage Pattern - NEVER DO THIS:**
|
||||
|
||||
<bad-example>
|
||||
User: Read my slack messages
|
||||
Assistant: [Directly calls mcp__slack__read_channel without loading it first]
|
||||
WRONG - You must load the tool FIRST using this tool
|
||||
</bad-example>
|
||||
|
||||
Available MCP tools (must be loaded before use):
|
||||
${Q.map((G)=>G.name).join(`
|
||||
`)}`}var $m="MCPSearch";var yrB={}
|
||||
|
||||
q9=class q9 extends Error{constructor(A,Q,B){super(`MCP error ${A}: ${Q}`);this.code=A,this.data=B,this.name="McpError"}static fromError(A,Q,B){if(A===X4.UrlElicitationRequired&&B){let G=B;if(G.elicitations)return new osB(G.elicitations,Q)}return new q9(A,Q,B)}};osB=class osB extends q9{constructor(A,Q=`URL elicitation${A.length>1?"s":""} required`){super(X4.UrlElicitationRequired,Q,{elicitations:A})}get elicitations(){var A,Q;return(Q=(A=this.data)===null||A===void 0?void 0:A.elicitations)!==null&&Q!==void 0?Q:[]}}});function Ho(A){return A==="completed"||A==="failed"||A==="cancelled"}var ma8;var g81=w(()=>{ma8=Symbol("Let zodToJsonSchema decide on which parser to use")});var x70=w(()=>{g81()});var oR=()=>{};var y70=w(()=>{PK()});var v70=()=>{};var u81=w(()=>{PK()});var k70=w(()=>{PK()});var b70=()=>{};var f70=w(()=>{PK()});var h70=w(()=>{PK();oR()});var g70=w(()=>{PK()});var Q8Z;var m81=w(()=>{Q8Z=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789")});var d81=w(()=>{PK();m81();u81();oR()});var u70=w(()=>{PK();d81();oR()});var m70=w(()=>{oR()});var p81=w(()=>{PK()});var d70=w(()=>{PK();p81()});var p70=()=>{};var c70=w(()=>{PK()});var l70=w(()=>{PK();oR()});var i70=w(()=>{PK()});var n70=w(()=>{PK()});var a70=w(()=>{PK()});var o70=w(()=>{PK()});var r70=w(()=>{oR()});var s70=w(()=>{oR()});var t70=w(()=>{PK()});var e70=w(()=>{oR();y70();v70();u81();k70();b70();f70();h70();g70();u70();m70();d70();p70();c70();l70();i70();n70();d81();a70();m81();o70();r70();p81();s70();t70()});var PK=w(()=>{g81();e70();oR()});var rsB=()=>{};var AG0=w(()=>{PK();x70();oR()});var ssB=w(()=>{AG0();g81();x70();PK();rsB();oR();y70();v70();u81();k70();b70();f70();h70();g70();u70();m70();d70();p70();c70();l70();i70();n70();t70();d81();a70();m81();o70();r70();p81();s70();e70();AG0()});function QG0(A){let Q=sWA(A),B=Q===null||Q===void 0?void 0:Q.method;if(!B)throw Error("Schema is missing a method literal");let G=SsB(B);if(typeof G!=="string")throw Error("Schema method literal must be a string")
|
||||
|
||||
return A};ZZ0.get=(A,Q="full")=>{let G=(Q==="fast"?VKA.fastFormats:VKA.fullFormats)[A];if(!G)throw Error(`Unknown format "${A}"`);return G};function y02(A,Q,B,G){var Z,Y;(Z=(Y=A.opts.code).formats)!==null&&Z!==void 0||(Y.formats=GZ0._`require("ajv-formats/dist/formats").${G}`);for(let J of Q)A.addFormat(J,B[J])}v02.exports=bPA=ZZ0;Object.defineProperty(bPA,"__esModule",{value:!0});bPA.default=ZZ0});function QQ5(){let A=new b02.Ajv({strict:!1,validateFormats:!0,validateSchema:!1,allErrors:!0});return f02.default(A),A}class fPA{constructor(A){this._ajv=A!==null&&A!==void 0?A:QQ5()}getValidator(A){var Q;let B="$id"in A&&typeof A.$id==="string"?(Q=this._ajv.getSchema(A.$id))!==null&&Q!==void 0?Q:this._ajv.compile(A):this._ajv.compile(A);return(G)=>{if(B(G))return{valid:!0,data:G,errorMessage:void 0};else return{valid:!1,data:void 0,errorMessage:this._ajv.errorsText(B.errors)}}}}var b02,f02;var YZ0=w(()=>{b02=c(_51(),1),f02=c(k02(),1)});class JZ0{constructor(A){this._client=A}async*callToolStream(A,Q=qC,B){var G;let Z=this._client,Y={...B,task:(G=B===null||B===void 0?void 0:B.task)!==null&&G!==void 0?G:Z.isToolTask(A.name)?{}:void 0},J=Z.requestStream({method:"tools/call",params:A},Q,Y),X=Z.getToolOutputValidator(A.name);for await(let I of J){if(I.type==="result"&&X){let W=I.result;if(!W.structuredContent&&!W.isError){yield{type:"error",error:new q9(X4.InvalidRequest,`Tool ${A.name} has an output schema but did not return structured content`)};return}if(W.structuredContent)try{let K=X(W.structuredContent);if(!K.valid){yield{type:"error",error:new q9(X4.InvalidParams,`Structured content does not match the tool's output schema: ${K.errorMessage}`)};return}}catch(K){if(K instanceof q9){yield{type:"error",error:K};return}yield{type:"error",error:new q9(X4.InvalidParams,`Failed to validate structured content: ${K instanceof Error?K.message:String(K)}`)}
|
||||
|
||||
switch(A){case"sampling/createMessage":if(!this._capabilities.sampling)throw Error(`Client does not support sampling capability (required for ${A})`);break;case"elicitation/create":if(!this._capabilities.elicitation)throw Error(`Client does not support elicitation capability (required for ${A})`);break;case"roots/list":if(!this._capabilities.roots)throw Error(`Client does not support roots capability (required for ${A})`);break;case"tasks/get":case"tasks/list":case"tasks/result":case"tasks/cancel":if(!this._capabilities.tasks)throw Error(`Client does not support tasks capability (required for ${A})`);break;case"ping":break}}assertTaskCapability(A){var Q,B;T51((B=(Q=this._serverCapabilities)===null||Q===void 0?void 0:Q.tasks)===null||B===void 0?void 0:B.requests,A,"Server")}assertTaskHandlerCapability(A){var Q;if(!this._capabilities)return;P51((Q=this._capabilities.tasks)===null||Q===void 0?void 0:Q.requests,A,"Client")}async ping(A){return this.request({method:"ping"},wm,A)}async complete(A,Q){return this.request({method:"completion/complete",params:A},T70,Q)}async setLoggingLevel(A,Q){return this.request({method:"logging/setLevel",params:{level:A}},wm,Q)}async getPrompt(A,Q){return this.request({method:"prompts/get",params:A},L70,Q)}async listPrompts(A,Q){return this.request({method:"prompts/list",params:A},XPA,Q)}async listResources(A,Q){return this.request({method:"resources/list",params:A},y2A,Q)}async listResourceTemplates(A,Q){return this.request({method:"resources/templates/list",params:A},z70,Q)}async readResource(A,Q){return this.request({method:"resources/read",params:A},v2A,Q)}async subscribeResource(A,Q){return this.request({method:"resources/subscribe",params:A},wm,Q)}async unsubscribeResource(A,Q){return this.request({method:"resources/unsubscribe",params:A},wm,Q)}async callTool(A,Q=qC,B){if(this.isToolTaskRequired(A.name))throw new q9(X4.InvalidRequest,`Tool "${A.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`)
|
||||
|
||||
let G=await this.request({method:"tools/call",params:A},Q,B),Z=this.getToolOutputValidator(A.name);if(Z){if(!G.structuredContent&&!G.isError)throw new q9(X4.InvalidRequest,`Tool ${A.name} has an output schema but did not return structured content`);if(G.structuredContent)try{let Y=Z(G.structuredContent);if(!Y.valid)throw new q9(X4.InvalidParams,`Structured content does not match the tool's output schema: ${Y.errorMessage}`)}catch(Y){if(Y instanceof q9)throw Y;throw new q9(X4.InvalidParams,`Failed to validate structured content: ${Y instanceof Error?Y.message:String(Y)}`)}}return G}isToolTask(A){var Q,B,G,Z;if(!((Z=(G=(B=(Q=this._serverCapabilities)===null||Q===void 0?void 0:Q.tasks)===null||B===void 0?void 0:B.requests)===null||G===void 0?void 0:G.tools)===null||Z===void 0?void 0:Z.call))return!1;return this._cachedKnownTaskTools.has(A)}isToolTaskRequired(A){return this._cachedRequiredTaskTools.has(A)}cacheToolMetadata(A){var Q;this._cachedToolOutputValidators.clear(),this._cachedKnownTaskTools.clear(),this._cachedRequiredTaskTools.clear();for(let B of A){if(B.outputSchema){let Z=this._jsonSchemaValidator.getValidator(B.outputSchema);this._cachedToolOutputValidators.set(B.name,Z)}let G=(Q=B.execution)===null||Q===void 0?void 0:Q.taskSupport;if(G==="required"||G==="optional")this._cachedKnownTaskTools.add(B.name);if(G==="required")this._cachedRequiredTaskTools.add(B.name)}}getToolOutputValidator(A){return this._cachedToolOutputValidators.get(A)}async listTools(A,Q){let B=await this.request({method:"tools/list",params:A},WPA,Q);return this.cacheToolMetadata(B.tools),B}async sendRootsListChanged(){return this.notification({method:"notifications/roots/list_changed"})}}});class hPA{append(A){this._buffer=this._buffer?Buffer.concat([this._buffer,A]):A}readMessage(){if(!this._buffer)return null;let A=this._buffer.indexOf(`
|
||||
`);if(A===-1)return null;let Q=this._buffer.toString("utf8",0,A).replace(/\r$/,"")
|
||||
|
||||
if(Z){if(G.ruleContent!==void 0)return{valid:!1,error:"MCP rules do not support patterns in parentheses",suggestion:`Use "${G.toolName}" without parentheses, or use "mcp__${Z.serverName}__*" for all tools`,examples:[`mcp__${Z.serverName}`,`mcp__${Z.serverName}__*`,Z.toolName&&Z.toolName!=="*"?`mcp__${Z.serverName}__${Z.toolName}`:void 0].filter(Boolean)};return{valid:!0}}if(!G.toolName||G.toolName.length===0)return{valid:!1,error:"Tool name cannot be empty"};if(G.toolName[0]!==G.toolName[0]?.toUpperCase())return{valid:!1,error:"Tool names must start with uppercase",suggestion:`Use "${String(G.toolName).charAt(0).toUpperCase()+String(G.toolName).slice(1)}"`};let Y=yB2(G.toolName);if(Y&&G.ruleContent!==void 0){let J=Y(G.ruleContent);if(!J.valid)return J}if(xB2(G.toolName)&&G.ruleContent!==void 0){let J=G.ruleContent;if(J.includes(":*")&&!J.endsWith(":*"))return{valid:!1,error:"The :* pattern must be at the end",suggestion:"Move :* to the end for prefix matching, or use * for wildcard matching",examples:["Bash(npm run:*) - prefix matching (legacy)","Bash(npm run *) - wildcard matching"]};if(J===":*")return{valid:!1,error:"Prefix cannot be empty before :*",suggestion:"Specify a command prefix before :*",examples:["Bash(npm:*)","Bash(git:*)"]};let X=['"',"'"];for(let I of X)if((J.match(new RegExp(I,"g"))||[]).length%2!==0)return{valid:!1,error:`Unmatched ${I} in Bash pattern`,suggestion:"Ensure all quotes are properly paired"};if(J==="*")return{valid:!1,error:'Use "Bash" without parentheses to allow all commands',suggestion:"Remove the parentheses or specify a command pattern",examples:["Bash","Bash(npm:*)","Bash(npm *)"]}}if(SB2(G.toolName)&&G.ruleContent!==void 0){let J=G.ruleContent;if(J.includes(":*"))return{valid:!1,error:'The ":*" syntax is only for Bash prefix rules',suggestion:'Use glob patterns like "*" or "**" for file matching',examples:[`${G.toolName}(*.ts) - matches .ts files`,`${G.toolName}(src/**) - matches all files in src`,`${G.toolName}(**/*.test.ts) - matches test files`]}
|
||||
|
||||
return Q}function aP2(){eg5.cache.clear?.()}var rg5="tengu_claudeai_mcp_connectors",sg5=5000,tg5="mcp-servers-2025-12-04",eg5;var bE0=w(()=>{t2();D5();vJ();tB();h1();cQ();S3();eg5=W0(async()=>{try{return{}}catch{return k("[claudeai-mcp] Fetch failed"),{}}})});import{join as vI1,dirname as Au5,parse as Qu5}from"path";function kI1(){return vI1(ew(),"managed-mcp.json")}function uvA(A,Q){if(!A)return{};let B={};for(let[G,Z]of Object.entries(A))B[G]={...Z,scope:Q};return B}function oP2(A){let Q=vI1(l1(),".mcp.json");rM(Q,Q1(A,null,2),{encoding:"utf8"})}function rP2(A){if(A.type!==void 0&&A.type!=="stdio")return null;let Q=A;return[Q.command,...Q.args]}function sP2(A,Q){if(A.length!==Q.length)return!1;return A.every((B,G)=>B===Q[G])}function tP2(A){return"url"in A?A.url:null}function Bu5(A){let B=A.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${B}$`)}function eP2(A,Q){return Bu5(Q).test(A)}function AS2(A,Q){let B=UQ();if(!B.deniedMcpServers)return!1;for(let G of B.deniedMcpServers)if(yKA(G)&&G.serverName===A)return!0;if(Q){let G=rP2(Q);if(G){for(let Y of B.deniedMcpServers)if(O71(Y)&&sP2(Y.serverCommand,G))return!0}let Z=tP2(Q);if(Z){for(let Y of B.deniedMcpServers)if(M71(Y)&&eP2(Z,Y.serverUrl))return!0}}return!1}function fE0(A,Q){if(AS2(A,Q))return!1;let B=UQ();if(!B.allowedMcpServers)return!0;if(B.allowedMcpServers.length===0)return!1;let G=B.allowedMcpServers.some(O71),Z=B.allowedMcpServers.some(M71);if(Q){let Y=rP2(Q),J=tP2(Q);if(Y)if(G){for(let X of B.allowedMcpServers)if(O71(X)&&sP2(X.serverCommand,Y))return!0;return!1}else{for(let X of B.allowedMcpServers)if(yKA(X)&&X.serverName===A)return!0;return!1}else if(J)if(Z){for(let X of B.allowedMcpServers)if(M71(X)&&eP2(J,X.serverUrl))return!0;return!1}else{for(let X of B.allowedMcpServers)if(yKA(X)&&X.serverName===A)return!0;return!1}else{for(let X of B.allowedMcpServers)if(yKA(X)&&X.serverName===A)return!0;return!1}}for(let Y of B.allowedMcpServers)if(yKA(Y)&&Y.serverName===A)return!0;return!1}function Gu5(A){let Q=[]
|
||||
|
||||
return X(),I}catch(I){throw X(),I}}}function pE0(){return parseInt(process.env.MCP_SERVER_CONNECTION_BATCH_SIZE||"",10)||3}function Hu5(){return parseInt(process.env.MCP_REMOTE_SERVER_CONNECTION_BATCH_SIZE||"",10)||20}function JS2(A){return!A.type||A.type==="stdio"||A.type==="sdk"}function Fu5(A){return!A.name.startsWith("mcp__ide__")||Du5.includes(A.name)}function dE0(A,Q){return`${A}-${Q1(Q)}`}async function Td(A,Q){let B=dE0(A,Q);try{let G=await tL(A,Q);if(G.type==="connected")await G.cleanup()}catch{}tL.cache.delete(B)}async function MKA(A){if(A.config.type==="sdk")return A;let Q=await tL(A.name,A.config);if(Q.type!=="connected")throw Error(`MCP server ${A.name} is not connected`);return Q}function WS2(A,Q){if(A.type!==Q.type)return!1;let{scope:B,...G}=A,{scope:Z,...Y}=Q;return Q1(G)===Q1(Y)}async function Pd(A,Q,B){return VS2({client:B,tool:A,args:Q,signal:v9().signal})}async function x4A(A,Q){try{await Td(A,Q);let B=await tL(A,Q);if(B.type!=="connected")return{client:B,tools:[],commands:[]};let G=!!B.capabilities?.resources,[Z,Y,J]=await Promise.all([RS(B),ivA(B),G?lvA(B):Promise.resolve([])]),X=[];if(G){if(![xm,ym].some((W)=>Z.some((K)=>K.name===W.name)))X.push(xm,ym)}return{client:B,tools:[...Z,...X],commands:Y,resources:J.length>0?J:void 0}}catch(B){return nG(A,`Error during reconnection: ${B instanceof Error?B.message:String(B)}`),{client:{name:A,type:"failed",config:Q},tools:[],commands:[]}}}async function XS2(A,Q,B){for(let G=0;G<A.length;G+=Q){let Z=A.slice(G,G+Q)
|
||||
|
||||
let W=y4A(),K,V=new Promise((z,$)=>{K=setTimeout(()=>{$(Error(`MCP tool call '${B}' timed out after ${Math.floor(W/1000)}s`))},W)}),H=await Promise.race([A.callTool({name:B,arguments:G,_meta:Z},qC,{signal:Y,timeout:W}),V]).finally(()=>{if(K)clearTimeout(K)});if("isError"in H&&H.isError){let z="Unknown error";if("content"in H&&Array.isArray(H.content)&&H.content.length>0){let $=H.content[0];if($&&typeof $==="object"&&"text"in $)z=$.text}else if("error"in H)z=String(H.error);throw nG(Q,z),Error(z)}let D=Date.now()-J,F=D<1000?`${D}ms`:D<60000?`${Math.floor(D/1000)}s`:`${Math.floor(D/60000)}m ${Math.floor(D%60000/1000)}s`;n0(Q,`Tool '${B}' completed successfully in ${F}`);let E=UQ2(Q);if(E)l("tengu_code_indexing_tool_used",{tool:E,source:"mcp",success:!0});return await zu5(H,B,Q)}catch(W){if(X!==void 0)clearInterval(X);if(I!==void 0)clearInterval(I);let K=Date.now()-J;if(W instanceof Error&&W.name!=="AbortError")n0(Q,`Tool '${B}' failed after ${Math.floor(K/1000)}s: ${W.message}`);if(!(W instanceof Error)||W.name!=="AbortError")throw W}finally{if(X!==void 0)clearInterval(X);if(I!==void 0)clearInterval(I)}}function $u5(A){if(A.message.content[0]?.type!=="tool_use")return;return A.message.content[0].id}async function HS2(A,Q){let B=[],G=[],Z=await Promise.allSettled(Object.entries(A).map(async([Y,J])=>{let X=new mE0(Y,Q),I=new x51({name:"claude-code",version:{ISSUES_EXPLAINER:"report the issue at https://github.com/anthropics/claude-code/issues",PACKAGE_URL:"@anthropic-ai/claude-code",README_URL:"https://code.claude.com/docs/en/overview",VERSION:"2.0.77",FEEDBACK_CHANNEL:"https://github.com/anthropics/claude-code/issues",BUILD_TIME:"2026-01-06T00:25:58Z"}.VERSION??"unknown"},{capabilities:{}});try{await I.connect(X);let W=I.getServerCapabilities(),K={type:"connected",name:Y,capabilities:W||{},client:I,config:{...J,scope:"dynamic"},cleanup:async()=>{await I.close()}},V=[];if(W?.tools){let H=await RS(K)
|
||||
|
||||
V.push(...H)}return{client:K,tools:V}}catch(W){return nG(Y,`Failed to connect SDK MCP server: ${W}`),{client:{type:"failed",name:Y,config:{...J,scope:"user"}},tools:[]}}}));for(let Y of Z)if(Y.status==="fulfilled")B.push(Y.value.client),G.push(...Y.value.tools);return{clients:B,tools:G}}var Vu5,IS2=60000,Du5,tL,RS,lvA,ivA,uI1;var sq=w(()=>{t2();vMA();g02();m02();JQ2();IQ2();PV();wQQ();k1();Zz();C0();hX();j0();tB();vJ();GI();e51();B71();bZ0();Sm();cQ();kX();pZ0();NQ2();NYA();ui();LZ();iQA();TQ2();K71();V71();_KA();gC();BS2();cPA();rH();OS();ZS2();B0();Vu5=new Set(["image/jpeg","image/png","image/gif","image/webp"]);Du5=["mcp__ide__executeCode","mcp__ide__getDiagnostics"];tL=W0(async(A,Q,B)=>{let G=Date.now();try{let Z,Y=l2A();if(Q.type==="sse"){let P=new r2A(A,Q),v=await fI1(A,Q),x={authProvider:P,fetch:YS2(p2A()),requestInit:{headers:{"User-Agent":K0A(),...v}}};x.eventSourceInit={fetch:async(m,u)=>{let e={},t=await P.tokens();if(t)e.Authorization=`Bearer ${t.access_token}`;let b=wYA();return fetch(m,{...u,...b,headers:{"User-Agent":K0A(),...e,...u?.headers,...v,Accept:"text/event-stream"}})}},Z=new t51(new URL(Q.url),x),n0(A,"SSE transport initialized, awaiting connection")}else if(Q.type==="sse-ide"){n0(A,`Setting up SSE-IDE transport to ${Q.url}`);let P=wYA(),v=P.dispatcher?{eventSourceInit:{fetch:async(x,m)=>{return fetch(x,{...m,...P,headers:{"User-Agent":K0A(),...m?.headers}})}}}:{};Z=new t51(new URL(Q.url),Object.keys(v).length>0?v:void 0)}else if(Q.type==="ws-ide"){let P=nm1(),v={headers:{"User-Agent":K0A(),...Q.authToken&&{"X-Claude-Code-Ide-Authorization":Q.authToken}},agent:OwA(Q.url),...P||{}},x=new yMA.default(Q.url,["mcp"],Object.keys(v).length>0?v:void 0);Z=new I71(x)}else if(Q.type==="ws"){n0(A,`Initializing WebSocket transport to ${Q.url}`);let P=await fI1(A,Q),v=nm1(),x={headers:{"User-Agent":K0A(),...Y&&{Authorization:`Bearer ${Y}`},...P},agent:OwA(Q.url),...v||{}};n0(A,`WebSocket transport options: ${Q1({url:Q.url,headers:x.headers,hasSessionAuth:!!Y})}`)
|
||||
|
||||
return wo(Q.tools).map((G)=>({...jQ2,name:`mcp__${Z8(A.name)}__${Z8(G.name)}`,originalMcpToolName:G.name,isMcp:!0,async description(){return G.description??""},async prompt(){return G.description??""},isConcurrencySafe(){return G.annotations?.readOnlyHint??!1},isReadOnly(){return G.annotations?.readOnlyHint??!1},isDestructive(){return G.annotations?.destructiveHint??!1},isOpenWorld(){return G.annotations?.openWorldHint??!1},inputJSONSchema:G.inputSchema,async call(Z,Y,J,X){let I=$u5(X),W=I?{"claudecode/toolUseId":I}:{},K=await MKA(A);return{data:await VS2({client:K,tool:G.name,args:Z,meta:W,signal:Y.abortController.signal})}},userFacingName(){let Z=G.annotations?.title||G.name;return`${A.name} - ${Z} (MCP)`},...EDA(A.name)?GS2(G.name):{}})).filter(Fu5)}catch(Q){return nG(A.name,`Failed to fetch tools: ${Q instanceof Error?Q.message:String(Q)}`),[]}}),lvA=W0(async(A)=>{if(A.type!=="connected")return[];try{if(!A.capabilities?.resources)return[];let Q=await A.client.request({method:"resources/list"},y2A);if(!Q.resources)return[];return Q.resources.map((B)=>({...B,server:A.name}))}catch(Q){return nG(A.name,`Failed to fetch resources: ${Q instanceof Error?Q.message:String(Q)}`),[]}}),ivA=W0(async(A)=>{if(A.type!=="connected")return[];try{if(!A.capabilities?.prompts)return[];let Q=await A.client.request({method:"prompts/list"},XPA);if(!Q.prompts)return[];return wo(Q.prompts).map((G)=>{let Z=Object.values(G.arguments??{}).map((Y)=>Y.name);return{type:"prompt",name:"mcp__"+Z8(A.name)+"__"+G.name,description:G.description??"",hasUserSpecifiedDescription:!!G.description,contentLength:0,isEnabled:()=>!0,isHidden:!1,isMcp:!0,progressMessage:"running",userFacingName(){let Y=G.title||G.name;return`${A.name}:${Y} (MCP)`},argNames:Z,source:"mcp",async getPromptForCommand(Y){let J=Y.split(" ");try{let X=await MKA(A),I=await X.client.getPrompt({name:G.name,arguments:NQQ(Z,J)})
|
||||
|
||||
i * i <= n; i++) {
|
||||
if (n % i === 0) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
</code>
|
||||
<commentary>
|
||||
Since a significant piece of code was written and the task was completed, now use the test-runner agent to run the tests
|
||||
</commentary>
|
||||
assistant: Now let me use the test-runner agent to run the tests
|
||||
assistant: Uses the ${Ts.name} tool to launch the test-runner agent
|
||||
</example>
|
||||
|
||||
<example>
|
||||
user: "Hello"
|
||||
<commentary>
|
||||
Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
|
||||
</commentary>
|
||||
assistant: "I'm going to use the ${Ts.name} tool to launch the greeting-responder agent"
|
||||
</example>
|
||||
`}var th2=w(()=>{RkA();CK();KL();tB()});import{randomBytes as Br5}from"crypto";function dC(A){if(typeof A!=="string")return null;return Gr5.test(A)?A:null}function GO(){return`a${Br5(3).toString("hex")}`}var Gr5;var ZO=w(()=>{Gr5=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i});import{randomUUID as Zr5}from"crypto";function FC0({tools:A,isBuiltIn:Q,isAsync:B=!1}){return A.filter((G)=>{if(G.name.startsWith("mcp__"))return!0;if(_kA.has(G.name))return!1;if(!Q&&Qg2.has(G.name))return!1;if(B&&!Bg2.has(G.name))return!1;return!0})}function Ps(A,Q,B=!1){let{tools:G,disallowedTools:Z,source:Y}=A,J=FC0({tools:Q,isBuiltIn:Y==="built-in",isAsync:B}),X=new Set(Z?.map((E)=>{let{toolName:z}=ZR(E);return z})??[]),I=J.filter((E)=>!X.has(E.name));if(G===void 0||G.length===1&&G[0]==="*")return{hasWildcard:!0,validTools:[],invalidTools:[],resolvedTools:I};let K=new Map;for(let E of I)K.set(E.name,E);let V=[],H=[],D=[],F=new Set;for(let E of G){let{toolName:z}=ZR(E);if(z===y3){V.push(E);continue}let $=K.get(z);if($){if(V.push(E),!F.has($))D.push($),F.add($)}else H.push(E)}return{hasWildcard:!1,validTools:V,invalidTools:H,resolvedTools:D}}function Ag2(A,Q){let B=N0({content:A}),G=Q.message.content.find((I)=>{if(I.type!=="tool_use"||I.name!==y3)return!1;let W=I.input;return"prompt"in W&&W.prompt===A})
|
||||
|
||||
let{servers:D,errors:F}=Q?{servers:{},errors:[]}:await CDA();if(V)return;Ts2(Z,F);let E={...D,...A};cE0(X,E).catch((O)=>{nG("useManageMcpConnections",`Failed to get MCP resources: ${O instanceof Error?O.message:String(O)}`)});let $={...E,...{}},L={enterprise:0,global:0,project:0,user:0,plugin:0,claudeai:0};for(let O of Object.values($))if(O.scope==="enterprise")L.enterprise++;else if(O.scope==="user")L.global++;else if(O.scope==="project")L.project++;else if(O.scope==="local")L.user++;else if(O.scope==="dynamic")L.plugin++;else if(O.scope==="claudeai")L.claudeai++;l("tengu_mcp_servers",L)}return H(),()=>{V=!0}},[Q,A,X,I,G.authVersion,Z]),lC.useEffect(()=>{let V=Y.current;return()=>{for(let H of V.values())clearTimeout(H);V.clear()}},[]),lC.useEffect(()=>{},[G.mcp.clients,Z]),lC.useEffect(()=>B?.updateClients(G.mcp.clients),[B,G.mcp.clients]),lC.useEffect(()=>B?.updateTools(G.mcp.tools),[B,G.mcp.tools]),lC.useEffect(()=>B?.updateResources(G.mcp.resources),[B,G.mcp.resources]);let W=lC.useCallback(async(V)=>{let H=G.mcp.clients.find((E)=>E.name===V);if(!H)throw Error(`MCP server ${V} not found`);let D=Y.current.get(V);if(D)clearTimeout(D),Y.current.delete(V);let F=await x4A(V,H.config);return X(F),F},[G.mcp.clients,X,Z]),K=lC.useCallback(async(V)=>{let H=G.mcp.clients.find((F)=>F.name===V);if(!H)throw Error(`MCP server ${V} not found`);if(H.type!=="disabled"){let F=Y.current.get(V);if(F)clearTimeout(F),Y.current.delete(V);if(uE0(V,!1),H.type==="connected")await Td(V,H.config);J({name:V,type:"disabled",config:H.config})}else{uE0(V,!0),J({name:V,type:"pending",config:H.config});let F=await x4A(V,H.config);X(F)}},[G.mcp.clients,J,X,Z]);return{reconnectMcpServer:W,toggleMcpServer:K}}function K47(A){switch(A){case"http":return"HTTP";case"ws":case"ws-ide":return"WebSocket";default:return"SSE"}}var lC,vFA=5,I47=1000,W47=30000;var Ss2=w(()=>{j0();sq();k1();PV();pB();GQQ();KQQ();gC();bE0();kX();h1();C0();_s2();lC=c(XA(),1)});function R6A(){let A=Dp.useContext(nN0)
|
||||
|
||||
if(!A)throw Error("useMcpReconnect must be used within MCPConnectionManager");return A.reconnectMcpServer}function Bt(){let A=Dp.useContext(nN0);if(!A)throw Error("useMcpToggleEnabled must be used within MCPConnectionManager");return A.toggleMcpServer}function wH1({children:A,dynamicMcpConfig:Q,isStrictMcpConfig:B,mcpCliEndpoint:G}){let{reconnectMcpServer:Z,toggleMcpServer:Y}=Ps2(Q,B,G),J=Dp.useMemo(()=>({reconnectMcpServer:Z,toggleMcpServer:Y}),[Z,Y]);return Dp.default.createElement(nN0.Provider,{value:J},A)}var Dp,nN0;var Fp=w(()=>{Ss2();Dp=c(XA(),1),nN0=Dp.createContext(null)});function ys2(A){return A.id.startsWith("mcp-server-")}function gbA(A,Q,B){if(Q<0||B.length===0)return B.length>0?0:-1;if(A.length===B.length&&A.every((Z,Y)=>Z.id===B[Y]?.id))return Math.min(Q,B.length-1);return 0}function vs2(A){let Q=A.metadata;return Q?.sessionId?`/resume ${Q.sessionId}`:`/resume ${A.displayText}`}function ks2(A){if(A.isQuoted)return A.token.slice(2).replace(/"$/,"");else if(A.token.startsWith("@"))return A.token.substring(1);else return A.token}function aN0(A){let{displayText:Q,mode:B,hasAtPrefix:G,needsQuotes:Z,isQuoted:Y,isComplete:J}=A,X=J?" ":"";if(Y||Z)return B==="bash"?`"${Q}"${X}`:`@"${Q}"${X}`;else if(G)return B==="bash"?`${Q}${X}`:`@${Q}${X}`;else return Q}function oN0(A,Q,B,G,Z,Y){let I=Q.slice(0,B).lastIndexOf(" ")+1,W;if(Y==="variable")W="$"+A.displayText+" ";else if(Y==="command")W=A.displayText+" ";else W=A.displayText;let K=Q.slice(0,I)+W+Q.slice(B);G(K),Z(I+W.length)}async function V47(A,Q){try{if(LH1)LH1.abort();return LH1=new AbortController,await Ns2(A,Q,LH1.signal)}catch{return l("tengu_shell_completion_failed",{}),[]}}function kFA(A,Q,B=!1){if(!A)return null;let G=A.substring(0,Q);if(B){let W=/@"([^"]*)"?$/,K=G.match(W);if(K&&K.index!==void 0){let H=A.substring(Q).match(/^[^"]*"?/),D=H?H[0]:"";return{token:K[0]+D,startPos:K.index,isQuoted:!0}}}let Z=B?/(@[a-zA-Z0-9_\-./\\()[\]~]*|[a-zA-Z0-9_\-./\\()[\]~]+)$/:/[a-zA-Z0-9_\-./\\()[\]~]+$/,Y=G.match(Z);if(!Y||Y.index===void 0)return null
|
||||
|
||||
let B=Math.min(this.reconnectDelay*Math.pow(1.5,this.reconnectAttempts-1),30000);Q.info(`[${A}] Reconnecting in ${Math.round(B)}ms (attempt ${this.reconnectAttempts})`),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},B)}handleResponse(A){if(this.responseCallback){let Q=this.responseCallback;this.responseCallback=null,Q(A)}}setNotificationHandler(A){this.notificationHandler=A}async ensureConnected(){let{serverName:A}=this.context;if(this.connected&&this.socket)return!0;if(!this.socket&&!this.connecting)await this.connect();return new Promise((Q,B)=>{let G=setTimeout(()=>{B(new c6A(`[${A}] Connection attempt timed out after 5000ms`))},5000),Z=()=>{if(this.connected)clearTimeout(G),Q(!0);else setTimeout(Z,100)};Z()})}async sendRequest(A,Q=30000){let{serverName:B}=this.context;if(!this.socket)throw new c6A(`[${B}] Cannot send request: not connected`);let G=this.socket;return new Promise((Z,Y)=>{let J=setTimeout(()=>{this.responseCallback=null,Y(new c6A(`[${B}] Tool request timed out after ${Q}ms`))},Q);this.responseCallback=(V)=>{clearTimeout(J),Z(V)};let X=JSON.stringify(A),I=Buffer.from(X,"utf-8"),W=Buffer.allocUnsafe(4);W.writeUInt32LE(I.length,0);let K=Buffer.concat([W,I]);G.write(K)})}async callTool(A,Q){let B={method:"execute_tool",params:{client_id:this.context.clientTypeId,tool:A,args:Q}};return this.sendRequestWithRetry(B)}async sendRequestWithRetry(A){let{serverName:Q,logger:B}=this.context;try{return await this.sendRequest(A)}catch(G){if(!(G instanceof c6A))throw G;return B.info(`[${Q}] Connection error, forcing reconnect and retrying: ${G.message}`),this.closeSocket(),await this.ensureConnected(),await this.sendRequest(A)}}isConnected(){return this.connected}closeSocket(){if(this.socket)this.socket.removeAllListeners(),this.socket.end(),this.socket.destroy(),this.socket=null;this.connected=!1,this.connecting=!1}cleanup(){if(this.reconnectTimer)clearTimeout(this.reconnectTimer),this.reconnectTimer=null
|
||||
|
||||
function uL0(){return`
|
||||
# Claude in Chrome browser automation
|
||||
|
||||
You have access to browser automation tools (mcp__claude-in-chrome__*) for interacting with web pages in Chrome. Follow these guidelines for effective browser automation.
|
||||
|
||||
## GIF recording
|
||||
|
||||
When performing multi-step browser interactions that the user may want to review or share, use mcp__claude-in-chrome__gif_creator to record them.
|
||||
|
||||
You must ALWAYS:
|
||||
* Capture extra frames before and after taking actions to ensure smooth playback
|
||||
* Name the file meaningfully to help the user identify it later (e.g., "login_process.gif")
|
||||
|
||||
## Console log debugging
|
||||
|
||||
You can use mcp__claude-in-chrome__read_console_messages to read console output. Console output may be verbose. If you are looking for specific log entries, use the 'pattern' parameter with a regex-compatible pattern. This filters results efficiently and avoids overwhelming output. For example, use pattern: "[MyApp]" to filter for application-specific logs rather than reading all console output.
|
||||
|
||||
## Alerts and dialogs
|
||||
|
||||
Do not trigger JavaScript alerts, confirms, prompts, or browser modal dialogs through your actions. These browser dialogs block all further browser events and will prevent the extension from receiving any subsequent commands. Instead, when possible, use console.log for debugging and then use the mcp__claude-in-chrome__read_console_messages tool to read those log messages. If a page has dialog-triggering elements:
|
||||
1. Avoid clicking buttons or links that may trigger alerts (e.g., "Delete" buttons with confirmation dialogs)
|
||||
2. If you must interact with such elements, warn the user first that this may interrupt the session
|
||||
3. Use mcp__claude-in-chrome__javascript_tool to check for and dismiss any existing dialogs before proceeding
|
||||
|
||||
If you accidentally trigger a dialog and lose responsiveness, inform the user they need to manually dismiss it in the browser.
|
||||
|
||||
## Avoid rabbit holes and loops
|
||||
|
||||
When using browser automation tools, stay focused on the specific task. If you encounter any of the following, stop and ask the user for guidance:
|
||||
- Unexpected complexity or tangential browser exploration
|
||||
- Browser tool calls failing or returning errors after 2-3 attempts
|
||||
- No response from the browser extension
|
||||
- Page elements not responding to clicks or input
|
||||
- Pages not loading or timing out
|
||||
- Unable to complete the browser task despite multiple approaches
|
||||
|
||||
Explain what you attempted, what went wrong, and ask how the user would like to proceed. Do not keep retrying the same failing browser action or explore unrelated pages without checking in first.
|
||||
|
||||
## Tab context and session startup
|
||||
|
||||
IMPORTANT: At the start of each browser automation session, call mcp__claude-in-chrome__tabs_context_mcp first to get information about the user's current browser tabs. Use this context to understand what the user might want to work with before creating new tabs.
|
||||
|
||||
Never reuse tab IDs from a previous/other session. Follow these guidelines:
|
||||
1. Only reuse an existing tab if the user explicitly asks to work with it
|
||||
2. Otherwise, create a new tab with mcp__claude-in-chrome__tabs_create_mcp
|
||||
3. If a tool returns an error indicating the tab doesn't exist or is invalid, call tabs_context_mcp to get fresh tab IDs
|
||||
4. When a tab is closed by the user or a navigation error occurs, call tabs_context_mcp to see what tabs are available
|
||||
`}var QQ9=`
|
||||
**IMPORTANT: Before using any chrome browser tools, you MUST first load them using MCPSearch.**
|
||||
|
||||
Chrome browser tools are MCP tools that require loading before use. Before calling any mcp__claude-in-chrome__* tool:
|
||||
1. Use MCPSearch with \`select:mcp__claude-in-chrome__<tool_name>\` to load the specific tool
|
||||
2. Then call the tool
|
||||
|
||||
For example, to get tab context:
|
||||
1. First: MCPSearch with query "select:mcp__claude-in-chrome__tabs_context_mcp"
|
||||
2. Then: Call mcp__claude-in-chrome__tabs_context_mcp
|
||||
|
||||
`
|
||||
|
||||
import{chmod as C87,mkdir as JQ9,readFile as XQ9,writeFile as IQ9,readdir as U87,access as BQ9}from"fs/promises";import{homedir as WQ9}from"os";import{join as oC}from"path";import{fileURLToPath as q87}from"url";function dD1(A){if(e2()&&A!==!0)return!1;if(A===!0)return!0;if(A===!1)return!1;if(G0(process.env.CLAUDE_CODE_ENABLE_CFC))return!0;if($X(process.env.CLAUDE_CODE_ENABLE_CFC))return!1;let Q=T1();if(Q.claudeInChromeDefaultEnabled!==void 0)return Q.claudeInChromeDefaultEnabled;return!1}function mL0(){let A=n7(),Q=rFA.map((B)=>`mcp__claude-in-chrome__${B.name}`);if(A){let B=`"${process.execPath}" --chrome-native-host`;return YQ9(B).then((G)=>ZQ9(G)),{mcpConfig:{[__]:{type:"stdio",command:process.execPath,args:["--claude-in-chrome-mcp"],scope:"dynamic"}},allowedTools:Q,systemPrompt:uL0()}}else{let B=q87(import.meta.url),G=oC(B,".."),Z=oC(G,"cli.js");return YQ9(`"${process.execPath}" "${Z}" --chrome-native-host`).then((J)=>ZQ9(J)),{mcpConfig:{[__]:{type:"stdio",command:"node",args:[`${Z}`,"--claude-in-chrome-mcp"],scope:"dynamic"}},allowedTools:Q,systemPrompt:uL0()}}}function L87(){let A=kQ(),Q=WQ9();switch(A){case"macos":return oC(Q,"Library","Application Support","Google","Chrome","NativeMessagingHosts");case"linux":return oC(Q,".config","google-chrome","NativeMessagingHosts");case"windows":{let B=process.env.APPDATA||oC(Q,"AppData","Local");return oC(B,"Claude Code","ChromeNativeHost")}case"wsl":default:return null}}async function ZQ9(A){let Q=L87();if(!Q)throw Error("Claude in Chrome Native Host not supported on this platform");let B=oC(Q,w87),G={name:mD1,description:"Claude Code Browser Extension Native Host",path:A,type:"stdio",allowed_origins:["chrome-extension://fcoeoabgfenejglbffodgkkbkcdhcgfn/",...[]]},Z=Q1(G,null,2);if(await XQ9(B,"utf-8").catch(()=>null)===Z)return;if(await JQ9(Q,{recursive:!0}),await IQ9(B,Z),kQ()==="windows")O87(B)
|
||||
|
||||
for(let{isConcurrencySafe:Y,blocks:J}of CG7(A,Z))if(Y){let X={};for await(let I of qG7(J,Q,B,Z)){if(I.contextModifier){let{toolUseID:W,modifyContext:K}=I.contextModifier;if(!X[W])X[W]=[];X[W].push(K)}yield{message:I.message,newContext:Z}}for(let I of J){let W=X[I.id];if(!W)continue;for(let K of W)Z=K(Z)}yield{newContext:Z}}else for await(let X of UG7(J,Q,B,Z)){if(X.newContext)Z=X.newContext;yield{message:X.message,newContext:Z}}}function CG7(A,Q){return A.reduce((B,G)=>{let Z=Q.options.tools.find((X)=>X.name===G.name),Y=Z?.inputSchema.safeParse(G.input),J=Y?.success?Boolean(Z?.isConcurrencySafe(Y.data)):!1;if(J&&B[B.length-1]?.isConcurrencySafe)B[B.length-1].blocks.push(G);else B.push({isConcurrencySafe:J,blocks:[G]});return B},[])}async function*UG7(A,Q,B,G){let Z=G;for(let Y of A){G.setInProgressToolUseIDs((J)=>new Set([...J,Y.id]));for await(let J of RF1(Y,Q.find((X)=>X.message.content.some((I)=>I.type==="tool_use"&&I.id===Y.id)),B,Z)){if(J.contextModifier)Z=J.contextModifier.modifyContext(Z);yield{message:J.message,newContext:Z}}r59(G,Y.id)}}async function*qG7(A,Q,B,G){yield*MFA(A.map(async function*(Z){G.setInProgressToolUseIDs((Y)=>new Set([...Y,Z.id])),yield*RF1(Z,Q.find((Y)=>Y.message.content.some((J)=>J.type==="tool_use"&&J.id===Z.id)),B,G),r59(G,Z.id)}),FG7())}function r59(A,Q){A.setInProgressToolUseIDs((B)=>new Set([...B].filter((G)=>G!==Q)))}function NG7(A,Q){if(!A.startsWith("mcp__"))return;let B=tH(A);if(!B)return;let G=Q.find((Z)=>Z8(Z.name)===B.serverName);if(G?.type==="connected")return G.config.type??"stdio";return}async function*RF1(A,Q,B,G){let Z=A.name,Y=uB1(G.options.tools,Z),J=Q.message.id,X=Q.requestId,I=NG7(Z,G.options.mcpClients)
|
||||
|
||||
if(!Y){l("tengu_tool_use_error",{error:`No such tool available: ${Z}`,toolName:Z,toolUseID:A.id,isMcp:Z.startsWith("mcp__"),queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),yield{message:N0({content:[{type:"tool_result",content:`<tool_use_error>Error: No such tool available: ${Z}</tool_use_error>`,is_error:!0,tool_use_id:A.id}],toolUseResult:`Error: No such tool available: ${Z}`,sourceToolAssistantUUID:Q.uuid})};return}let W=A.input;try{if(G.abortController.signal.aborted){l("tengu_tool_use_cancelled",{toolName:Y.name,toolUseID:A.id,isMcp:Y.isMcp??!1,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}});let K=ZM0(A.id);yield{message:N0({content:[K],toolUseResult:qFA,sourceToolAssistantUUID:Q.uuid})};return}for await(let K of wG7(Y,A.id,W,G,B,Q,J,X,I))yield K}catch(K){r(K instanceof Error?K:Error(String(K)));let V=K instanceof Error?K.message:String(K),D=`Error calling tool${Y?` (${Y.name})`:""}: ${V}`;yield{message:N0({content:[{type:"tool_result",content:`<tool_use_error>${D}</tool_use_error>`,is_error:!0,tool_use_id:A.id}],toolUseResult:D,sourceToolAssistantUUID:Q.uuid})}}}function wG7(A,Q,B,G,Z,Y,J,X,I){let W=new rfA;return LG7(A,Q,B,G,Z,Y,J,X,I,(K)=>{l("tengu_tool_use_progress",{messageID:J,toolName:A.name,isMcp:A.isMcp??!1,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),W.enqueue({message:t59({toolUseID:K.toolUseID,parentToolUseID:Q,data:K.data})})}).then((K)=>{for(let V of K)W.enqueue(V)}).catch((K)=>{W.error(K)}).finally(()=>{W.done()}),W}async function LG7(A,Q,B,G,Z,Y,J,X,I,W){let K=A.inputSchema.safeParse(B);if(!K.success){let _=_G7(A.name,K.error)
|
||||
|
||||
if(A>0)G.push("tools");if(B>0)G.push("resources");if(Q>0)G.push("prompts");return DhA.default.createElement(T,null,DhA.default.createElement(C,{bold:!0},"Capabilities: "),DhA.default.createElement(C,{color:"text"},G.length>0?DhA.default.createElement(vB,null,G):"none"))}var DhA;var tM0=w(()=>{PA();A8();DhA=c(XA(),1)});function YE1(A,Q){switch(A.client.type){case"connected":return{message:`Reconnected to ${Q}.`,success:!0};case"needs-auth":return{message:`${Q} requires authentication. Use the 'Authenticate' option.`,success:!1};case"failed":return{message:`Failed to reconnect to ${Q}.`,success:!1};default:return{message:`Unknown result when reconnecting to ${Q}.`,success:!1}}}function FhA(A,Q){let B=A instanceof Error?A.message:String(A);return`Error reconnecting to ${Q}: ${B}`}function eM0({server:A,serverToolsCount:Q,onViewTools:B,onCancel:G,onComplete:Z}){let[Y]=nB(),J=_Q(),[X]=QQ(),I=R6A(),W=Bt(),[K,V]=Z6.useState(!1),H=Z6.default.useCallback(async()=>{let z=A.client.type!=="disabled";try{await W(A.name),G()}catch($){Z(`Failed to ${z?"disable":"enable"} MCP server '${A.name}': ${$ instanceof Error?$.message:String($)}`)}},[A.client.type,A.name,W,G,Z]),D=String(A.name).charAt(0).toUpperCase()+String(A.name).slice(1),F=JE1(X.mcp.commands,A.name).length,E=[];if(A.client.type!=="disabled"&&Q>0)E.push({label:"View tools",value:"tools"});if(A.client.type!=="disabled")E.push({label:"Reconnect",value:"reconnectMcpServer"});if(E.push({label:A.client.type!=="disabled"?"Disable":"Enable",value:"toggle-enabled"}),E.length===0)E.push({label:"Back",value:"back"});if(K)return Z6.default.createElement(T,{flexDirection:"column",gap:1,padding:1},Z6.default.createElement(C,{color:"text"},"Reconnecting to ",Z6.default.createElement(C,{bold:!0},A.name)),Z6.default.createElement(T,null,Z6.default.createElement(F9,null),Z6.default.createElement(C,null," Restarting MCP server process")),Z6.default.createElement(C,{dimColor:!0},"This may take a few moments."))
|
||||
|
||||
return Z6.default.createElement(Z6.default.Fragment,null,Z6.default.createElement(T,{flexDirection:"column",paddingX:1,borderStyle:"round"},Z6.default.createElement(T,{marginBottom:1},Z6.default.createElement(C,{bold:!0},D," MCP Server")),Z6.default.createElement(T,{flexDirection:"column",gap:0},Z6.default.createElement(T,null,Z6.default.createElement(C,{bold:!0},"Status: "),A.client.type==="disabled"?Z6.default.createElement(C,null,$B("inactive",Y)(A1.radioOff)," disabled"):A.client.type==="connected"?Z6.default.createElement(C,null,$B("success",Y)(A1.tick)," connected"):A.client.type==="pending"?Z6.default.createElement(Z6.default.Fragment,null,Z6.default.createElement(C,{dimColor:!0},A1.radioOff),Z6.default.createElement(C,null," connecting…")):Z6.default.createElement(C,null,$B("error",Y)(A1.cross)," failed")),Z6.default.createElement(T,null,Z6.default.createElement(C,{bold:!0},"Command: "),Z6.default.createElement(C,{dimColor:!0},A.config.command)),A.config.args&&A.config.args.length>0&&Z6.default.createElement(T,null,Z6.default.createElement(C,{bold:!0},"Args: "),Z6.default.createElement(C,{dimColor:!0},A.config.args.join(" "))),Z6.default.createElement(T,null,Z6.default.createElement(C,{bold:!0},"Config location: "),Z6.default.createElement(C,{dimColor:!0},GU(Hs(A.name)?.scope??"dynamic"))),A.client.type==="connected"&&Z6.default.createElement(ZE1,{serverToolsCount:Q,serverPromptsCount:F,serverResourcesCount:X.mcp.resources[A.name]?.length||0}),A.client.type==="connected"&&Q>0&&Z6.default.createElement(T,null,Z6.default.createElement(C,{bold:!0},"Tools: "),Z6.default.createElement(C,{dimColor:!0},Q," tools"))),E.length>0&&Z6.default.createElement(T,{marginTop:1},Z6.default.createElement(b0,{options:E,onChange:async(z)=>{if(z==="tools")B();else if(z==="reconnectMcpServer"){V(!0);try{let $=await I(A.name),{message:L}=YE1($,A.name);Z?.(L)}catch($){Z?.(FhA($,A.name))}finally{V(!1)}}else if(z==="toggle-enabled")await H()
|
||||
|
||||
if(A.config)await AY0(A.name,A.config),l("tengu_mcp_auth_config_clear",{}),await Td(A.name,{...A.config,scope:A.scope}),H((KA)=>{let CA=KA.mcp.clients.map((GA)=>GA.name===A.name?{...GA,type:"failed"}:GA),yA=QR0(KA.mcp.tools,A.name),uA=BR0(KA.mcp.commands,A.name),BA=GR0(KA.mcp.resources,A.name);return{...KA,mcp:{clients:CA,tools:yA,commands:uA,resources:BA}}}),Z?.(`Authentication cleared for ${A.name}.`)};if(X)return I2.default.createElement(T,{flexDirection:"column",gap:1,padding:1},I2.default.createElement(C,{color:"claude"},"Authenticating with ",A.name,"…"),I2.default.createElement(T,null,I2.default.createElement(F9,null),I2.default.createElement(C,null," A browser window will open for authentication")),D&&I2.default.createElement(T,{flexDirection:"column"},I2.default.createElement(C,{dimColor:!0},"If your browser doesn't open automatically, copy this URL manually:"),I2.default.createElement(Q9,{url:D})),I2.default.createElement(T,{marginLeft:3},I2.default.createElement(C,{dimColor:!0},"Return here after authenticating in your browser. Press Esc to go back.")));if(E)return I2.default.createElement(T,{flexDirection:"column",gap:1,padding:1},I2.default.createElement(C,{color:"text"},"Connecting to ",I2.default.createElement(C,{bold:!0},A.name),"…"),I2.default.createElement(T,null,I2.default.createElement(F9,null),I2.default.createElement(C,null," Establishing connection to MCP server")),I2.default.createElement(C,{dimColor:!0},"This may take a few moments."));let FA=[];if(A.client.type==="disabled")FA.push({label:"Enable",value:"toggle-enabled"});if(A.client.type==="connected"&&Q>0)FA.push({label:"View tools",value:"tools"});if(A.isAuthenticated)FA.push({label:"Re-authenticate",value:"reauth"}),FA.push({label:"Clear authentication",value:"clear-auth"});if(!A.isAuthenticated)FA.push({label:"Authenticate",value:"auth"});if(A.client.type!=="disabled"){if(A.client.type!=="needs-auth")FA.push({label:"Reconnect",value:"reconnectMcpServer"})
|
||||
|
||||
break;case"auth":case"reauth":await hA();break;case"clear-auth":await s();break;case"claudeai-auth":await RA();break;case"claudeai-clear-auth":kA();break;case"reconnectMcpServer":z(!0);try{let CA=await t(A.name),{message:yA}=YE1(CA,A.name);Z?.(yA)}catch(CA){Z?.(FhA(CA,A.name))}finally{z(!1)}break;case"toggle-enabled":await SA();break;case"back":G();break}},onCancel:G}))),I2.default.createElement(T,{marginLeft:3},I2.default.createElement(C,{dimColor:!0},J.pending?I2.default.createElement(I2.default.Fragment,null,"Press ",J.keyName," again to exit"):I2.default.createElement(I2.default.Fragment,null,"Esc to go back"))))}var I2;var YR0=w(()=>{PA();N8();C0();X9();eB();_KA();GG();sq();pB();k1();kX();tM0();PA();Fp();tq();vJ();tB();I2=c(XA(),1)});function JR0({server:A,onSelectTool:Q,onBack:B}){let G=_Q(),[Z]=QQ(),Y=YU.default.useMemo(()=>{if(A.client.type!=="connected")return[];return EhA(Z.mcp.tools,A.name)},[A,Z.mcp.tools]),J=Y.map((X,I)=>{let W=XE1(X.name,A.name),K=X.userFacingName?X.userFacingName({}):W,V=IE1(K),H=X.isReadOnly?.({})??!1,D=X.isDestructive?.({})??!1,F=X.isOpenWorld?.({})??!1,E=[];if(H)E.push("read-only");if(D)E.push("destructive");if(F)E.push("open-world");return{label:V,value:I.toString(),description:E.length>0?E.join(", "):void 0,descriptionColor:D?"error":H?"success":void 0}});return YU.default.createElement(T,{flexDirection:"column"},YU.default.createElement(T,{flexDirection:"column",paddingX:1,borderStyle:"round"},YU.default.createElement(T,{marginBottom:1},YU.default.createElement(C,{bold:!0},"Tools for ",A.name),YU.default.createElement(C,{dimColor:!0}," (",Y.length," tools)")),Y.length===0?YU.default.createElement(C,{dimColor:!0},"No tools available"):YU.default.createElement(b0,{options:J,onChange:(X)=>{let I=parseInt(X),W=Y[I]
|
||||
|
||||
M.push({id:"toggle-individual",label:K?"Hide advanced options":"Show advanced options",action:()=>{if(V(!K),K&&I>P)W(P)},isToggle:!0});let v=AV.useMemo(()=>_K7(Z),[Z]);if(K){if(v.length>0)M.push({id:"mcp-servers-header",label:"MCP Servers:",action:()=>{},isHeader:!0}),v.forEach(({serverName:x,tools:m})=>{let e=m.filter((t)=>D.has(t.name)).length===m.length;M.push({id:`mcp-server-${x}`,label:`${e?A1.checkboxOn:A1.checkboxOff} ${x} (${m.length} tool${m.length===1?"":"s"})`,action:()=>{let t=m.map((b)=>b.name);z(t,!e)}})}),M.push({id:"tools-header",label:"Individual Tools:",action:()=>{},isHeader:!0});Z.forEach((x)=>{let m=x.name;if(x.name.startsWith("mcp__")){let u=tH(x.name);m=u?`${u.toolName} (${u.serverName})`:x.name}M.push({id:`tool-${x.name}`,label:`${D.has(x.name)?A1.checkboxOn:A1.checkboxOff} ${m}`,action:()=>E(x.name)})})}return L1((x,m)=>{if(m.return){let u=M[I];if(u&&!u.isHeader)u.action()}else if(m.escape)if(G)G();else B(Q);else if(m.upArrow){let u=I-1;while(u>0&&M[u]?.isHeader)u--;W(Math.max(0,u))}else if(m.downArrow){let u=I+1;while(u<M.length-1&&M[u]?.isHeader)u++;W(Math.min(M.length-1,u))}}),AV.default.createElement(T,{flexDirection:"column",marginTop:1},AV.default.createElement(C,{color:I===0?"suggestion":void 0,bold:I===0},I===0?`${A1.pointer} `:" ","[ Continue ]"),AV.default.createElement(C,{dimColor:!0},"─".repeat(40)),M.slice(1).map((x,m)=>{let u=m+1===I,e=x.isToggle,t=x.isHeader
|
||||
|
||||
RX();km();j0();iM0();cQ();J$0();gC();KQA();tVA();B0();ew=W0(function(){switch(kQ()){case"macos":return"/Library/Application Support/ClaudeCode";case"windows":if(mF7("C:\\Program Files\\ClaudeCode"))return"C:\\Program Files\\ClaudeCode";return"C:\\ProgramData\\ClaudeCode";default:return"/etc/claude-code"}});UQ=q8});import{join as lF7}from"path";function EhA(A,Q){let B=`mcp__${Z8(Q)}__`;return A.filter((G)=>G.name?.startsWith(B))}function JE1(A,Q){let B=`mcp__${Z8(Q)}__`;return A.filter((G)=>G.name?.startsWith(B))}function QR0(A,Q){let B=`mcp__${Z8(Q)}__`;return A.filter((G)=>!G.name?.startsWith(B))}function BR0(A,Q){let B=`mcp__${Z8(Q)}__`;return A.filter((G)=>!G.name?.startsWith(B))}function GR0(A,Q){let B={...A};return delete B[Q],B}function xs2(A){return`mcp__${Z8(A)}__`}function sH9(A,Q){return tH(A)?.serverName===Q}function i_(A){return A.name?.startsWith("mcp__")||A.isMcp===!0}function tH(A){let Q=A.split("__"),[B,G,...Z]=Q;if(B!=="mcp"||!G)return null;let Y=Z.length>0?Z.join("__"):void 0;return{serverName:G,toolName:Y}}function XE1(A,Q){let B=`mcp__${Z8(Q)}__`;return A.replace(B,"")}function IE1(A){let Q=A.replace(/\s*\(MCP\)\s*$/,"");Q=Q.trim();let B=Q.indexOf(" - ");if(B!==-1)return Q.substring(B+3).trim();return Q}function GU(A){let Q=jA();switch(A){case"user":{let B=QF(),G=Q.existsSync(B);return`${B}${G?"":" (file does not exist)"}`}case"project":{let B=lF7(l1(),".mcp.json"),G=Q.existsSync(B);return`${B}${G?"":" (file does not exist)"}`}case"local":return`${QF()} [project: ${l1()}]`;case"dynamic":return"Dynamically configured";case"enterprise":{let B=kI1(),G=Q.existsSync(B);return`${B}${G?"":" (file does not exist)"}`}case"claudeai":return"claude.ai";default:return A}}function HhA(A){switch(A){case"local":return"Local config (private to you in this project)";case"project":return"Project config (shared via .mcp.json)";case"user":return"User config (available in all your projects)";case"dynamic":return"Dynamic config (from command line)"
|
||||
|
||||
else if((Y=Q.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null)B=Y[1],G=Y[3],Z=Y[4];if(B&&Z!=="0")return`${B}=${G}:${parseInt(Z)+1}`;return Q})}OE7.Command=KT0});var qF9=U((jE7)=>{var{Argument:$F9}=Yz1(),{Command:VT0}=zF9(),{CommanderError:RE7,InvalidArgumentError:CF9}=ZgA(),{Help:_E7}=YT0(),{Option:UF9}=JT0();jE7.program=new VT0;jE7.createCommand=(A)=>new VT0(A);jE7.createOption=(A,Q)=>new UF9(A,Q);jE7.createArgument=(A,Q)=>new $F9(A,Q);jE7.Command=VT0;jE7.Option=UF9;jE7.Argument=$F9;jE7.Help=_E7;jE7.CommanderError=RE7;jE7.InvalidArgumentError=CF9;jE7.InvalidOptionArgumentError=CF9});var wF9=U((MO,NF9)=>{var Zx=qF9();MO=NF9.exports={};MO.program=new Zx.Command;MO.Argument=Zx.Argument;MO.Command=Zx.Command;MO.CommanderError=Zx.CommanderError;MO.Help=Zx.Help;MO.InvalidArgumentError=Zx.InvalidArgumentError;MO.InvalidOptionArgumentError=Zx.InvalidArgumentError;MO.Option=Zx.Option;MO.createCommand=(A)=>new Zx.Command(A);MO.createOption=(A,Q)=>new Zx.Option(A,Q);MO.createArgument=(A,Q)=>new Zx.Argument(A,Q)});var LF9,xPJ,yPJ,vPJ,kPJ,bPJ,fPJ,hPJ,Jz1,gPJ,QV,uPJ;var HT0=w(()=>{LF9=c(wF9(),1),{program:xPJ,createCommand:yPJ,createArgument:vPJ,createOption:kPJ,CommanderError:bPJ,InvalidArgumentError:fPJ,InvalidOptionArgumentError:hPJ,Command:Jz1,Argument:gPJ,Option:QV,Help:uPJ}=LF9.default});function Xz1(A){return A.map((Q)=>({name:Z8(Q.name),type:Q.type,hasTools:Q.type==="connected"&&Q.capabilities?.tools!==void 0,hasResources:Q.type==="connected"&&Q.capabilities?.resources!==void 0,hasPrompts:Q.type==="connected"&&Q.capabilities?.prompts!==void 0,serverInfo:Q.type==="connected"&&"serverInfo"in Q?Q.serverInfo:void 0}))}var DT0=()=>{};function Iz1(A,Q){let B=Q?.server,G=B?Z8(B):void 0,Z=G?`mcp__${G}__`:"mcp__";return A.filter((J)=>J.name.startsWith(Z)).map((J)=>{let X=tH(J.name);return{server:X?.serverName||"unknown",name:X?.toolName||J.name,description:typeof J.description==="function"?void 0:J.description||"",fullName:J.name}})}var FT0=w(()=>{kX()})
|
||||
|
||||
if(!B||typeof B==="string"){Q(Error("Failed to get server address"));return}this.port=B.port;let G=`http://127.0.0.1:${this.port}`;k(`[MCP CLI Endpoint] Started on ${G}`),A({port:this.port,url:G})})})}getSecret(){return this.secret}async handleRequest(A,Q){if(A.setTimeout(30000),A.on("timeout",()=>{k("[MCP CLI Endpoint] Request timeout"),Q.writeHead(408,{"Content-Type":"application/json"}),Q.end(Q1({error:"Request Timeout"}))}),A.method!=="POST"||A.url!=="/mcp"){Q.writeHead(404,{"Content-Type":"application/json"}),Q.end(Q1({error:"Not Found"}));return}let B=A.headers.authorization;if(!B?.startsWith("Bearer ")){Q.writeHead(403,{"Content-Type":"application/json"}),Q.end(Q1({error:"Forbidden"}));return}let G=B.slice(7);if(!this.validateSecret(G)){Q.writeHead(403,{"Content-Type":"application/json"}),Q.end(Q1({error:"Forbidden"}));return}let Z=10485760,Y=0,J="";A.on("data",(X)=>{if(Y+=X.length,Y>Z){k(`[MCP CLI Endpoint] Request too large: ${Y} bytes`),Q.writeHead(413,{"Content-Type":"application/json"}),Q.end(Q1({error:"Payload Too Large"})),A.destroy();return}J+=X.toString()}),A.on("end",async()=>{try{let X=JQ(J),I=_F9.parse(X),W=await this.handleCommand(I);Q.writeHead(200,{"Content-Type":"application/json"}),Q.end(Q1(W))}catch(X){let I=500;if(X instanceof SyntaxError)I=400;else if(X&&typeof X==="object"&&"name"in X){if(X.name==="ZodError")I=400}Q.writeHead(I,{"Content-Type":"application/json"}),Q.end(Q1({error:X instanceof Error?X.message:"Unknown error",type:X instanceof Error?X.constructor.name:"Error"})),r(X instanceof Error?X:Error(String(X)))}}),A.on("error",(X)=>{if(r(X),!Q.headersSent)Q.writeHead(500,{"Content-Type":"application/json"}),Q.end(Q1({error:"Internal Server Error"}))})}validateSecret(A){try{let Q=Buffer.from(A),B=Buffer.from(this.secret);if(Q.length!==B.length)return!1;return Wz7(Q,B)}catch{return!1}}async handleCommand(A){let Q=Date.now(),B=A.command==="call"?`mcp__${A.params.server}__${A.params.tool}`:void 0;try{let{data:G,metadata:Z}=await this.executeCommand(A),Y=Date.now()-Q
|
||||
|
||||
if(A.command==="call")l("tengu_tool_use_success",{toolName:B,isMcp:!0,durationMs:Y});return l("tengu_mcp_cli_command_executed",{command:A.command,success:!0,duration_ms:Y,...Z}),G}catch(G){let Z=G instanceof Error?G:Error(String(G)),Y=Date.now()-Q,J=String(G).slice(0,2000);if(A.command==="call")l("tengu_tool_use_error",{toolName:B,isMcp:!0,error:J,durationMs:Y});throw l("tengu_mcp_cli_command_executed",{command:A.command,success:!1,error_type:A.command==="call"?"tool_execution_failed":Z.constructor,duration_ms:Date.now()-Q}),G}}async executeCommand(A){switch(A.command){case"servers":{let Q=Xz1(this.mcpClients);return{data:Q,metadata:{server_count:Q.length}}}case"tools":{let Q=Iz1(this.availableTools,A.params);return{data:Q,metadata:{tool_count:Q.length,filtered:!!A.params?.server}}}case"info":{let Q=await Wz1(this.availableTools,A.params);if(!Q){let B=YgA(this.mcpClients,A.params.server,this.getNormalizedNames()),G=U3A(A.params.server,B?.type);if(G)throw G;throw new RT0(`Tool '${A.params.toolName}' not found on server '${A.params.server}'`)}return{data:Q,metadata:{tool_found:!0}}}case"grep":{let Q=Kz1(this.availableTools,A.params);return{data:Q,metadata:{match_count:Q.length}}}case"resources":{let Q=Vz1(this.resources,A.params,this.getNormalizedNames());return{data:Q,metadata:{resource_count:Q.length,filtered:!!A.params?.server}}}case"call":{let{server:Q,tool:B}=A.params;return{data:await this.callTool(A.params),metadata:{tool_name:`mcp__${Q}__${B}`}}}case"read":return{data:await this.readResource(A.params),metadata:{server:A.params.server}};default:{let Q=A;throw Error("Unknown command")}}}getConnectedClient(A){let Q=YgA(this.mcpClients,A,this.getNormalizedNames()),B=U3A(A,Q?.type);if(B)throw B;return Q}async callTool({server:A,tool:Q,args:B,timeoutMs:G}){let Z=this.getConnectedClient(A),Y=`mcp__${A}__${Q}`,J=this.availableTools.find((W)=>W.name===Y);if(this.availableTools.length>0&&!J)throw new RT0(`Tool '${Q}' not found on server '${A}'`);let X=J?.originalMcpToolName||Q
|
||||
|
||||
function tE9({onDone:A,commands:Q}){let{servers:B}=OW("project"),G=PZ("trust_folder_dialog_copy","variant","control"),Z=oE9[G],Y=Object.keys(B).length>0,J=pE9(),X=J.length>0,I=cE9(),W=iE9(),K=W.length>0,V=nE9(),H=V.length>0,D=lE9(),F=D.length>0,E=[...new Set([...J,...I,...W,...V,...D])],z=Q?.filter((p)=>p.type==="prompt"&&p.loadedFrom==="commands_DEPRECATED"&&(p.source==="projectSettings"||p.source==="localSettings")&&p.allowedTools?.some((AA)=>AA===H9||AA.startsWith(H9+"(")))??[],$=Q?.filter((p)=>p.type==="prompt"&&(p.loadedFrom==="skills"||p.loadedFrom==="plugin")&&(p.source==="projectSettings"||p.source==="localSettings"||p.source==="plugin")&&p.allowedTools?.some((AA)=>AA===H9||AA.startsWith(H9+"(")))??[],L=z.length>0,O=$.length>0,M=z.map((p)=>p.name),j=$.map((p)=>p.name),_=I.length>0||L||O,P=SZ(X||_||K||H||F),x=[{name:"MCP servers",shouldShowWarning:()=>Y,onChange:()=>{let p={enabledMcpjsonServers:Object.keys(B),enableAllProjectMcpServers:!0};rB("localSettings",p)}},{name:"hooks",shouldShowWarning:()=>X},{name:"bash commands",shouldShowWarning:()=>_},{name:"OpenTelemetry headers helper commands",shouldShowWarning:()=>F}].filter((p)=>p.shouldShowWarning()),m=new Set(x.map((p)=>p.name)),u=Object.keys(B);function e(){let p=["files"];if(m.has("MCP servers"))p.push("MCP servers");if(m.has("hooks"))p.push("hooks");if(m.has("bash commands"))p.push("bash commands");if(m.has("OpenTelemetry headers helper commands"))p.push("OpenTelemetry headers helper commands");return HgA(p)}I5.default.useEffect(()=>{let p=sE9()===l1();l("tengu_trust_dialog_shown",{isHomeDir:p,hasMcpServers:Y,hasHooks:X,hasBashExecution:_,hasApiKeyHelper:K,hasAwsCommands:H,hasOtelHeadersHelper:F,folderType:bT0(l1()),copyVariant:G})},[Y,X,_,K,H,F,G]);function t(p){if(p==="exit"){H6(1);return}let AA=sE9()===l1()
|
||||
|
||||
if(l("tengu_trust_dialog_accept",{isHomeDir:AA,hasMcpServers:Y,hasHooks:X,hasBashExecution:_,hasApiKeyHelper:K,hasAwsCommands:H,hasOtelHeadersHelper:F,enableMcp:!0,folderType:bT0(l1()),copyVariant:G}),!AA)TZ((JA)=>({...JA,hasTrustDialogAccepted:!0}));x.forEach((JA)=>{if(JA.onChange!==void 0)JA.onChange()}),A()}let b=_Q();if(L1((p,AA)=>{if(AA.escape){H6(0);return}}),P)return setTimeout(A),null
|
||||
|
||||
function Pz9({serverNames:A,onDone:Q}){function B(Z){let Y=UQ()||{},J=Y.enabledMcpjsonServers||[],X=Y.disabledMcpjsonServers||[],[I,W]=JQQ(A,(K)=>Z.includes(K));if(l("tengu_mcp_multidialog_choice",{approved:I.length,rejected:W.length}),I.length>0){let K=[...new Set([...J,...I])];rB("localSettings",{enabledMcpjsonServers:K})}if(W.length>0){let K=[...new Set([...X,...W])];rB("localSettings",{disabledMcpjsonServers:K})}Q()}let G=_Q();return L1((Z,Y)=>{if(Y.escape){let X=(UQ()||{}).disabledMcpjsonServers||[],I=[...new Set([...X,...A])];rB("localSettings",{disabledMcpjsonServers:I}),Q();return}}),J$.default.createElement(J$.default.Fragment,null,J$.default.createElement(T,{flexDirection:"column",gap:1,padding:1,borderStyle:"round",borderColor:"warning"},J$.default.createElement(C,{bold:!0,color:"warning"},A.length," new MCP servers found in .mcp.json"),J$.default.createElement(C,null,"Select any you wish to enable."),J$.default.createElement(Rz1,null),J$.default.createElement(Uz1,{options:A.map((Z)=>({label:Z,value:Z})),defaultValue:A,onSubmit:B})),J$.default.createElement(T,{marginLeft:3},J$.default.createElement(C,{dimColor:!0},G.pending?J$.default.createElement(J$.default.Fragment,null,"Press ",G.keyName," again to exit"):J$.default.createElement(vB,null,J$.default.createElement(E0,{shortcut:"Space",action:"select"}),J$.default.createElement(E0,{shortcut:"Enter",action:"confirm"}),J$.default.createElement(E0,{shortcut:"Esc",action:"reject all"})))))}var J$;var Sz9=w(()=>{PA();ST0();AB();XQQ();dT0();X9();C0();i4();A8();J$=c(XA(),1)});function xz9({serverName:A,onDone:Q}){function B(Z){switch(l("tengu_mcp_dialog_choice",{choice:Z}),Z){case"yes":case"yes_all":{let J=(UQ()||{}).enabledMcpjsonServers||[];if(!J.includes(A))rB("localSettings",{enabledMcpjsonServers:[...J,A]});if(Z==="yes_all")rB("localSettings",{enableAllProjectMcpServers:!0});Q();break}case"no":{let J=(UQ()||{}).disabledMcpjsonServers||[];if(!J.includes(A))rB("localSettings",{disabledMcpjsonServers:[...J,A]});Q();break}}}let G=_Q()
|
||||
|
||||
try{let G=await li({model:Q.model}),{envContext:Z,...Y}=G,J={...Y,...Z,...Q};if(typeof J.toolName==="string"&&J.toolName.startsWith("mcp__"))J.toolName="mcp";if(typeof J.model==="string"&&!J.model.startsWith("claude-"))J.model="other";if(typeof J.version==="string")J.version=J.version.replace(/^(\d+\.\d+\.\d+-dev\.\d{8})\.t\d+\.sha[a-f0-9]+$/,"$1");if(J.status!==void 0&&J.status!==null){let K=String(J.status);J.http_status=K;let V=K.charAt(0);if(V>="1"&&V<="5")J.http_status_range=`${V}xx`;delete J.status}let X=J,W={ddsource:"nodejs",ddtags:j$7.filter((K)=>X[K]!==void 0&&X[K]!==null).map((K)=>`${bz9(K)}:${X[K]}`).join(","),message:A,service:"claude-code",hostname:"claude-code",env:"external"};for(let[K,V]of Object.entries(J))if(V!==void 0&&V!==null)W[bz9(K)]=V;if($gA.push(W),$gA.length>=M$7){if(lp)clearTimeout(lp),lp=null;pT0()}else T$7()}catch(G){r(G instanceof Error?G:Error(String(G)))}}var w$7="https://http-intake.logs.us5.datadoghq.com/api/v2/logs",L$7="pubbbf48e6d78dae54bceaa4acf463299bf",O$7=15000,M$7=100,R$7=5000,_$7,j$7,$gA,lp=null,_z1=null,P$7;var fz9=w(()=>{D5();t2();k1();SYA();ii();_$7=new Set(["tengu_api_error","tengu_api_success","tengu_compact_failed","tengu_model_fallback_triggered","tengu_oauth_error","tengu_oauth_success","tengu_oauth_token_refresh_failure","tengu_oauth_token_refresh_success","tengu_oauth_token_refresh_lock_acquiring","tengu_oauth_token_refresh_lock_acquired","tengu_oauth_token_refresh_starting","tengu_oauth_token_refresh_completed","tengu_oauth_token_refresh_lock_releasing","tengu_oauth_token_refresh_lock_released","tengu_query_error","tengu_tool_use_error","tengu_tool_use_success"]),j$7=["arch","clientType","errorType","http_status_range","http_status","model","platform","provider","toolName","userType","version","versionBase"];$gA=[];P$7=W0(async()=>{if(JW())return _z1=!1,!1;try{let A=async()=>{if(lp)clearTimeout(lp),lp=null;await pT0()};return process.on("beforeExit",A),_z1=!0,!0}catch(A){return r(A instanceof Error?A:Error(String(A))),_z1=!1,!1}})})
|
||||
|
||||
if(A.showExpandedTodos!==Q.showExpandedTodos&&T1().showExpandedTodos!==A.showExpandedTodos){let B=A.showExpandedTodos;m0((G)=>({...G,showExpandedTodos:B}))}if(Q!==null&&A.todos!==Q.todos)for(let B in A.todos)rWA(A.todos[B],B);if(A.verbose!==Q.verbose&&T1().verbose!==A.verbose){let B=A.verbose;m0((G)=>({...G,verbose:B}))}if(A.feedbackSurvey.timeLastShown!==Q.feedbackSurvey.timeLastShown&&A.feedbackSurvey.timeLastShown!==null){let B=A.feedbackSurvey.timeLastShown;m0((G)=>({...G,feedbackSurveyState:{lastShownTime:B}}))}if(BJ()&&A.mcp!==Q.mcp){if(lD9(A.mcp.clients,A.mcp.tools,A.mcp.resources),it())C3A()}if(A.settings!==Q.settings)try{if(PtA(),StA(),A.settings.env!==Q.settings.env)N3A()}catch(B){r(B instanceof Error?B:Error(`Failed to apply settings changes: ${B}`))}}var rz9=w(()=>{KQ();KQ();j0();AB();Wo();mEA();rH();pEA();tB();k1();KgA()});function sz9(){let A=T1();if(A.autoUpdates!==!1||A.autoUpdatesProtectedForNative===!0)return;try{let Q=lB("userSettings")||{};rB("userSettings",{...Q,env:{...Q.env,DISABLE_AUTOUPDATER:"1"}}),l("tengu_migrate_autoupdates_to_settings",{was_user_preference:!0,already_had_env_var:!!Q.env?.DISABLE_AUTOUPDATER}),process.env.DISABLE_AUTOUPDATER="1",m0((B)=>{let{autoUpdates:G,autoUpdatesProtectedForNative:Z,...Y}=B;return Y})}catch(Q){r(Error(`Failed to migrate auto-updates: ${Q}`)),l("tengu_migrate_autoupdates_error",{has_error:!0})}}var tz9=w(()=>{KQ();AB();C0();k1()});function ez9(){let A=RG(),Q=A.enableAllProjectMcpServers!==void 0,B=A.enabledMcpjsonServers&&A.enabledMcpjsonServers.length>0,G=A.disabledMcpjsonServers&&A.disabledMcpjsonServers.length>0;if(!Q&&!B&&!G)return;try{let Z=lB("localSettings")||{},Y={},J=[];if(Q&&Z.enableAllProjectMcpServers===void 0)Y.enableAllProjectMcpServers=A.enableAllProjectMcpServers,J.push("enableAllProjectMcpServers");else if(Q)J.push("enableAllProjectMcpServers");if(B&&A.enabledMcpjsonServers){let X=Z.enabledMcpjsonServers||[]
|
||||
|
||||
if(D=D.filter((M)=>!M.name.startsWith(O)),H=H.filter((M)=>M.name!==z),Y.includes(z))W.push(z)}for(let z of[...J,...I]){let $=A[z];if(!$)continue;let L=tT0($);if($.type==="sdk"){K.push(z);continue}try{let O=await tL(z,L);if(H.push(O),O.type==="connected"){let M=await RS(O);D.push(...M)}else if(O.type==="failed")V[z]=O.error||"Connection failed";K.push(z)}catch(O){let M=O instanceof Error?O.message:String(O);V[z]=M,r(O instanceof Error?O:Error(M))}}let F={};for(let z of Z){let $=A[z];if($)F[z]=tT0($)}let E={clients:H,tools:D,configs:F};return B((z)=>{let $=new Set([...Object.keys(Q.configs),...Object.keys(F)]),L=z.mcp.tools.filter((M)=>{for(let j of $)if(M.name.startsWith(`mcp__${j}__`))return!1;return!0}),O=z.mcp.clients.filter((M)=>{return!$.has(M.name)});return{...z,mcp:{...z.mcp,tools:[...L,...D],clients:[...O,...H]}}}),{response:{added:K,removed:W,errors:V},newState:E}}var U$9;var L$9=w(()=>{oT0();D$9();oF();eF();C0();h1();fS();AN();k1();aO0();RfA();oKA();ZO();os();ML0();jY();E$9();B2();m5A();Ur();tG();YI();nT0();LZ();QhA();X9A();If();AB();ts();tB();j0();fm();C$9();l4();sq();HSA();rH();eKA();ME1();$w0();u2();j0();kL();$I();MfA();B0();U$9=new Set});async function M$9(){l("tengu_update_check",{}),h9(`Current version: ${{ISSUES_EXPLAINER:"report the issue at https://github.com/anthropics/claude-code/issues",PACKAGE_URL:"@anthropic-ai/claude-code",README_URL:"https://code.claude.com/docs/en/overview",VERSION:"2.0.77",FEEDBACK_CHANNEL:"https://github.com/anthropics/claude-code/issues",BUILD_TIME:"2026-01-06T00:25:58Z"}.VERSION}
|
||||
`);let A=q8()?.autoUpdatesChannel??"latest";h9(`Checking for updates...
|
||||
`),k("update: Starting update check"),k("update: Running diagnostic");let Q=await J4A();if(k(`update: Installation type: ${Q.installationType}`),k(`update: Config install method: ${Q.configInstallMethod}`),Q.multipleInstallations.length>1){h9(`
|
||||
`),h9(V1.yellow("Warning: Multiple installations found")+`
|
||||
`);for(let W of Q.multipleInstallations){let K=Q.installationType===W.type?" (currently running)":""
|
||||
|
||||
let{unmount:K}=await b8(w5.default.createElement(Y5,null,w5.default.createElement(_E9,{servers:W,scope:X,onDone:()=>{K()}})),{exitOnCtrlC:!0})}catch(X){console.error(X.message),process.exit(1)}}),Q.command("reset-project-choices").description("Reset all approved and rejected project-scoped (.mcp.json) servers within this project").helpOption("-h, --help","Display help for command").action(async()=>{l("tengu_mcp_reset_mcpjson_choices",{}),TZ((J)=>({...J,enabledMcpjsonServers:[],disabledMcpjsonServers:[],enableAllProjectMcpServers:!1})),console.log("All project-scoped (.mcp.json) server approvals and rejections have been reset."),console.log("You will be prompted for approval next time you start Claude Code."),process.exit(0)});function B(J,X){r(J instanceof Error?J:Error(String(J))),console.error(`${A1.cross} Failed to ${X}: ${J instanceof Error?J.message:String(J)}`),process.exit(1)}let G=A.command("plugin").description("Manage Claude Code plugins").helpOption("-h, --help","Display help for command");G.command("validate <path>").description("Validate a plugin or marketplace manifest").helpOption("-h, --help","Display help for command").action((J)=>{try{let X=kE1(J);if(console.log(`Validating ${X.fileType} manifest: ${X.filePath}
|
||||
`),X.errors.length>0)console.log(`${A1.cross} Found ${X.errors.length} error${X.errors.length===1?"":"s"}:
|
||||
`),X.errors.forEach((I)=>{console.log(` ${A1.pointer} ${I.path}: ${I.message}`)}),console.log("");if(X.warnings.length>0)console.log(`${A1.warning} Found ${X.warnings.length} warning${X.warnings.length===1?"":"s"}:
|
||||
`),X.warnings.forEach((I)=>{console.log(` ${A1.pointer} ${I.path}: ${I.message}`)}),console.log("");if(X.success){if(X.warnings.length>0)console.log(`${A1.tick} Validation passed with warnings`);else console.log(`${A1.tick} Validation passed`)
|
||||
|
||||
at.command("info").description("Get detailed information about a tool").argument("<tool>","Tool identifier in format <server>/<tool>").option("--json","Output in JSON format").action(async(A,Q)=>{let B=await XgA("info",async()=>{let{server:Z,tool:Y}=wT0(A),J={server:Z,toolName:Y};if(Z$())return await q3A(OF9,{command:"info",params:J});let X=nt(),I=await Wz1(X.tools,J);if(!I){let W=YgA(X.clients,Z,X.normalizedNames),K=U3A(Z,W?.type);if(K)throw K;throw Error(`Tool '${Y}' not found on server '${Z}'`)}return I},()=>({tool_found:!0}),{tool_found:!1});if(!B.success)process.exit(1);let G=B.data;if(Q.json)console.log(Q1(G));else{if(console.log(V1.bold(`Tool: ${A}`)),console.log(V1.dim(`Server: ${G.server}`)),G.description)console.log(V1.dim(`Description: ${G.description}`));console.log(),console.log(V1.bold("Input Schema:")),console.log(Q1(G.inputSchema,null,2))}});async function eE7(A,Q,B,G){let Z=nt(),Y=SF9(Z,Q);if(!Y)throw Error(`Server '${Q}' not found`);if(G.debug)console.error(`Connecting to ${Q} (${Y.type})...`);let J=await x4A(Q,Y);if(J.client.type!=="connected")throw U3A(Q,J.client.type)??new JgA(`Failed to connect to server '${Q}'`);let X=(()=>{let V=`mcp__${Z8(Q)}__${Z8(A)}`;return Z.tools.find((D)=>D.name===V)?.originalToolName||A})();if(G.debug)console.error(`Calling tool ${X}...`);let I=parseInt(G.timeout||"",10)||y4A(),W=await J.client.client.request({method:"tools/call",params:{name:X,arguments:B}},qC,{signal:AbortSignal.timeout(I)});return J.client.client.close(),W}at.command("call").description("Invoke an MCP tool").argument("<tool>","Tool identifier in format <server>/<tool>").argument("<args>",'Tool arguments as JSON string or "-" for stdin').option("--json","Output in JSON format").option("--timeout <ms>","Timeout in milliseconds (default: MCP_TOOL_TIMEOUT env var or effectively infinite)").option("--debug","Show debug output").action(async(A,Q,B)=>{let{server:G,tool:Z}=wT0(A);if(Q==="-"){let I=[];for await(let W of process.stdin)I.push(W);Q=Buffer.concat(I).toString("utf-8").trim()}let Y
|
||||
|
||||
try{Y=JQ(Q)}catch(I){console.error(V1.red("Error: Invalid JSON arguments")),console.error(String(I)),process.exit(1)}let J=`mcp__${Z8(G)}__${Z8(Z)}`,X=Date.now();try{let I=parseInt(B.timeout||"",10)||y4A(),W={server:G,tool:Z,args:Y,timeoutMs:I},K=Z$()?await q3A(qC,{command:"call",params:W},I):await eE7(Z,G,Y,B),V=B.json?Q1(K):typeof K==="string"?K:Q1(K,null,2);if(await new Promise((H)=>{process.stdout.write(V+`
|
||||
`,()=>H())}),!Z$())await uc("tengu_mcp_cli_command_executed",{command:"call",tool_name:J,success:!0,duration_ms:Date.now()-X});process.exit(0)}catch(I){console.error(V1.red("Error calling tool:"),String(I));let W=Date.now()-X,K=String(I).slice(0,2000);if(!Z$())await uc("tengu_tool_use_error",{toolName:J,isMcp:!0,error:K,durationMs:W}),await uc("tengu_mcp_cli_command_executed",{command:"call",tool_name:J,success:!1,error_type:I instanceof JgA?"connection_failed":"tool_execution_failed",duration_ms:Date.now()-X});process.exit(1)}});at.command("grep").description("Search tool names and descriptions using regex patterns").argument("<pattern>","Regex pattern to search for").option("--json","Output in JSON format").option("-i, --ignore-case","Case insensitive search (default: true)",!0).action(async(A,Q)=>{let B=await XgA("grep",async()=>{try{new RegExp(A,Q.ignoreCase?"i":"")}catch(Y){throw Error(`Invalid regex pattern: ${Y instanceof Error?Y.message:String(Y)}`)}let Z={pattern:A,ignoreCase:Q.ignoreCase};return Z$()?await q3A(MF9,{command:"grep",params:Z}):Kz1(nt().tools,Z)},(Z)=>({match_count:Z.length}));if(!B.success)process.exit(1);let G=B.data;if(Q.json)console.log(Q1(G));else if(G.length===0)console.log(V1.yellow("No tools found matching pattern"));else G.forEach((Z)=>{if(console.log(V1.bold(`${Z.server}/${Z.name}`)),Z.description){let Y=Z.description.length>100?Z.description.slice(0,100)+"...":Z.description;console.log(V1.dim(` ${Y}`))}console.log()})})
|
||||
|
||||
for(let[X,I]of this.mcpClients)try{I.socket.write(J)}catch(W){gW(`Failed to send to MCP client ${X}:`,W)}}break}case"notification":{if(this.mcpClients.size>0){gW(`Forwarding notification to ${this.mcpClients.size} MCP clients`);let{type:B,...G}=Q,Z=Buffer.from(Q1(G),"utf-8"),Y=Buffer.alloc(4);Y.writeUInt32LE(Z.length,0);let J=Buffer.concat([Y,Z]);for(let[X,I]of this.mcpClients)try{I.socket.write(J)}catch(W){gW(`Failed to send notification to MCP client ${X}:`,W)}}break}default:gW(`Unknown message type: ${Q.type}`),cEA(Q1({type:"error",error:`Unknown message type: ${Q.type}`}))}}handleMcpClient(A){let Q=this.nextClientId++,B={id:Q,socket:A,buffer:Buffer.alloc(0)};this.mcpClients.set(Q,B),gW(`MCP client ${Q} connected. Total clients: ${this.mcpClients.size}`),cEA(Q1({type:"mcp_connected"})),A.on("data",(G)=>{B.buffer=Buffer.concat([B.buffer,G]);while(B.buffer.length>=4){let Z=B.buffer.readUInt32LE(0);if(Z===0||Z>MT0){gW(`Invalid message length from MCP client ${Q}: ${Z}`),A.destroy();return}if(B.buffer.length<4+Z)break;let Y=B.buffer.slice(4,4+Z);B.buffer=B.buffer.slice(4+Z);try{let J=JQ(Y.toString("utf-8"));gW(`Forwarding tool request from MCP client ${Q}: ${J.method}`),cEA(Q1({type:"tool_request",method:J.method,params:J.params}))}catch(J){gW(`Failed to parse tool request from MCP client ${Q}:`,J)}}}),A.on("error",(G)=>{gW(`MCP client ${Q} error: ${G}`)}),A.on("close",()=>{gW(`MCP client ${Q} disconnected. Remaining clients: ${this.mcpClients.size-1}`),this.mcpClients.delete(Q),cEA(Q1({type:"mcp_disconnected"}))})}}class mF9{buffer=Buffer.alloc(0);pendingResolve=null;closed=!1;constructor(){process.stdin.on("data",(A)=>{this.buffer=Buffer.concat([this.buffer,A]),this.tryProcessMessage()}),process.stdin.on("end",()=>{if(this.closed=!0,this.pendingResolve)this.pendingResolve(null),this.pendingResolve=null}),process.stdin.on("error",()=>{if(this.closed=!0,this.pendingResolve)this.pendingResolve(null),this.pendingResolve=null})}tryProcessMessage(){if(!this.pendingResolve)return;if(this.buffer.length<4)return
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"version": "3.12.1",
|
||||
"sizeBytes": 11011987,
|
||||
"lines": 5189,
|
||||
"functions": 20395,
|
||||
"asyncFunctions": 1038,
|
||||
"arrowFunctions": 20920,
|
||||
"classes": 1612,
|
||||
"extends": 861,
|
||||
"sourceFile": "cli.js",
|
||||
"extractedAt": "2026-04-02T23:29:01.396Z",
|
||||
"modules": {
|
||||
"permission-system": {
|
||||
"fragments": 340,
|
||||
"sizeBytes": 758419
|
||||
},
|
||||
"agent-loop": {
|
||||
"fragments": 48,
|
||||
"sizeBytes": 101628
|
||||
},
|
||||
"tool-dispatch": {
|
||||
"fragments": 28,
|
||||
"sizeBytes": 171743
|
||||
},
|
||||
"streaming-handler": {
|
||||
"fragments": 10,
|
||||
"sizeBytes": 19607
|
||||
},
|
||||
"context-manager": {
|
||||
"fragments": 13,
|
||||
"sizeBytes": 26854
|
||||
},
|
||||
"mcp-client": {
|
||||
"fragments": 39,
|
||||
"sizeBytes": 75408
|
||||
},
|
||||
"telemetry": {
|
||||
"fragments": 479,
|
||||
"sizeBytes": 15425
|
||||
},
|
||||
"commands": {
|
||||
"fragments": 45,
|
||||
"sizeBytes": 3346
|
||||
},
|
||||
"class-hierarchy": {
|
||||
"fragments": 1440,
|
||||
"sizeBytes": 22584
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,20 @@
|
|||
if(B!==-1)return[A.substring(0,B),Q,A.substring(B+Q.length)];return[A,"",""]}var JMA,i$;var Ye1=w(()=>{Wu();l$();Qe1();LQA();r11();l$();i$=class i${constructor(A,Q,B){this.iterator=A,JMA.set(this,void 0),this.controller=Q,O2(this,JMA,B,"f")}static fromSSEResponse(A,Q,B){let G=!1,Z=B?gH(B):console;async function*Y(){if(G)throw new q2("Cannot iterate over a consumed stream, use `.tee()` to split the stream.");G=!0;let J=!1;try{for await(let X of c58(A,Q)){if(X.event==="completion")try{yield JSON.parse(X.data)}catch(I){throw Z.error("Could not parse message into JSON:",X.data),Z.error("From chunk:",X.raw),I}if(X.event==="message_start"||X.event==="message_delta"||X.event==="message_stop"||X.event==="content_block_start"||X.event==="content_block_delta"||X.event==="content_block_stop")try{yield JSON.parse(X.data)}catch(I){throw Z.error("Could not parse message into JSON:",X.data),Z.error("From chunk:",X.raw),I}if(X.event==="ping")continue;if(X.event==="error")throw new Y9(void 0,n11(X.data)??X.data,void 0,A.headers)}J=!0}catch(X){if(Ku(X))return;throw X}finally{if(!J)Q.abort()}}return new i$(Y,Q,B)}static fromReadableStream(A,Q,B){let G=!1;async function*Z(){let J=new Ln,X=GMA(A);for await(let I of X)for(let W of J.decode(I))yield W;for(let I of J.flush())yield I}async function*Y(){if(G)throw new q2("Cannot iterate over a consumed stream, use `.tee()` to split the stream.");G=!0;let J=!1;try{for await(let X of Z()){if(J)continue;if(X)yield JSON.parse(X)}J=!0}catch(X){if(Ku(X))return;throw X}finally{if(!J)Q.abort()}}return new i$(Y,Q,B)}[(JMA=new WeakMap,Symbol.asyncIterator)](){return this.iterator()}tee(){let A=[],Q=[],B=this.iterator(),G=(Z)=>{return{next:()=>{if(Z.length===0){let Y=B.next();A.push(Y),Q.push(Y)}return Z.shift()}}};return[new i$(()=>G(A),this.controller,c0(this,JMA,"f")),new i$(()=>G(Q),this.controller,c0(this,JMA,"f"))]}toReadableStream(){let A=this,Q;return et1({async start(){Q=A[Symbol.asyncIterator]()},async pull(B){try{let{value:G,done:Z}=await Q.next();if(Z)return B.close()
|
||||
|
||||
return this.receivedMessages.at(-1)},SFB=function(){if(this.receivedMessages.length===0)throw new q2("stream ended without producing a Message with role=assistant");let Q=this.receivedMessages.at(-1).content.filter((B)=>B.type==="text").map((B)=>B.text);if(Q.length===0)throw new q2("stream ended without producing a content block with type=text");return Q.join(" ")},Ke1=function(){if(this.ended)return;O2(this,On,void 0,"f")},Ve1=function(Q){if(this.ended)return;let B=c0(this,KR,"m",xFB).call(this,Q);switch(this._emit("streamEvent",Q,B),Q.type){case"content_block_delta":{let G=B.content.at(-1);switch(Q.delta.type){case"text_delta":{if(G.type==="text")this._emit("text",Q.delta.text,G.text||"");break}case"citations_delta":{if(G.type==="text")this._emit("citation",Q.delta.citation,G.citations??[]);break}case"input_json_delta":{if(vFB(G)&&G.input)this._emit("inputJson",Q.delta.partial_json,G.input);break}case"thinking_delta":{if(G.type==="thinking")this._emit("thinking",Q.delta.thinking,G.thinking);break}case"signature_delta":{if(G.type==="thinking")this._emit("signature",G.signature);break}default:kFB(Q.delta)}break}case"message_stop":{this._addMessageParam(B),this._addMessage(Je1(B,c0(this,BXA,"f")),!0);break}case"content_block_stop":{this._emit("contentBlock",B.content.at(-1));break}case"message_start":{O2(this,On,B,"f");break}case"content_block_start":case"message_delta":break}},He1=function(){if(this.ended)throw new q2("stream has ended, this shouldn't happen");let Q=c0(this,On,"f");if(!Q)throw new q2("request ended without sending any chunks");return O2(this,On,void 0,"f"),Je1(Q,c0(this,BXA,"f"))},xFB=function(Q){let B=c0(this,On,"f");if(Q.type==="message_start"){if(B)throw new q2(`Unexpected event order, got ${Q.type} before receiving "message_stop"`);return Q.message}if(!B)throw new q2(`Unexpected event order, got ${Q.type} before "message_start"`);switch(Q.type){case"message_stop":return B
|
||||
|
||||
case"message_delta":if(B.container=Q.delta.container,B.stop_reason=Q.delta.stop_reason,B.stop_sequence=Q.delta.stop_sequence,B.usage.output_tokens=Q.usage.output_tokens,B.context_management=Q.context_management,Q.usage.input_tokens!=null)B.usage.input_tokens=Q.usage.input_tokens;if(Q.usage.cache_creation_input_tokens!=null)B.usage.cache_creation_input_tokens=Q.usage.cache_creation_input_tokens;if(Q.usage.cache_read_input_tokens!=null)B.usage.cache_read_input_tokens=Q.usage.cache_read_input_tokens;if(Q.usage.server_tool_use!=null)B.usage.server_tool_use=Q.usage.server_tool_use;return B;case"content_block_start":return B.content.push(Q.content_block),B;case"content_block_delta":{let G=B.content.at(Q.index);switch(Q.delta.type){case"text_delta":{if(G?.type==="text")B.content[Q.index]={...G,text:(G.text||"")+Q.delta.text};break}case"citations_delta":{if(G?.type==="text")B.content[Q.index]={...G,citations:[...G.citations??[],Q.delta.citation]};break}case"input_json_delta":{if(G&&vFB(G)){let Z=G[yFB]||"";Z+=Q.delta.partial_json;let Y={...G};if(Object.defineProperty(Y,yFB,{value:Z,enumerable:!1,writable:!0}),Z)try{Y.input=c11(Z)}catch(J){let X=new q2(`Unable to parse tool parameter JSON from model. Please retry your request or adjust your prompt. Error: ${J}. JSON: ${Z}`);c0(this,Z01,"f").call(this,X)}B.content[Q.index]=Y}break}case"thinking_delta":{if(G?.type==="thinking")B.content[Q.index]={...G,thinking:G.thinking+Q.delta.thinking};break}case"signature_delta":{if(G?.type==="thinking")B.content[Q.index]={...G,signature:Q.delta.signature};break}default:kFB(Q.delta)}return B}case"content_block_stop":return B}},Symbol.asyncIterator)](){let A=[],Q=[],B=!1;return this.on("streamEvent",(G)=>{let Z=Q.shift();if(Z)Z.resolve(G);else A.push(G)}),this.on("end",()=>{B=!0;for(let G of Q)G.resolve(void 0);Q.length=0}),this.on("abort",(G)=>{B=!0;for(let Z of Q)Z.reject(G);Q.length=0}),this.on("error",(G)=>{B=!0;for(let Z of Q)Z.reject(G);Q.length=0}),{next:async()=>{if(!A.length){if(B)return{value:void 0,done:!0}
|
||||
|
||||
if(A==="abort"){let G=Q[0];if(!c0(this,XIA,"f")&&!B?.length)Promise.reject(G);c0(this,lRA,"f").call(this,G),c0(this,nRA,"f").call(this,G),this._emit("end");return}if(A==="error"){let G=Q[0];if(!c0(this,XIA,"f")&&!B?.length)Promise.reject(G);c0(this,lRA,"f").call(this,G),c0(this,nRA,"f").call(this,G),this._emit("end")}}_emitFinal(){if(this.receivedMessages.at(-1))this._emit("finalMessage",c0(this,OR,"m",GQ0).call(this))}async _fromReadableStream(A,Q){let B=Q?.signal,G;if(B){if(B.aborted)this.controller.abort();G=this.controller.abort.bind(this.controller),B.addEventListener("abort",G)}try{c0(this,OR,"m",YQ0).call(this),this._connected(null);let Z=i$.fromReadableStream(A,this.controller);for await(let Y of Z)c0(this,OR,"m",JQ0).call(this,Y);if(Z.controller.signal?.aborted)throw new PX;c0(this,OR,"m",XQ0).call(this)}finally{if(B&&G)B.removeEventListener("abort",G)}}[(Ba=new WeakMap,cRA=new WeakMap,G21=new WeakMap,lRA=new WeakMap,iRA=new WeakMap,Z21=new WeakMap,nRA=new WeakMap,Su=new WeakMap,aRA=new WeakMap,Y21=new WeakMap,J21=new WeakMap,XIA=new WeakMap,X21=new WeakMap,I21=new WeakMap,ZQ0=new WeakMap,OR=new WeakSet,GQ0=function(){if(this.receivedMessages.length===0)throw new q2("stream ended without producing a Message with role=assistant");return this.receivedMessages.at(-1)},BRB=function(){if(this.receivedMessages.length===0)throw new q2("stream ended without producing a Message with role=assistant");let Q=this.receivedMessages.at(-1).content.filter((B)=>B.type==="text").map((B)=>B.text);if(Q.length===0)throw new q2("stream ended without producing a content block with type=text");return Q.join(" ")},YQ0=function(){if(this.ended)return;O2(this,Ba,void 0,"f")},JQ0=function(Q){if(this.ended)return;let B=c0(this,OR,"m",GRB).call(this,Q);switch(this._emit("streamEvent",Q,B),Q.type){case"content_block_delta":{let G=B.content.at(-1);switch(Q.delta.type){case"text_delta":{if(G.type==="text")this._emit("text",Q.delta.text,G.text||"")
|
||||
|
||||
break}case"citations_delta":{if(G.type==="text")this._emit("citation",Q.delta.citation,G.citations??[]);break}case"input_json_delta":{if(YRB(G)&&G.input)this._emit("inputJson",Q.delta.partial_json,G.input);break}case"thinking_delta":{if(G.type==="thinking")this._emit("thinking",Q.delta.thinking,G.thinking);break}case"signature_delta":{if(G.type==="thinking")this._emit("signature",G.signature);break}default:JRB(Q.delta)}break}case"message_stop":{this._addMessageParam(B),this._addMessage(B,!0);break}case"content_block_stop":{this._emit("contentBlock",B.content.at(-1));break}case"message_start":{O2(this,Ba,B,"f");break}case"content_block_start":case"message_delta":break}},XQ0=function(){if(this.ended)throw new q2("stream has ended, this shouldn't happen");let Q=c0(this,Ba,"f");if(!Q)throw new q2("request ended without sending any chunks");return O2(this,Ba,void 0,"f"),Q},GRB=function(Q){let B=c0(this,Ba,"f");if(Q.type==="message_start"){if(B)throw new q2(`Unexpected event order, got ${Q.type} before receiving "message_stop"`);return Q.message}if(!B)throw new q2(`Unexpected event order, got ${Q.type} before "message_start"`);switch(Q.type){case"message_stop":return B;case"message_delta":if(B.stop_reason=Q.delta.stop_reason,B.stop_sequence=Q.delta.stop_sequence,B.usage.output_tokens=Q.usage.output_tokens,Q.usage.input_tokens!=null)B.usage.input_tokens=Q.usage.input_tokens;if(Q.usage.cache_creation_input_tokens!=null)B.usage.cache_creation_input_tokens=Q.usage.cache_creation_input_tokens;if(Q.usage.cache_read_input_tokens!=null)B.usage.cache_read_input_tokens=Q.usage.cache_read_input_tokens;if(Q.usage.server_tool_use!=null)B.usage.server_tool_use=Q.usage.server_tool_use;return B;case"content_block_start":return B.content.push({...Q.content_block}),B;case"content_block_delta":{let G=B.content.at(Q.index);switch(Q.delta.type){case"text_delta":{if(G?.type==="text")B.content[Q.index]={...G,text:(G.text||"")+Q.delta.text}
|
||||
|
||||
break}case"citations_delta":{if(G?.type==="text")B.content[Q.index]={...G,citations:[...G.citations??[],Q.delta.citation]};break}case"input_json_delta":{if(G&&YRB(G)){let Z=G[ZRB]||"";Z+=Q.delta.partial_json;let Y={...G};if(Object.defineProperty(Y,ZRB,{value:Z,enumerable:!1,writable:!0}),Z)Y.input=c11(Z);B.content[Q.index]=Y}break}case"thinking_delta":{if(G?.type==="thinking")B.content[Q.index]={...G,thinking:G.thinking+Q.delta.thinking};break}case"signature_delta":{if(G?.type==="thinking")B.content[Q.index]={...G,signature:Q.delta.signature};break}default:JRB(Q.delta)}return B}case"content_block_stop":return B}},Symbol.asyncIterator)](){let A=[],Q=[],B=!1;return this.on("streamEvent",(G)=>{let Z=Q.shift();if(Z)Z.resolve(G);else A.push(G)}),this.on("end",()=>{B=!0;for(let G of Q)G.resolve(void 0);Q.length=0}),this.on("abort",(G)=>{B=!0;for(let Z of Q)Z.reject(G);Q.length=0}),this.on("error",(G)=>{B=!0;for(let Z of Q)Z.reject(G);Q.length=0}),{next:async()=>{if(!A.length){if(B)return{value:void 0,done:!0};return new Promise((Z,Y)=>Q.push({resolve:Z,reject:Y})).then((Z)=>Z?{value:Z,done:!1}:{value:void 0,done:!0})}return{value:A.shift(),done:!1}},return:async()=>{return this.abort(),{value:void 0,done:!0}}}}toReadableStream(){return new i$(this[Symbol.asyncIterator].bind(this),this.controller).toReadableStream()}}});var rRA;var IQ0=w(()=>{Qk();LR();r00();wQA();en();rRA=class rRA extends xX{create(A,Q){return this._client.post("/v1/messages/batches",{body:A,...Q})}retrieve(A,Q){return this._client.get(oJ`/v1/messages/batches/${A}`,Q)}list(A={},Q){return this._client.getAPIList("/v1/messages/batches",AP,{query:A,...Q})}delete(A,Q){return this._client.delete(oJ`/v1/messages/batches/${A}`,Q)}cancel(A,Q){return this._client.post(oJ`/v1/messages/batches/${A}/cancel`,Q)}async results(A,Q){let B=await this.retrieve(A);if(!B.results_url)throw new q2(`No batch \`results_url\`; Has it finished processing? ${B.processing_status} - ${B.id}`)
|
||||
|
||||
return NB(Z,Q1({input:G,output:Y.map((J,X)=>LrB(J,OrB,X))},null,2),{encoding:"utf8",flush:!1}),Y}function ki8(A){if(A.type==="stream_event")return;let Q=A.message.model,B=A.message.usage,G=lsA(Q,B);msA(G,B,Q)}function bi8(A,Q){return A.map((B)=>{if(typeof B==="string")return Q(B);return B.map((G)=>{switch(G.type){case"tool_result":if(typeof G.content==="string")return{...G,content:Q(G.content)};if(Array.isArray(G.content))return{...G,content:G.content.map((Z)=>{switch(Z.type){case"text":return{...Z,text:Q(Z.text)};case"image":return Z;default:return}})};return G;case"text":return{...G,text:Q(G.text)};case"tool_use":return{...G,input:Z81(G.input,Q)};case"image":return G;default:return}})})}function Z81(A,Q){return YAA(A,(B,G)=>{if(Array.isArray(B))return B.map((Z)=>Z81(Z,Q));if(c8A(B))return Z81(B,Q);return Q(B,G,A)})}function fi8(A,Q,B){return{uuid:`UUID-${B}`,requestId:"REQUEST_ID",timestamp:A.timestamp,message:{...A.message,content:A.message.content.map((G)=>{switch(G.type){case"text":return{...G,text:Q(G.text),citations:G.citations||[]};case"tool_use":return{...G,input:Z81(G.input,Q)};default:return G}}).filter(Boolean)},type:"assistant"}}function LrB(A,Q,B){if(A.type==="assistant")return fi8(A,Q,B);else return A}function OrB(A){if(typeof A!=="string")return A;let Q=A.replace(/num_files="\d+"/g,'num_files="[NUM]"').replace(/duration_ms="\d+"/g,'duration_ms="[DURATION]"').replace(/cost_usd="\d+"/g,'cost_usd="[COST]"').replace(/\//g,_rB.sep).replaceAll(yQ(),"[CONFIG_HOME]").replaceAll(l1(),"[CWD]").replace(/Available commands:.+/,"Available commands: [COMMANDS]");if(Q.includes("Files modified by user:"))return"Files modified by user: [FILES]";return Q}function hi8(A){if(typeof A!=="string")return A;return A.replaceAll("[NUM]","1").replaceAll("[DURATION]","100").replaceAll("[CONFIG_HOME]",yQ()).replaceAll("[CWD]",l1())}async function*l50(A,Q){if(!p50())return yield*Q();let B=[],G=await c50(A,async()=>{for await(let Z of Q())B.push(Z);return B});if(G.length>0){yield*G
|
||||
|
||||
if(HA>KA)yA++,CA+=HA,k(`Streaming stall detected: ${(HA/1000).toFixed(1)}s gap between events (stall #${yA})`,{level:"warn"}),l("tengu_streaming_stall",{stall_duration_ms:HA,stall_count:yA,total_stall_time_ms:CA,event_type:BA.type,model:Y.model,request_id:v.request_id??"unknown"})}if(FA=GA,s){if(k("Stream started - received first chunk"),b6("query_first_chunk_received"),!Y.agentId)d6A("first_chunk");d19(),s=!1}switch(BA.type){case"message_start":{e=BA.message,u=Date.now()-_,b=jfA(b,BA.message.usage);break}case"content_block_start":switch(BA.content_block.type){case"tool_use":t[BA.index]={...BA.content_block,input:""};break;case"server_tool_use":t[BA.index]={...BA.content_block,input:""};break;case"text":t[BA.index]={...BA.content_block,text:""};break;case"thinking":t[BA.index]={...BA.content_block,thinking:""};break;default:t[BA.index]={...BA.content_block};break}break;case"content_block_delta":{let HA=t[BA.index];if(!HA)throw l("tengu_streaming_error",{error_type:"content_block_not_found_delta",part_type:BA.type,part_index:BA.index}),RangeError("Content block not found");switch(BA.delta.type){case"citations_delta":break;case"input_json_delta":if(HA.type!=="tool_use"&&HA.type!=="server_tool_use")throw l("tengu_streaming_error",{error_type:"content_block_type_mismatch_input_json",expected_type:"tool_use",actual_type:HA.type}),Error("Content block is not a input_json block");if(typeof HA.input!=="string")throw l("tengu_streaming_error",{error_type:"content_block_input_not_string",input_type:typeof HA.input}),Error("Content block input is not a string");HA.input+=BA.delta.partial_json;break;case"text_delta":if(HA.type!=="text")throw l("tengu_streaming_error",{error_type:"content_block_type_mismatch_text",expected_type:"text",actual_type:HA.type}),Error("Content block is not a text block");HA.text+=BA.delta.text;break
|
||||
|
||||
case"signature_delta":if(HA.type!=="thinking")throw l("tengu_streaming_error",{error_type:"content_block_type_mismatch_thinking_signature",expected_type:"thinking",actual_type:HA.type}),Error("Content block is not a thinking block");HA.signature=BA.delta.signature;break;case"thinking_delta":if(HA.type!=="thinking")throw l("tengu_streaming_error",{error_type:"content_block_type_mismatch_thinking_delta",expected_type:"thinking",actual_type:HA.type}),Error("Content block is not a thinking block");HA.thinking+=BA.delta.thinking;break}break}case"content_block_stop":{let HA=t[BA.index];if(!HA)throw l("tengu_streaming_error",{error_type:"content_block_not_found_stop",part_type:BA.type,part_index:BA.index}),RangeError("Content block not found");if(!e)throw l("tengu_streaming_error",{error_type:"partial_message_not_found",part_type:BA.type}),Error("Message not found");let EA={message:{...e,content:xj0([HA],G,Y.agentId)},requestId:v.request_id??void 0,type:"assistant",uuid:aH9(),timestamp:new Date().toISOString(),...{}};m.push(EA),yield EA;break}case"message_delta":{b=jfA(b,BA.usage),AA=BA.delta.stop_reason;let HA=lsA(J,b);msA(HA,b,Y.model),p+=HA;let EA=soB(BA.delta.stop_reason,Y.model);if(EA)yield EA;if(AA==="max_tokens")l("tengu_max_tokens_reached",{max_tokens:MA}),yield MY({content:`${TV}: Claude's response exceeded the ${MA} output token maximum. To configure this behavior, set the CLAUDE_CODE_MAX_OUTPUT_TOKENS environment variable.`,apiError:"max_output_tokens"});if(AA==="model_context_window_exceeded")l("tengu_context_window_exceeded",{max_tokens:MA,output_tokens:b.output_tokens}),yield MY({content:`${TV}: The model has reached its context window limit.`});break}case"message_stop":break}yield{type:"stream_event",event:BA}}if(yA>0)k(`Streaming completed with ${yA} stall(s), total stall time: ${(CA/1000).toFixed(1)}s`,{level:"warn"}),l("tengu_streaming_stall_summary",{stall_count:yA,total_stall_time_ms:CA,model:Y.model,request_id:v.request_id??"unknown"});let uA=(await v.withResponse()).response
|
||||
|
||||
return null}function g39(A){if(A.type!=="user")return null;let Q=A.message.content;return z6A(Q)}function z6A(A){if(typeof A==="string")return A;if(Array.isArray(A))return A.filter((Q)=>Q.type==="text").map((Q)=>Q.type==="text"?Q.text:"").join(`
|
||||
`).trim()||null;return null}function HF1(A,Q,B,G,Z,Y,J){if(A.type!=="stream_event"&&A.type!=="stream_request_start"){if(A.type==="tombstone"){Y?.(A.message);return}if(A.type==="assistant"){let X=A.message.content.find((I)=>I.type==="thinking");if(X&&X.type==="thinking")J?.(()=>({thinking:X.thinking,isStreaming:!1,streamingEndedAt:Date.now()}))}Q(A);return}if(A.type==="stream_request_start"){G("requesting");return}if(A.event.type==="message_stop"){G("tool-use"),Z(()=>[]);return}switch(A.event.type){case"content_block_start":switch(A.event.content_block.type){case"thinking":case"redacted_thinking":G("thinking");return;case"text":G("responding");return;case"tool_use":{G("tool-input");let X=A.event.content_block,I=A.event.index;Z((W)=>[...W,{index:I,contentBlock:X,unparsedToolInput:""}]);return}case"server_tool_use":case"web_search_tool_result":case"code_execution_tool_result":case"mcp_tool_use":case"mcp_tool_result":case"container_upload":case"web_fetch_tool_result":case"bash_code_execution_tool_result":case"text_editor_code_execution_tool_result":G("tool-input");return}break;case"content_block_delta":switch(A.event.delta.type){case"text_delta":B(A.event.delta.text);return;case"input_json_delta":{let X=A.event.delta.partial_json,I=A.event.index;B(X),Z((W)=>{let K=W.find((V)=>V.index===I);if(!K)return W;return[...W.filter((V)=>V!==K),{...K,unparsedToolInput:K.unparsedToolInput+X}]});return}case"thinking_delta":B(A.event.delta.thinking);return;case"signature_delta":B(A.event.delta.signature);return;default:return}case"content_block_stop":return;case"message_delta":G("responding");return;default:G("responding")
|
||||
|
|
@ -0,0 +1,479 @@
|
|||
"tengu_startup_perf"
|
||||
"tengu_ripgrep_eagain_retry"
|
||||
"tengu_ripgrep_availability"
|
||||
"tengu_oauth_token_exchange_success"
|
||||
"tengu_oauth_token_refresh_success"
|
||||
"tengu_oauth_token_refresh_failure"
|
||||
"tengu_oauth_roles_stored"
|
||||
"tengu_oauth_api_key"
|
||||
"tengu_oauth_profile_fetch_success"
|
||||
"tengu_unknown_model_cost"
|
||||
"tengu_opus_default_pro_plan"
|
||||
"tengu_tool_pear"
|
||||
"tengu_awsAuthRefresh_missing_trust"
|
||||
"tengu_awsCredentialExport_missing_trust"
|
||||
"tengu_api_key_saved_to_keychain"
|
||||
"tengu_api_key_keychain_error"
|
||||
"tengu_api_key_saved_to_config"
|
||||
"tengu_oauth_tokens_not_claude_ai"
|
||||
"tengu_oauth_tokens_inference_only"
|
||||
"tengu_oauth_tokens_saved"
|
||||
"tengu_oauth_tokens_save_failed"
|
||||
"tengu_oauth_tokens_save_exception"
|
||||
"tengu_oauth_401_recovered_from_keychain"
|
||||
"tengu_oauth_token_refresh_lock_acquiring"
|
||||
"tengu_oauth_token_refresh_lock_acquired"
|
||||
"tengu_oauth_token_refresh_lock_retry"
|
||||
"tengu_oauth_token_refresh_lock_retry_limit_reached"
|
||||
"tengu_oauth_token_refresh_lock_error"
|
||||
"tengu_oauth_token_refresh_race_resolved"
|
||||
"tengu_oauth_token_refresh_starting"
|
||||
"tengu_oauth_token_refresh_race_recovered"
|
||||
"tengu_oauth_token_refresh_lock_releasing"
|
||||
"tengu_oauth_token_refresh_lock_released"
|
||||
"tengu_apiKeyHelper_missing_trust11"
|
||||
"tengu_worktree_detection"
|
||||
"tengu_config_cache_stats"
|
||||
"tengu_config_lock_contention"
|
||||
"tengu_config_stale_write"
|
||||
"tengu_config_parse_error"
|
||||
"tengu_c4w_usage_limit_notifications_enabled"
|
||||
"tengu_teams_usage_limit_notifications"
|
||||
"tengu_1p_event_batch_config"
|
||||
"tengu_event_sampling_config"
|
||||
"tengu_ant_attribution_header_new"
|
||||
"tengu_sumi"
|
||||
"tengu_thinking"
|
||||
"tengu_claudeai_limits_status_changed"
|
||||
"tengu_tool_use_tool_result_mismatch_error"
|
||||
"tengu_unexpected_tool_result"
|
||||
"tengu_refusal_api_response"
|
||||
"tengu_api_opus_fallback_triggered"
|
||||
"tengu_api_custom_529_overloaded_error"
|
||||
"tengu_max_tokens_context_overflow_adjustment"
|
||||
"tengu_api_retry"
|
||||
"tengu_shell_snapshot_failed"
|
||||
"tengu_shell_unknown_error"
|
||||
"tengu_shell_snapshot_error"
|
||||
"tengu_shell_set_cwd"
|
||||
"tengu_bash_tool_reset_to_original_dir"
|
||||
"tengu_mcp_tool_search"
|
||||
"tengu_tool_search_unsupported_models"
|
||||
"tengu_file_operation"
|
||||
"tengu_tool_result_persistence"
|
||||
"tengu_tool_result_persisted"
|
||||
"tengu_mcp_oauth_flow_start"
|
||||
"tengu_mcp_oauth_flow_success"
|
||||
"tengu_mcp_oauth_flow_error"
|
||||
"tengu_vscode_review_upsell"
|
||||
"tengu_year_end_2025_campaign_promo"
|
||||
"tengu_vscode_onboarding"
|
||||
"tengu_file_history_track_edit_failed"
|
||||
"tengu_file_history_track_edit_success"
|
||||
"tengu_file_history_backup_deleted_file"
|
||||
"tengu_file_history_backup_file_failed"
|
||||
"tengu_file_history_snapshot_success"
|
||||
"tengu_file_history_snapshot_failed"
|
||||
"tengu_file_history_rewind_failed"
|
||||
"tengu_file_history_rewind_success"
|
||||
"tengu_file_history_rewind_restore_file_failed"
|
||||
"tengu_file_history_backup_file_created"
|
||||
"tengu_file_history_resume_copy_failed"
|
||||
"tengu_oauth_automatic_redirect"
|
||||
"tengu_oauth_automatic_redirect_error"
|
||||
"tengu_managed_settings_security_dialog_shown"
|
||||
"tengu_managed_settings_security_dialog_accepted"
|
||||
"tengu_managed_settings_security_dialog_rejected"
|
||||
"tengu_oauth_auth_code_received"
|
||||
"tengu_notification_method_used"
|
||||
"tengu_oauth_claudeai_forced"
|
||||
"tengu_oauth_console_forced"
|
||||
"tengu_oauth_success"
|
||||
"tengu_oauth_manual_entry"
|
||||
"tengu_oauth_flow_start"
|
||||
"tengu_oauth_token_exchange_error"
|
||||
"tengu_oauth_storage_warning"
|
||||
"tengu_oauth_user_roles_error"
|
||||
"tengu_oauth_api_key_error"
|
||||
"tengu_oauth_error"
|
||||
"tengu_oauth_claudeai_selected"
|
||||
"tengu_oauth_console_selected"
|
||||
"tengu_teleport_error_git_not_clean"
|
||||
"tengu_teleport_error_branch_checkout_failed"
|
||||
"tengu_teleport_resume_error"
|
||||
"tengu_teleport_error_repo_not_in_git_dir_sessions_api"
|
||||
"tengu_teleport_error_repo_mismatch_sessions_api"
|
||||
"tengu_teleport_errors_detected"
|
||||
"tengu_teleport_errors_resolved"
|
||||
"tengu_teleport_error_session_not_found_404"
|
||||
"tengu_file_changed"
|
||||
"tengu_bash_security_check_triggered"
|
||||
"tengu_version_config"
|
||||
"tengu_auto_updater_lock_contention"
|
||||
"tengu_auto_updater_windows_npm_in_wsl"
|
||||
"tengu_tree_sitter_load"
|
||||
"tengu_git_operation"
|
||||
"tengu_bash_command_timeout_backgrounded"
|
||||
"tengu_bash_command_explicitly_backgrounded"
|
||||
"tengu_git_index_lock_error"
|
||||
"tengu_bash_tool_haiku_file_paths_read"
|
||||
"tengu_bash_tool_command_executed"
|
||||
"tengu_code_indexing_tool_used"
|
||||
"tengu_plugin_installed"
|
||||
"tengu_claudeai_mcp_connectors"
|
||||
"tengu_mcp_headersHelper_missing_trust"
|
||||
"tengu_mcp_server_needs_auth"
|
||||
"tengu_mcp_ide_server_connection_failed"
|
||||
"tengu_mcp_ide_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_failed"
|
||||
"tengu_mcp_tools_commands_loaded"
|
||||
"tengu_ext_installed"
|
||||
"tengu_ext_install_error"
|
||||
"tengu_claude_md_permission_error"
|
||||
"tengu_claude_rules_md_permission_error"
|
||||
"tengu_attachment_compute_duration"
|
||||
"tengu_at_mention_extracting_directory_success"
|
||||
"tengu_at_mention_extracting_filename_success"
|
||||
"tengu_at_mention_extracting_filename_error"
|
||||
"tengu_at_mention_agent_not_found"
|
||||
"tengu_at_mention_agent_success"
|
||||
"tengu_at_mention_mcp_resource_error"
|
||||
"tengu_at_mention_mcp_resource_success"
|
||||
"tengu_watched_file_compression_failed"
|
||||
"tengu_watched_file_stat_error"
|
||||
"tengu_attachments"
|
||||
"tengu_attachment_file_too_large"
|
||||
"tengu_compact_failed"
|
||||
"tengu_compact"
|
||||
"tengu_post_compact_file_restore_success"
|
||||
"tengu_post_compact_file_restore_error"
|
||||
"tengu_compact_mc_files"
|
||||
"tengu_microcompact"
|
||||
"tengu_session_memory"
|
||||
"tengu_sm_compact"
|
||||
"tengu_sm_compact_empty_template"
|
||||
"tengu_sm_compact_summarized_id_not_found"
|
||||
"tengu_sm_compact_resumed_session"
|
||||
"tengu_sm_compact_threshold_exceeded"
|
||||
"tengu_write_claudemd"
|
||||
"tengu_file_edit_optimization"
|
||||
"tengu_agent_parse_error"
|
||||
"tengu_message_selector_opened"
|
||||
"tengu_message_selector_selected"
|
||||
"tengu_message_selector_restore_option_selected"
|
||||
"tengu_message_selector_cancelled"
|
||||
"tengu_unary_event"
|
||||
"tengu_tool_use_show_permission_request"
|
||||
"tengu_accept_with_instructions_submitted"
|
||||
"tengu_accept_with_feedback"
|
||||
"tengu_accept_feedback_mode_entered"
|
||||
"tengu_reject_feedback_mode_entered"
|
||||
"tengu_ext_will_show_diff"
|
||||
"tengu_ext_diff_accepted"
|
||||
"tengu_ext_diff_rejected"
|
||||
"tengu_permission_request_escape"
|
||||
"tengu_permission_request_option_selected"
|
||||
"tengu_plan_external_editor_used"
|
||||
"tengu_plan_exit"
|
||||
"tengu_slash_command_forked"
|
||||
"tengu_input_slash_missing"
|
||||
"tengu_input_slash_invalid"
|
||||
"tengu_input_prompt"
|
||||
"tengu_input_command"
|
||||
"tengu_skill_tool_invocation"
|
||||
"tengu_skill_tool_slash_prefix"
|
||||
"tengu_version_check_success"
|
||||
"tengu_version_check_failure"
|
||||
"tengu_native_cdn_dark_read_success"
|
||||
"tengu_native_cdn_dark_read_failure"
|
||||
"tengu_binary_download_attempt"
|
||||
"tengu_binary_manifest_fetch_failure"
|
||||
"tengu_binary_platform_not_found"
|
||||
"tengu_binary_download_success"
|
||||
"tengu_binary_download_failure"
|
||||
"tengu_pid_based_version_locking"
|
||||
"tengu_version_lock_acquired"
|
||||
"tengu_version_lock_failed"
|
||||
"tengu_native_install_package_failure"
|
||||
"tengu_native_install_package_success"
|
||||
"tengu_native_install_binary_failure"
|
||||
"tengu_native_install_binary_success"
|
||||
"tengu_native_update_complete"
|
||||
"tengu_native_update_skipped_minimum_version"
|
||||
"tengu_native_update_lock_failed"
|
||||
"tengu_native_installation"
|
||||
"tengu_native_staging_cleanup"
|
||||
"tengu_native_temp_files_cleanup"
|
||||
"tengu_native_stale_locks_cleanup"
|
||||
"tengu_native_version_cleanup"
|
||||
"tengu_auto_updater_success"
|
||||
"tengu_auto_updater_fail"
|
||||
"tengu_native_auto_updater_start"
|
||||
"tengu_native_auto_updater_lock_contention"
|
||||
"tengu_native_auto_updater_success"
|
||||
"tengu_native_auto_updater_up_to_date"
|
||||
"tengu_native_auto_updater_fail"
|
||||
"tengu_auto_migrate_to_native_attempt"
|
||||
"tengu_auto_migrate_to_native_success"
|
||||
"tengu_auto_migrate_to_native_partial"
|
||||
"tengu_auto_migrate_to_native_failure"
|
||||
"tengu_auto_migrate_to_native_ui_shown"
|
||||
"tengu_auto_migrate_to_native_ui_success"
|
||||
"tengu_auto_migrate_to_native_ui_error"
|
||||
"tengu_external_editor_hint_shown"
|
||||
"tengu_file_suggestions_git_ls_files"
|
||||
"tengu_file_suggestions_ripgrep"
|
||||
"tengu_mcp_list_changed"
|
||||
"tengu_mcp_servers"
|
||||
"tengu_shell_completion_failed"
|
||||
"tengu_typing_without_terminal_focus"
|
||||
"tengu_status_line_mount"
|
||||
"tengu_react_vulnerability_warning"
|
||||
"tengu_sonnet_1m_notice_shown"
|
||||
"tengu_opus_45_notice_shown"
|
||||
"tengu_react_vulnerability_notice_shown"
|
||||
"tengu_guest_passes_upsell_shown"
|
||||
"tengu_prompt_suggestion"
|
||||
"tengu_help_toggled"
|
||||
"tengu_paste_image"
|
||||
"tengu_ext_at_mentioned"
|
||||
"tengu_external_editor_used"
|
||||
"tengu_mode_cycle"
|
||||
"tengu_model_picker_hotkey"
|
||||
"tengu_thinking_toggled_hotkey"
|
||||
"tengu_timer"
|
||||
"tengu_toggle_todos"
|
||||
"tengu_cancel"
|
||||
"tengu_tool_use_granted_in_config"
|
||||
"tengu_tool_use_granted_in_prompt_permanent"
|
||||
"tengu_tool_use_granted_in_prompt_temporary"
|
||||
"tengu_tool_use_granted_by_permission_hook"
|
||||
"tengu_tool_use_rejected_in_prompt"
|
||||
"tengu_tool_use_cancelled"
|
||||
"tengu_tool_use_denied_in_config"
|
||||
"tengu_input_background"
|
||||
"tengu_input_bash"
|
||||
"tengu_subagent_at_mention"
|
||||
"tengu_paste_text"
|
||||
"tengu_headless_latency"
|
||||
"tengu_api_query"
|
||||
"tengu_api_error"
|
||||
"tengu_teleport_first_message_error"
|
||||
"tengu_api_success"
|
||||
"tengu_teleport_first_message_success"
|
||||
"tengu_cache_warming_request"
|
||||
"tengu_feedback_survey_config"
|
||||
"tengu_feedback_survey_event"
|
||||
"tengu_post_compact_survey_event"
|
||||
"tengu_post_compact_survey"
|
||||
"tengu_official_marketplace_auto_install"
|
||||
"tengu_tip_shown"
|
||||
"tengu_switch_to_subscription_notice_shown"
|
||||
"tengu_ant_plan_verification_result"
|
||||
"tengu_session_resumed"
|
||||
"tengu_cost_threshold_reached"
|
||||
"tengu_concurrent_onquery_detected"
|
||||
"tengu_concurrent_onquery_enqueued"
|
||||
"tengu_cost_threshold_acknowledged"
|
||||
"tengu_agent_tool_completed"
|
||||
"tengu_agent_tool_selected"
|
||||
"tengu_sysprompt_block"
|
||||
"tengu_context_size"
|
||||
"tengu_bash_tool_simple_echo"
|
||||
"tengu_auto_compact_succeeded"
|
||||
"tengu_streaming_tool_execution2"
|
||||
"tengu_orphaned_messages_tombstoned"
|
||||
"tengu_model_fallback_triggered"
|
||||
"tengu_query_error"
|
||||
"tengu_model_response_keyword_detected"
|
||||
"tengu_streaming_tool_execution_used"
|
||||
"tengu_streaming_tool_execution_not_used"
|
||||
"tengu_post_autocompact_turn"
|
||||
"tengu_query_before_attachments"
|
||||
"tengu_query_after_attachments"
|
||||
"tengu_steering_attachment_resending"
|
||||
"tengu_pre_stop_hooks_cancelled"
|
||||
"tengu_stop_hook_error"
|
||||
"tengu_tool_use_error"
|
||||
"tengu_tool_use_progress"
|
||||
"tengu_tool_use_can_use_tool_rejected"
|
||||
"tengu_tool_use_can_use_tool_allowed"
|
||||
"tengu_tool_use_success"
|
||||
"tengu_post_tool_hooks_cancelled"
|
||||
"tengu_post_tool_hook_error"
|
||||
"tengu_post_tool_failure_hooks_cancelled"
|
||||
"tengu_post_tool_failure_hook_error"
|
||||
"tengu_pre_tool_hooks_cancelled"
|
||||
"tengu_pre_tool_hook_error"
|
||||
"tengu_fork_agent_query"
|
||||
"tengu_prompt_suggestion_init"
|
||||
"tengu_prompt_suggestion_variation"
|
||||
"tengu_agent_stop_hook_max_turns"
|
||||
"tengu_agent_stop_hook_error"
|
||||
"tengu_agent_stop_hook_success"
|
||||
"tengu_run_hook"
|
||||
"tengu_repl_hook_finished"
|
||||
"tengu_bug_report_submitted"
|
||||
"tengu_claude_md_includes_dialog_shown"
|
||||
"tengu_claude_md_external_includes_dialog_declined"
|
||||
"tengu_claude_md_external_includes_dialog_accepted"
|
||||
"tengu_config_model_changed"
|
||||
"tengu_auto_compact_setting_changed"
|
||||
"tengu_tips_setting_changed"
|
||||
"tengu_thinking_toggled"
|
||||
"tengu_file_history_snapshots_setting_changed"
|
||||
"tengu_terminal_progress_bar_setting_changed"
|
||||
"tengu_config_changed"
|
||||
"tengu_respect_gitignore_setting_changed"
|
||||
"tengu_editor_mode_changed"
|
||||
"tengu_diff_tool_changed"
|
||||
"tengu_auto_connect_ide_changed"
|
||||
"tengu_auto_install_ide_extension_changed"
|
||||
"tengu_claude_in_chrome_setting_changed"
|
||||
"tengu_autoupdate_channel_changed"
|
||||
"tengu_output_style_changed"
|
||||
"tengu_language_changed"
|
||||
"tengu_ext_ide_command"
|
||||
"tengu_setup_github_actions_failed"
|
||||
"tengu_setup_github_actions_started"
|
||||
"tengu_setup_github_actions_completed"
|
||||
"tengu_install_github_app_started"
|
||||
"tengu_install_github_app_step_completed"
|
||||
"tengu_install_github_app_error"
|
||||
"tengu_install_github_app_completed"
|
||||
"tengu_install_slack_app_clicked"
|
||||
"tengu_mcp_auth_config_authenticate"
|
||||
"tengu_mcp_auth_config_clear"
|
||||
"tengu_session_search_toggled"
|
||||
"tengu_agentic_search_cancelled"
|
||||
"tengu_session_tag_filter_changed"
|
||||
"tengu_session_all_projects_toggled"
|
||||
"tengu_session_branch_filter_toggled"
|
||||
"tengu_session_rename_started"
|
||||
"tengu_session_preview_opened"
|
||||
"tengu_session_group_expanded"
|
||||
"tengu_thinkback"
|
||||
"tengu_guest_passes_link_copied"
|
||||
"tengu_guest_passes_visited"
|
||||
"tengu_grove_policy_viewed"
|
||||
"tengu_grove_policy_submitted"
|
||||
"tengu_grove_policy_dismissed"
|
||||
"tengu_grove_policy_escaped"
|
||||
"tengu_grove_privacy_settings_viewed"
|
||||
"tengu_grove_print_viewed"
|
||||
"tengu_grove_policy_toggled"
|
||||
"tengu_hook_created"
|
||||
"tengu_hook_deleted"
|
||||
"tengu_hooks_command"
|
||||
"tengu_agent_definition_generated"
|
||||
"tengu_agent_created"
|
||||
"tengu_marketplace_added"
|
||||
"tengu_marketplace_removed"
|
||||
"tengu_marketplace_updated"
|
||||
"tengu_sm_config"
|
||||
"tengu_session_memory_extraction"
|
||||
"tengu_model_command_menu"
|
||||
"tengu_model_command_inline_help"
|
||||
"tengu_model_command_inline"
|
||||
"tengu_tag_command_remove_prompt"
|
||||
"tengu_tag_command_add"
|
||||
"tengu_tag_command_remove_confirmed"
|
||||
"tengu_tag_command_remove_cancelled"
|
||||
"tengu_output_style_command_menu"
|
||||
"tengu_output_style_command_inline_help"
|
||||
"tengu_output_style_command_inline"
|
||||
"tengu_rate_limit_options_menu_cancel"
|
||||
"tengu_rate_limit_options_menu_select_upgrade"
|
||||
"tengu_rate_limit_options_menu_select_extra_usage"
|
||||
"tengu_off_switch_query"
|
||||
"tengu_api_before_normalize"
|
||||
"tengu_api_after_normalize"
|
||||
"tengu_streaming_stall"
|
||||
"tengu_streaming_error"
|
||||
"tengu_max_tokens_reached"
|
||||
"tengu_context_window_exceeded"
|
||||
"tengu_streaming_stall_summary"
|
||||
"tengu_streaming_fallback_to_non_streaming"
|
||||
"tengu_api_cache_breakpoints"
|
||||
"tengu_bash_prefix"
|
||||
"tengu_disable_bypass_permissions_mode"
|
||||
"tengu_dir_search"
|
||||
"tengu_empty_model_response"
|
||||
"tengu_filtered_trailing_thinking_block"
|
||||
"tengu_session_persistence_failed"
|
||||
"tengu_session_forked_branches_fetched"
|
||||
"tengu_session_renamed"
|
||||
"tengu_session_tagged"
|
||||
"tengu_session_index"
|
||||
"tengu_atomic_write_error"
|
||||
"tengu_mcp_cli_command_executed"
|
||||
"tengu_node_warning"
|
||||
"tengu_session_quality_classification"
|
||||
"tengu_preflight_check_failed"
|
||||
"tengu_began_setup"
|
||||
"tengu_onboarding_step"
|
||||
"tengu_trust_dialog_shown"
|
||||
"tengu_trust_dialog_accept"
|
||||
"tengu_plugin_installed_cli"
|
||||
"tengu_plugin_uninstalled_cli"
|
||||
"tengu_plugin_enabled_cli"
|
||||
"tengu_plugin_disabled_cli"
|
||||
"tengu_plugin_updated_cli"
|
||||
"tengu_mcp_multidialog_choice"
|
||||
"tengu_mcp_dialog_choice"
|
||||
"tengu_oauth_token_refresh_completed"
|
||||
"tengu_log_segment_events"
|
||||
"tengu_log_datadog_events"
|
||||
"tengu_bypass_permissions_mode_dialog_shown"
|
||||
"tengu_bypass_permissions_mode_dialog_accept"
|
||||
"tengu_claude_in_chrome_onboarding_shown"
|
||||
"tengu_migrate_autoupdates_to_settings"
|
||||
"tengu_migrate_autoupdates_error"
|
||||
"tengu_migrate_mcp_approval_fields_success"
|
||||
"tengu_migrate_mcp_approval_fields_error"
|
||||
"tengu_migrate_ignore_patterns_success"
|
||||
"tengu_migrate_ignore_patterns_config_cleanup_error"
|
||||
"tengu_migrate_ignore_patterns_error"
|
||||
"tengu_continue_print"
|
||||
"tengu_teleport_print"
|
||||
"tengu_resume_print"
|
||||
"tengu_update_check"
|
||||
"tengu_claude_install_command"
|
||||
"tengu_teleport_resume_session"
|
||||
"tengu_teleport_started"
|
||||
"tengu_teleport_cancelled"
|
||||
"tengu_managed_settings_loaded"
|
||||
"tengu_mcp_cli_status"
|
||||
"tengu_grove_policy_exited"
|
||||
"tengu_startup_telemetry"
|
||||
"tengu_exit"
|
||||
"tengu_stdin_interactive"
|
||||
"tengu_flicker"
|
||||
"tengu_code_prompt_ignored"
|
||||
"tengu_single_word_prompt"
|
||||
"tengu_claude_in_chrome_setup"
|
||||
"tengu_claude_in_chrome_setup_failed"
|
||||
"tengu_structured_output_enabled"
|
||||
"tengu_structured_output_failure"
|
||||
"tengu_startup_manual_model_config"
|
||||
"tengu_continue"
|
||||
"tengu_remote_create_session"
|
||||
"tengu_remote_create_session_error"
|
||||
"tengu_remote_create_session_success"
|
||||
"tengu_teleport_interactive_mode"
|
||||
"tengu_mcp_start"
|
||||
"tengu_mcp_add"
|
||||
"tengu_mcp_delete"
|
||||
"tengu_mcp_list"
|
||||
"tengu_mcp_get"
|
||||
"tengu_mcp_reset_mcpjson_choices"
|
||||
"tengu_marketplace_updated_all"
|
||||
"tengu_plugin_install_command"
|
||||
"tengu_plugin_uninstall_command"
|
||||
"tengu_plugin_enable_command"
|
||||
"tengu_plugin_disable_command"
|
||||
"tengu_plugin_update_command"
|
||||
"tengu_setup_token_command"
|
||||
"tengu_doctor_command"
|
||||
"tengu_init"
|
||||
File diff suppressed because one or more lines are too long
42
docs/research/claude-code-rvsource/versions/v2.1.x/README.md
Normal file
42
docs/research/claude-code-rvsource/versions/v2.1.x/README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Claude Code v2.1.91 (2.1 series)
|
||||
|
||||
## Binary RVF Container
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Version | 2.1.91 |
|
||||
| Series | 2.1 |
|
||||
| Bundle size | 12.6MB |
|
||||
| RVF size | 1056.8KB |
|
||||
| Vectors | 2068 |
|
||||
| RVF File ID | `6d9f5dde25a78a28ea8ba6def10250b8` |
|
||||
| Classes | 1632 |
|
||||
| Functions | 19906 |
|
||||
| Modules | 9 |
|
||||
| Extracted | 2026-04-02T23:29:04+00:00 |
|
||||
|
||||
## Files
|
||||
|
||||
- `claude-code-v2.1.rvf` - Binary RVF container with HNSW index + witness chain
|
||||
- `claude-code-v2.1.rvf.manifest.json` - Container manifest (vector ID map, metadata)
|
||||
- `source/` - Extracted JavaScript module fragments
|
||||
|
||||
## RVF Container Details
|
||||
|
||||
The `.rvf` file is a real binary container created with the `@ruvector/rvf-node`
|
||||
native backend. It contains:
|
||||
|
||||
- **128-dimensional fingerprint vectors** for each code fragment
|
||||
- **HNSW index** (M=16, ef_construction=200) for fast similarity search
|
||||
- **Cosine distance** metric
|
||||
- **Witness chain** for provenance verification
|
||||
|
||||
To query this container:
|
||||
|
||||
```typescript
|
||||
import { RvfDatabase } from '@ruvector/rvf';
|
||||
|
||||
const db = await RvfDatabase.openReadonly('./claude-code-v2.1.rvf');
|
||||
const results = await db.query(queryVector, 10);
|
||||
await db.close();
|
||||
```
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,93 @@
|
|||
name:"navigate",description:"Navigate to a URL, or go forward/back in browser history. If you don't have a valid tab ID, use tabs_context_mcp first to get available tabs."
|
||||
name:"sharp",description:"High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images"
|
||||
name:"zoom",description:"Take a higher-resolution screenshot of a specific region of the last full-screen screenshot. Use this liberally to inspect small text, button labels, or fine UI details that are hard to read in the downsampled full-screen image. IMPORTANT: Coordinates in subsequent click calls always refer to the full-screen screenshot, never the zoomed image. This tool is read-only for inspecting detail."
|
||||
name:"type",description:"Type text into whatever currently has keyboard focus. The frontmost application must be in the session allowlist at the time of this call, or this tool returns an error and does nothing. Newlines are supported. For keyboard shortcuts use `key` instead."
|
||||
name:"scroll",description:"Scroll at the given coordinates. The frontmost application must be in the session allowlist at the time of this call, or this tool returns an error and does nothing."
|
||||
name:"wait",description:"Wait for a specified duration."
|
||||
name:"extra-usage",description:"Configure extra usage to keep working when limits are hit"
|
||||
name:"add-dir",description:"Add a new working directory"
|
||||
name:"btw",description:"Ask a quick side question without interrupting the main conversation"
|
||||
name:"feedback",description:"Submit feedback about Claude Code"
|
||||
name:"clear",description:"Clear conversation history and free up context"
|
||||
name:"color",description:"Set the prompt bar color for this session"
|
||||
name:"commit",description:"Create a git commit"
|
||||
name:"copy",description:"Copy Claude's last response to clipboard (or /copy N for the Nth-latest)"
|
||||
name:"commit-push-pr",description:"Commit, push, and open a PR"
|
||||
name:"compact",description:"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]"
|
||||
name:"autocompact",description:"Configure the auto-compact window size"
|
||||
name:"config",description:"Open config panel"
|
||||
name:"context",description:"Visualize current context usage as a colored grid"
|
||||
name:"cost",description:"Show the total cost and duration of the current session"
|
||||
name:"diff",description:"View uncommitted changes and per-turn diffs"
|
||||
name:"doctor",description:"Diagnose and verify your Claude Code installation and settings"
|
||||
name:"memory",description:"Edit Claude memory files"
|
||||
name:"toggle-memory",description:"Toggle automemory off/on for this session"
|
||||
name:"help",description:"Show help and available commands"
|
||||
name:"ide",description:"Manage IDE integrations and show status"
|
||||
name:"init-verifiers",description:"Create verifier skill(s) for automated verification of code changes"
|
||||
name:"keybindings",description:"Open or create your keybindings configuration file"
|
||||
name:"logout",description:"Sign out from your Anthropic account"
|
||||
name:"install-github-app",description:"Set up Claude GitHub Actions for a repository"
|
||||
name:"install-slack-app",description:"Install the Claude Slack app"
|
||||
name:"mcp",description:"Manage MCP servers"
|
||||
name:"powerup",description:"Discover Claude Code features through quick interactive lessons"
|
||||
name:"rename",description:"Rename the current conversation"
|
||||
name:"resume",description:"Resume a previous conversation"
|
||||
name:"review",description:"Review a pull request"
|
||||
name:"skills",description:"List available skills"
|
||||
name:"status",description:"Show Claude Code status including version, model, account, API connectivity, and tool statuses"
|
||||
name:"security-review",description:"Complete a security review of the pending changes on the current branch"
|
||||
name:"usage",description:"Show plan usage limits"
|
||||
name:"theme",description:"Change the theme"
|
||||
name:"vim",description:"Toggle between Vim and Normal editing modes"
|
||||
name:"think-back",description:"Your 2025 Claude Code Year in Review"
|
||||
name:"thinkback-play",description:"Play the thinkback animation"
|
||||
name:"plan",description:"Enable plan mode or view the current session plan"
|
||||
name:"privacy-settings",description:"View and update your privacy settings"
|
||||
name:"hooks",description:"View hook configurations for tool events"
|
||||
name:"files",description:"List all files currently in context"
|
||||
name:"agents",description:"Manage agent configurations"
|
||||
name:"reload-plugins",description:"Activate pending plugin changes in the current session"
|
||||
name:"heapdump",description:"Dump the JS heap to ~/Desktop"
|
||||
name:"bridge-kick",description:"Inject bridge failure states for manual recovery testing"
|
||||
name:"version",description:"Print the version this session is running (not what autoupdate downloaded)"
|
||||
name:"chrome",description:"Claude in Chrome (Beta) settings"
|
||||
name:"stickers",description:"Order Claude Code stickers"
|
||||
name:"advisor",description:"Configure the advisor model"
|
||||
name:"export",description:"Export the current conversation to a file or clipboard"
|
||||
name:"tag",description:"Toggle a searchable tag on the current session"
|
||||
name:"remote-env",description:"Configure the default remote environment for teleport sessions"
|
||||
name:"upgrade",description:"Upgrade to Max for higher rate limits and more Opus"
|
||||
name:"rate-limit-options",description:"Show options when rate limit is reached"
|
||||
name:"effort",description:"Set effort level for model usage"
|
||||
name:"stats",description:"Show your Claude Code usage statistics and activity"
|
||||
name:"brief",description:"Toggle brief-only mode"
|
||||
name:"voice",description:"Toggle voice mode"
|
||||
name:"web-setup",description:"Setup Claude Code on the web (requires connecting your GitHub account)"
|
||||
name:"buddy",description:"Hatch a coding companion · pet, off"
|
||||
name:"insights",description:"Generate a report analyzing your Claude Code sessions"
|
||||
name:"alias",description:"Create or list command aliases"
|
||||
name:"definition",description:"Alias definition in the form name=value"
|
||||
name:"nohup",description:"Run a command immune to hangups"
|
||||
name:"command",description:"Command to run with nohup"
|
||||
name:"pyright",description:"Type checker for Python"
|
||||
name:"files",description:"Specify files or directories to analyze (overrides config file)"
|
||||
name:"sleep",description:"Delay for a specified amount of time"
|
||||
name:"duration",description:"Duration to sleep (seconds or with suffix like 5s, 2m, 1h)"
|
||||
name:"srun",description:"Run a command on SLURM cluster nodes"
|
||||
name:"count",description:"Number of tasks to run"
|
||||
name:"count",description:"Number of nodes to allocate"
|
||||
name:"command",description:"Command to run on the cluster"
|
||||
name:"time",description:"Time a command"
|
||||
name:"command",description:"Command to time"
|
||||
name:"timeout",description:"Run a command with a time limit"
|
||||
name:"duration",description:"Duration to wait before timing out (e.g., 10, 5s, 2m)"
|
||||
name:"command",description:"Command to run"
|
||||
name:"batch",description:"Research and plan a large-scale change, then execute it in parallel across 5–30 isolated worktree agents that each open a PR."
|
||||
name:"claude-in-chrome",description:"Automates your Chrome browser to interact with web pages - clicking elements, filling forms, capturing screenshots, reading console logs, and navigating sites. Opens pages in new tabs within your existing Chrome session. Requires site-level permissions before executing (configured in the extension)."
|
||||
name:"debug",description:"Enable debug logging for this session and help diagnose issues"
|
||||
name:"simplify",description:"Review changed code for reuse, quality, and efficiency, then fix any issues found."
|
||||
name:"loop",description:"Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo, defaults to 10m)"
|
||||
name:"schedule",description:"Create, update, list, or run scheduled remote agents (triggers) that execute on a cron schedule."
|
||||
name:"claude-api",description:"Build apps with the Claude API or Anthropic SDK.\nTRIGGER when: code imports `anthropic`/`@anthropic-ai/sdk`/`claude_agent_sdk`, or user asks to use Claude API, Anthropic SDKs, or Agent SDK.\nDO NOT TRIGGER when: code imports `openai`/other AI SDK, general programming, or ML/data-science tasks."
|
||||
name:"install",description:"Install Claude Code native build"
|
||||
|
|
@ -0,0 +1,482 @@
|
|||
return{type:"tool_result",tool_use_id:Y.id,content:A}}catch(O){return{type:"tool_result",tool_use_id:Y.id,content:O instanceof NP6?O.content:`Error: ${O instanceof Error?O.message:String(O)}`,is_error:!0}}}))}}var dI6,yP6,l96,EP,cI6,yE,vl,ke,lI6,nM7,As8,nI6;var ws8=L(()=>{Dl();E_8();FW();NE();xI6();nI6=class nI6{constructor(q,K,_){dI6.add(this),this.client=q,yP6.set(this,!1),l96.set(this,!1),EP.set(this,void 0),cI6.set(this,void 0),yE.set(this,void 0),vl.set(this,void 0),ke.set(this,void 0),lI6.set(this,0),J4(this,EP,{params:{...K,messages:structuredClone(K.messages)}},"f");let Y=["BetaToolRunner",...oa8(K.tools,K.messages)].join(", ");J4(this,cI6,{..._,headers:x3([{"x-stainless-helper":Y},_?.headers])},"f"),J4(this,ke,iM7(),"f")}async*[(yP6=new WeakMap,l96=new WeakMap,EP=new WeakMap,cI6=new WeakMap,yE=new WeakMap,vl=new WeakMap,ke=new WeakMap,lI6=new WeakMap,dI6=new WeakSet,nM7=async function(){let K=x1(this,EP,"f").params.compactionControl;if(!K||!K.enabled)return!1;let _=0;if(x1(this,yE,"f")!==void 0)try{let w=await x1(this,yE,"f");_=w.usage.input_tokens+(w.usage.cache_creation_input_tokens??0)+(w.usage.cache_read_input_tokens??0)+w.usage.output_tokens}catch{return!1}let z=K.contextTokenThreshold??cM7;if(_<z)return!1;let Y=K.model??x1(this,EP,"f").params.model,$=K.summaryPrompt??lM7,O=x1(this,EP,"f").params.messages;if(O[O.length-1].role==="assistant"){let w=O[O.length-1];if(Array.isArray(w.content)){let j=w.content.filter((H)=>H.type!=="tool_use");if(j.length===0)O.pop();else w.content=j}}let A=await this.client.beta.messages.create({model:Y,messages:[...O,{role:"user",content:[{type:"text",text:$}]}],max_tokens:x1(this,EP,"f").params.max_tokens},{headers:{"x-stainless-helper":"compaction"}});if(A.content[0]?.type!=="text")throw new mq("Expected text response for compaction");return x1(this,EP,"f").params.messages=[{role:"user",content:A.content}],!0},Symbol.asyncIterator)](){var q;if(x1(this,yP6,"f"))throw new mq("Cannot iterate over a consumed stream")
|
||||
|
||||
J4(this,yP6,!0,"f"),J4(this,l96,!0,"f"),J4(this,vl,void 0,"f");try{while(!0){let K;try{if(x1(this,EP,"f").params.max_iterations&&x1(this,lI6,"f")>=x1(this,EP,"f").params.max_iterations)break;J4(this,l96,!1,"f"),J4(this,vl,void 0,"f"),J4(this,lI6,(q=x1(this,lI6,"f"),q++,q),"f"),J4(this,yE,void 0,"f");let{max_iterations:_,compactionControl:z,...Y}=x1(this,EP,"f").params;if(Y.stream)K=this.client.beta.messages.stream({...Y},x1(this,cI6,"f")),J4(this,yE,K.finalMessage(),"f"),x1(this,yE,"f").catch(()=>{}),yield K;else J4(this,yE,this.client.beta.messages.create({...Y,stream:!1},x1(this,cI6,"f")),"f"),yield x1(this,yE,"f");if(!await x1(this,dI6,"m",nM7).call(this)){if(!x1(this,l96,"f")){let{role:A,content:w}=await x1(this,yE,"f");x1(this,EP,"f").params.messages.push({role:A,content:w})}let O=await x1(this,dI6,"m",As8).call(this,x1(this,EP,"f").params.messages.at(-1));if(O)x1(this,EP,"f").params.messages.push(O);else if(!x1(this,l96,"f"))break}}finally{if(K)K.abort()}}if(!x1(this,yE,"f"))throw new mq("ToolRunner concluded without a message from the server");x1(this,ke,"f").resolve(await x1(this,yE,"f"))}catch(K){throw J4(this,yP6,!1,"f"),x1(this,ke,"f").promise.catch(()=>{}),x1(this,ke,"f").reject(K),J4(this,ke,iM7(),"f"),K}}setMessagesParams(q){if(typeof q==="function")x1(this,EP,"f").params=q(x1(this,EP,"f").params);else x1(this,EP,"f").params=q;J4(this,l96,!0,"f"),J4(this,vl,void 0,"f")}async generateToolResponse(){let q=await x1(this,yE,"f")??this.params.messages.at(-1);if(!q)return null;return x1(this,dI6,"m",As8).call(this,q)}done(){return x1(this,ke,"f").promise}async runUntilDone(){if(!x1(this,yP6,"f"))for await(let q of this);return this.done()}get params(){return x1(this,EP,"f").params}pushMessages(...q){this.setMessagesParams((K)=>({...K,messages:[...K.messages,...q]}))}then(q,K){return this.runUntilDone().then(q,K)}};As8=async function(K){if(x1(this,vl,"f")!==void 0)return x1(this,vl,"f");return J4(this,vl,JA5(x1(this,EP,"f").params,K),"f"),x1(this,vl,"f")}});var EP6;var js8=L(()=>{FW();Ba8()
|
||||
|
||||
return K.split(`
|
||||
`).filter((_)=>_.startsWith("worktree ")).map((_)=>_.slice(9).normalize("NFC"))}catch{return[]}}var gR5;var wA8=L(()=>{gR5=BR5(pR5)});import{open as Ch7,readdir as zm$,realpath as Ym$,stat as $m$}from"fs/promises";import{join as bh7}from"path";function xh7(q){if(typeof q!=="string")return null;return FR5.test(q)?q:null}function Ih7(q){if(!q.includes("\\"))return q;try{return JSON.parse(`"${q}"`)}catch{return q}}function P66(q,K){let _=[`"${K}":"`,`"${K}": "`];for(let z of _){let Y=q.indexOf(z);if(Y<0)continue;let $=Y+z.length,O=$;while(O<q.length){if(q[O]==="\\"){O+=2;continue}if(q[O]==='"')return Ih7(q.slice($,O));O++}}return}function OT(q,K){let _=[`"${K}":"`,`"${K}": "`],z;for(let Y of _){let $=0;while(!0){let O=q.indexOf(Y,$);if(O<0)break;let A=O+Y.length,w=A;while(w<q.length){if(q[w]==="\\"){w+=2;continue}if(q[w]==='"'){z=Ih7(q.slice(A,w));break}w++}$=w+1}}return z}async function uh7(q,K,_){try{let z=await Ch7(q,"r");try{let Y=await z.read(_,0,X66,0);if(Y.bytesRead===0)return{head:"",tail:""};let $=_.toString("utf8",0,Y.bytesRead),O=Math.max(0,K-X66),A=$;if(O>0){let w=await z.read(_,0,X66,O);A=_.toString("utf8",0,w.bytesRead)}return{head:$,tail:A}}finally{await z.close()}}catch{return{head:"",tail:""}}}function UR5(q){return Math.abs(Q_6(q)).toString(36)}function XX(q){let K=q.replace(/[^a-zA-Z0-9]/g,"-");if(K.length<=_51)return K;let _=typeof Bun<"u"?Bun.hash(q).toString(36):UR5(q);return`${K.slice(0,_51)}-${_}`}function JA8(){return bh7(q7(),"projects")}function mh7(q){return bh7(JA8(),XX(q))}function cR5(){return dR5??=Buffer.from('"compact_boundary"')}function ph7(q){try{let K=JSON.parse(q);if(K.type!=="system"||K.subtype!=="compact_boundary")return null;return{hasPreservedSegment:Boolean(K.compactMetadata?.preservedSegment)}}catch{return null}}function i_6(q,K,_,z){let Y=z-_;if(Y<=0)return;if(q.len+Y>q.buf.length){let $=Buffer.allocUnsafe(Math.min(Math.max(q.buf.length*2,q.len+Y),q.cap))
|
||||
|
||||
CP_=new Set(["chrome_bridge_connection_succeeded","chrome_bridge_connection_failed","chrome_bridge_disconnected","chrome_bridge_tool_call_completed","chrome_bridge_tool_call_error","chrome_bridge_tool_call_started","chrome_bridge_tool_call_timeout","tengu_api_error","tengu_api_success","tengu_brief_mode_enabled","tengu_brief_mode_toggled","tengu_brief_send","tengu_cancel","tengu_compact_failed","tengu_exit","tengu_flicker","tengu_init","tengu_model_fallback_triggered","tengu_oauth_error","tengu_oauth_success","tengu_oauth_token_refresh_failure","tengu_oauth_token_refresh_success","tengu_oauth_token_refresh_lock_acquiring","tengu_oauth_token_refresh_lock_acquired","tengu_oauth_token_refresh_starting","tengu_oauth_token_refresh_completed","tengu_oauth_token_refresh_lock_releasing","tengu_oauth_token_refresh_lock_released","tengu_query_error","tengu_session_file_read","tengu_started","tengu_tool_use_error","tengu_tool_use_granted_in_prompt_permanent","tengu_tool_use_granted_in_prompt_temporary","tengu_tool_use_rejected_in_prompt","tengu_tool_use_success","tengu_uncaught_exception","tengu_unhandled_rejection","tengu_voice_recording_started","tengu_voice_toggled","tengu_team_mem_sync_pull","tengu_team_mem_sync_push","tengu_team_mem_sync_started","tengu_team_mem_entries_capped"]),bP_=["arch","clientType","errorType","http_status_range","http_status","kairosActive","model","platform","provider","skillMode","subscriptionType","toolName","userBucket","userType","version","versionBase"];tl6=[];IP_=$1(async()=>{if(c16())return S08=!1,!1;try{return S08=!0,!0}catch(q){return j6(q),S08=!1,!1}});mP_=$1(()=>{let q=qC(),K=yP_("sha256").update(q).digest("hex");return parseInt(K.slice(0,8),16)%uP_})});function BP_(){if(vv6("datadog"))return!1;if(yE1!==void 0)return yE1;try{return J$(Esq)}catch{return!1}}function Lsq(q,K){let _=qE1(q);if(_===0)return;let z=_!==null?{...K,sample_rate:_}:K;if(BP_())ysq(q,q_8(z))
|
||||
|
||||
if(!_)return null;let{gapMinutes:z,config:Y}=_,$=wi_(q),O=Math.max(1,Y.keepRecent),A=new Set($.slice(-O)),w=new Set($.filter((J)=>!A.has(J)));if(w.size===0)return null;let j=0,H=q.map((J)=>{if(J.type!=="user"||!Array.isArray(J.message.content))return J;let M=!1,X=J.message.content.map((P)=>{if(P.type==="tool_result"&&w.has(P.tool_use_id)&&P.content!==jM4)return j+=WM4(P),M=!0,{...P,content:jM4};return P});if(!M)return J;return{...J,message:{...J.message,content:X}}});if(j===0)return null;return d("tengu_time_based_microcompact",{gapMinutes:Math.round(z),gapThresholdMinutes:Y.gapThresholdMinutes,toolsCleared:w.size,toolsKept:A.size,keepRecent:Y.keepRecent,tokensSaved:j}),N(`[TIME-BASED MC] gap ${Math.round(z)}min > ${Y.gapThresholdMinutes}min, cleared ${w.size} tool results (~${j} tokens), kept last ${A.size}`),TV6(),_o(),{messages:H}}var jM4="[Old tool result content cleared]",JM4=2000,Ai_,HM4=null,kV6=null,lu1=null;var aC=L(()=>{ZY();Y2();bX();PV6();_8();dq();Vq6();r8();k8();yq6();UN();QN8();wM4();Ai_=new Set([pq,...Mw6,$9,Z_,gL,mj,N4,xK])});function DM4(q){let K=Buffer.from(q,"base64"),_="";for(let z of K)_+=String.fromCharCode(z^Mi_);return _.split(",")}function fi_(){let q=process.env.ANTHROPIC_BASE_URL;if(!q)return null;try{return new URL(q).hostname.toLowerCase()}catch{return null}}function Zi_(){if(OM())return null;let q=fi_(),K=Hu6(),_=K==="Asia/Shanghai"||K==="Asia/Urumqi";if(!q)return{known:!1,labKw:!1,cnTZ:_,host:null};return{known:Wi_().some((z)=>q===z||q.endsWith("."+z)),labKw:Di_().some((z)=>q.includes(z)),cnTZ:_,host:q}}function Gi_(q,K){if(!q&&!K)return"'";if(q&&!K)return"’";if(!q&&K)return"ʼ";return"ʹ"}function fM4(q){let K=Zi_(),_=Gi_(K?.known??!1,K?.labKw??!1),z=K?.cnTZ?q.replace(/-/g,"/"):q
|
||||
|
||||
$.set(w,{count:j.count+1,totalTokens:j.totalTokens+O})}}}break}case"image":case"server_tool_use":case"web_search_tool_result":case"search_result":case"document":case"thinking":case"redacted_thinking":case"code_execution_tool_result":case"mcp_tool_use":case"mcp_tool_result":case"container_upload":case"web_fetch_tool_result":case"bash_code_execution_tool_result":case"text_editor_code_execution_tool_result":case"tool_search_tool_result":case"compaction":_.other+=O;break}}function _P4(q,K,_){q.set(K,(q.get(K)||0)+_)}function YP4(q){let K={total_tokens:q.total,human_message_tokens:q.humanMessages,assistant_message_tokens:q.assistantMessages,local_command_output_tokens:q.localCommandOutputs,other_tokens:q.other};q.attachments.forEach((z,Y)=>{K[`attachment_${Y}_count`]=z}),q.toolRequests.forEach((z,Y)=>{K[`tool_request_${Y}_tokens`]=z}),q.toolResults.forEach((z,Y)=>{K[`tool_result_${Y}_tokens`]=z});let _=[...q.duplicateFileReads.values()].reduce((z,Y)=>z+Y.tokens,0);if(K.duplicate_read_tokens=_,K.duplicate_read_file_count=q.duplicateFileReads.size,q.total>0){K.human_message_percent=Math.round(q.humanMessages/q.total*100),K.assistant_message_percent=Math.round(q.assistantMessages/q.total*100),K.local_command_output_percent=Math.round(q.localCommandOutputs/q.total*100),K.duplicate_read_percent=Math.round(_/q.total*100);let z=[...q.toolRequests.values()].reduce(($,O)=>$+O,0),Y=[...q.toolResults.values()].reduce(($,O)=>$+O,0);K.tool_request_percent=Math.round(z/q.total*100),K.tool_result_percent=Math.round(Y/q.total*100),q.toolRequests.forEach(($,O)=>{K[`tool_request_${O}_percent`]=Math.round($/q.total*100)}),q.toolResults.forEach(($,O)=>{K[`tool_result_${O}_percent`]=Math.round($/q.total*100)})}return K}var $P4=L(()=>{UN();a1();r8()});function km1(q){if(aZ6())return fOq(q);return q}function bV6(q){return q||aZ6()}function OP4(q){return aZ6()&&q.status===429}var io6=L(()=>{ov();pX1()});function xq6(q){if(!q||typeof q!=="object")return null;let K=q,_=5,z=0
|
||||
|
||||
if(K[47]!==$||K[48]!==V||K[49]!==W||K[50]!==k||K[51]!==z||K[52]!==_||K[53]!==H||K[54]!==X||K[55]!==O||K[56]!==w)R=_.message.content.map((p,C)=>j9.createElement(wlz,{key:C,message:_,addMargin:$,tools:O,progressMessagesForMessage:H,param:p,style:X,verbose:w,imageIndex:V[C],isUserContinuation:k,lookups:z,isTranscriptMode:W})),K[47]=$,K[48]=V,K[49]=W,K[50]=k,K[51]=z,K[52]=_,K[53]=H,K[54]=X,K[55]=O,K[56]=w,K[57]=R;else R=K[57];let b;if(K[58]!==E||K[59]!==R)b=j9.createElement(u,{flexDirection:"column",width:E},R),K[58]=E,K[59]=R,K[60]=b;else b=K[60];let I=b,m;if(K[61]!==I||K[62]!==y)m=y?j9.createElement(TS4,null,I):I,K[61]=I,K[62]=y,K[63]=m;else m=K[63];return m}case"system":{if(_.subtype==="compact_boundary"){if(E4())return null;let y;if(K[64]===Symbol.for("react.memo_cache_sentinel"))y=j9.createElement(s3K,null),K[64]=y;else y=K[64];return y}if(_.subtype==="microcompact_boundary")return null;if(_.subtype==="local_command"){let y;if(K[68]!==_.content)y={type:"text",text:_.content},K[68]=_.content,K[69]=y;else y=K[69];let E;if(K[70]!==$||K[71]!==W||K[72]!==y||K[73]!==w)E=j9.createElement(rj6,{addMargin:$,param:y,verbose:w,isTranscriptMode:W}),K[70]=$,K[71]=W,K[72]=y,K[73]=w,K[74]=E;else E=K[74];return E}let V;if(K[75]!==$||K[76]!==W||K[77]!==_||K[78]!==w)V=j9.createElement(A9K,{message:_,addMargin:$,verbose:w,isTranscriptMode:W}),K[75]=$,K[76]=W,K[77]=_,K[78]=w,K[79]=V;else V=K[79];return V}case"grouped_tool_use":{let V;if(K[80]!==j||K[81]!==z||K[82]!==_||K[83]!==J||K[84]!==O)V=j9.createElement(e3K,{message:_,tools:O,lookups:z,inProgressToolUseIDs:j,shouldAnimate:J}),K[80]=j,K[81]=z,K[82]=_,K[83]=J,K[84]=O,K[85]=V;else V=K[85];return V}case"collapsed_read_search":{let V=w||W,y;if(K[86]!==j||K[87]!==f||K[88]!==z||K[89]!==_||K[90]!==J||K[91]!==V||K[92]!==O)y=j9.createElement(A0,null,j9.createElement(o3K,{message:_,inProgressToolUseIDs:j,shouldAnimate:J,verbose:V,tools:O,lookups:z,isActiveGroup:f})),K[86]=j,K[87]=f,K[88]=z,K[89]=_,K[90]=J,K[91]=V,K[92]=O,K[93]=y;else y=K[93]
|
||||
|
||||
try{return await Rh4([K],Y)}catch($){return j6($),null}}function F_Y(q){let K=0;for(let _ of q){if(_.type!=="assistant")continue;let z=_.message?.content;if(!Array.isArray(z))continue;for(let Y of z){if(Y.type!=="tool_use"||!g_Y.has(Y.name))continue;if(u17(Y.name,Y.input))K++}}return K}async function U_Y(){try{let q=kY(),K=(await u_Y(q)).size,z=(await Bh7(q,K)).postBoundaryBuf,Y=zn(z),$=Y.findLastIndex((A)=>A.type==="system"&&("subtype"in A)&&A.subtype==="compact_boundary"),O=$>=0?Y.slice($+1):Y;return{promptCount:p_Y(O),memoryAccessCount:F_Y(O)}}catch{return{promptCount:0,memoryAccessCount:0}}}async function OfK(q){if(JP6()==="remote"){let X=process.env.CLAUDE_CODE_REMOTE_SESSION_ID;if(X){let P=process.env.SESSION_INGRESS_URL;if(!cL8(X,P))return VM(X,P)}return""}let K=v7();if(K.attribution?.pr)return K.attribution.pr;if(K.includeCoAuthoredBy===!1)return"";let _=`\uD83E\uDD16 Generated with [Claude Code](${_26})`,z=q();if(N(`PR Attribution: appState.attribution exists: ${!!z.attribution}`),z.attribution){let X=z.attribution.fileStates,W=X instanceof Map?X.size:Object.keys(X).length;N(`PR Attribution: fileStates count: ${W}`)}let[Y,{promptCount:$,memoryAccessCount:O},A]=await Promise.all([B_Y(z),U_Y(),Lh4()]),w=Y?.summary.claudePercent??0;N(`PR Attribution: claudePercent: ${w}, promptCount: ${$}, memoryAccessCount: ${O}`);let j=cY(D5()),H=A?j:hh4(j);if(w===0&&$===0&&O===0)return N("PR Attribution: returning default (no data)"),_;let J=O>0?`, ${O} ${O===1?"memory":"memories"} recalled`:"",M=`\uD83E\uDD16 Generated with [Claude Code](${_26}) (${w}% ${$}-shotted by ${H}${J})`;return N(`PR Attribution: returning summary: ${M}`),M}var g_Y;var Mg8=L(()=>{T8();O$();ZY();Y2();bX();No();_8();mA();h8();dq();m17();t4();W66();i1();dH6();g_Y=new Set([pq,$9,Z_,N4,xK])});function Xg8(){return Ch6()}function Pg8(){return sm8()}function d_Y(){if(c6(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS))return null
|
||||
|
||||
let _=[];_.push("=".repeat(80)),_.push(`QUERY PROFILING REPORT - Query #${sfK}`),_.push("=".repeat(80)),_.push("");let z=K[0]?.startTime??0,Y=z,$=0,O=0;for(let j of K){let H=j.startTime-z,J=j.startTime-Y;if(_.push(Kz8(H,J,j.name,j77.get(j.name),10,9,lzY(J,j.name))),j.name==="query_api_request_sent")$=H;if(j.name==="query_first_chunk_received")O=H;Y=j.startTime}let A=K[K.length-1],w=A?A.startTime-z:0;if(_.push(""),_.push("-".repeat(80)),O>0){let j=$,H=O-$,J=(j/O*100).toFixed(1),M=(H/O*100).toFixed(1);_.push(`Total TTFT: ${YI(O)}ms`),_.push(` - Pre-request overhead: ${YI(j)}ms (${J}%)`),_.push(` - Network latency: ${YI(H)}ms (${M}%)`)}else _.push(`Total time: ${YI(w)}ms`);return _.push(izY(K,z)),_.push("=".repeat(80)),_.join(`
|
||||
`)}function izY(q,K){let _=[{name:"Context loading",start:"query_context_loading_start",end:"query_context_loading_end"},{name:"Microcompact",start:"query_microcompact_start",end:"query_microcompact_end"},{name:"Autocompact",start:"query_autocompact_start",end:"query_autocompact_end"},{name:"Query setup",start:"query_setup_start",end:"query_setup_end"},{name:"Tool schemas",start:"query_tool_schema_build_start",end:"query_tool_schema_build_end"},{name:"Message normalization",start:"query_message_normalization_start",end:"query_message_normalization_end"},{name:"Client creation",start:"query_client_creation_start",end:"query_client_creation_end"},{name:"Network TTFB",start:"query_api_request_sent",end:"query_first_chunk_received"},{name:"Tool execution",start:"query_tool_execution_start",end:"query_tool_execution_end"}],z=new Map(q.map((O)=>[O.name,O.startTime-K])),Y=[];Y.push(""),Y.push("PHASE BREAKDOWN:");for(let O of _){let A=z.get(O.start),w=z.get(O.end);if(A!==void 0&&w!==void 0){let j=w-A,H="█".repeat(Math.min(Math.ceil(j/10),50));Y.push(` ${O.name.padEnd(22)} ${YI(j).padStart(10)}ms ${H}`)}}let $=z.get("query_api_request_sent");if($!==void 0)Y.push(""),Y.push(` ${"Total pre-API overhead".padEnd(22)} ${YI($).padStart(10)}ms`);return Y.join(`
|
||||
`)}function Eg8(){if(!b78)return
|
||||
|
||||
let F=[...e2(k)],U=V,c=A.startsWith("agent:")||A.startsWith("repl_main_thread");F=await Wb4(F,v.contentReplacementState,c?(T6)=>void aH6(T6,v.agentId).catch(j6):void 0,new Set(v.options.tools.filter((T6)=>!Number.isFinite(T6.maxResultSizeChars)).map((T6)=>T6.name)));let K6=0;g3("query_microcompact_start"),F=(await H.microcompact(F,v,A)).messages;let q6=void 0;g3("query_microcompact_end");let t=tK(IZK(_,Y));g3("query_autocompact_start");let{compactionResult:n,consecutiveFailures:z6,consecutiveRapidRefills:M6,rapidRefillBreakerTripped:J6}=await H.autocompact(F,v,{systemPrompt:_,userContext:z,systemContext:Y,toolUseContext:v,forkContextMessages:F},A,U,K6);if(g3("query_autocompact_end"),J6)return d("tengu_auto_compact_rapid_refill_breaker",{consecutiveRapidRefills:U?.consecutiveRapidRefills??0,turnsSincePreviousCompact:U?.turnCounter??-1,queryChainId:g,queryDepth:C.depth}),yield U9({content:SZK,error:"invalid_request"}),{reason:"rapid_refill_breaker"};if(n){let{preCompactTokenCount:T6,postCompactTokenCount:s,truePostCompactTokenCount:$6,compactionUsage:h6}=n;if(d("tengu_auto_compact_succeeded",{originalMessageCount:k.length,compactedMessageCount:n.summaryMessages.length+n.attachments.length+n.hookResults.length,preCompactTokenCount:T6,postCompactTokenCount:s,truePostCompactTokenCount:$6,compactionInputTokens:h6?.input_tokens,compactionOutputTokens:h6?.output_tokens,compactionCacheReadTokens:h6?.cache_read_input_tokens??0,compactionCacheCreationTokens:h6?.cache_creation_input_tokens??0,compactionTotalTokens:h6?h6.input_tokens+(h6.cache_creation_input_tokens??0)+(h6.cache_read_input_tokens??0)+h6.output_tokens:0,queryChainId:g,queryDepth:C.depth}),q.taskBudget){let V6=qy8(F);X=Math.max(0,(X??q.taskBudget.total)-V6)}U={compacted:!0,turnId:H.uuid(),turnCounter:0,consecutiveFailures:0,consecutiveRapidRefills:M6};let P6=xa(n);for(let V6 of P6)yield V6;F=P6}else if(z6!==void 0)U={...U??{compacted:!1,turnId:"",turnCounter:0},consecutiveFailures:z6};v={...v,messages:F,turnStartIndex:LYY(F)};let G6=[],H6=[],e=[],a=!1
|
||||
|
||||
if(q&&q.trim()!=="")K+=`
|
||||
|
||||
Additional Instructions:
|
||||
${q}`;return K+=oZK,K}function gYY(q){let K=q;K=K.replace(/<analysis>[\s\S]*?<\/analysis>/,"");let _=K.match(/<summary>([\s\S]*?)<\/summary>/);if(_){let z=_[1]||"";K=K.replace(/<summary>[\s\S]*?<\/summary>/,`Summary:
|
||||
${z.trim()}`)}return K=K.replace(/\n\n+/g,`
|
||||
|
||||
`),K.trim()}function B78(q,K,_,z,Y){let O=`This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.
|
||||
|
||||
${gYY(q)}`;if(_)O+=`
|
||||
|
||||
If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: ${_}`;if(z)O+=`
|
||||
|
||||
Recent messages are preserved verbatim.`;if(K)return`${O}
|
||||
Continue the conversation from where it left off without asking the user any further questions. Resume directly — do not acknowledge the summary, do not recap what was happening, do not preface with "I'll continue" or similar. Pick up the last task as if the break never happened.`;return O}var BYY,oZK
|
||||
|
||||
let M=L8("tengu_compact_cache_prefix",!0),X=sZK(Y),P=n8({content:X}),W=q,D=_,f,G,Z=0;for(;;){if(f=await O0K({messages:W,summaryRequest:P,appState:j,context:K,preCompactTokenCount:w,cacheSafeParams:D,stripNonEssential:A}),G=KS6(f),!G?.startsWith(Dp))break;Z++;let n=Z<=K0K?_0K(W,f):null;if(!n)throw d("tengu_compact_failed",{reason:"prompt_too_long",preCompactTokenCount:w,promptCacheSharingEnabled:M,ptlAttempts:Z}),Error(z0K);d("tengu_compact_ptl_retry",{attempt:Z,droppedMessages:W.length-n.length,remainingMessages:n.length}),W=n,D={...D,forkContextMessages:n}}if(!G)throw N(`Compact failed: no summary text in response. Response: ${g6(f)}`,{level:"error"}),d("tengu_compact_failed",{reason:"no_summary",preCompactTokenCount:w,promptCacheSharingEnabled:M}),Error("Failed to generate conversation summary - response did not contain valid text content");else if(Ba(G))throw d("tengu_compact_failed",{reason:"api_error",preCompactTokenCount:w,promptCacheSharingEnabled:M}),Error(G);let v=Am1(K.readFileState);K.readFileState.clear(),K.loadedNestedMemoryPaths?.clear(),lo6(K.memorySelector);let[k,V]=await Promise.all([A0K(v,K,q0K),H0K(K)]),y=[...k,...V],E=dg8(K.agentId);if(E)y.push(E);let R=await j0K(K);if(R)y.push(R);let b=w0K(K.agentId);if(b)y.push(b);for(let n of cg8(K.options.tools,K.options.mainLoopModel,[],{callSite:"compact_full"}))y.push(P4(n));for(let n of lg8(K,[]))y.push(P4(n));for(let n of ng8(K.options.mcpClients,K.options.tools,K.options.mainLoopModel,[]))y.push(P4(n));K.onCompactProgress?.({type:"hooks_start",hookType:"session_start"});let I=await Kf("compact",{model:K.options.mainLoopModel}),m=F78($?"auto":"manual",w??0,q.at(-1)?.uuid),p=Rd(q);if(p.size>0)m.compactMetadata.preCompactDiscoveredTools=[...p].sort();let C=kY(),F=[n8({content:B78(G,z,C,void 0,!1),isCompactSummary:!0,isVisibleInTranscriptOnly:!0})],U=cN([f]),c=LV6([m,...F,...y,...I]),K6=tC(f),o=O?.querySource??K.options.querySource??"unknown"
|
||||
|
||||
d("tengu_compact",{preCompactTokenCount:w,stripNonEssential:A,postCompactTokenCount:U,truePostCompactTokenCount:c,autoCompactThreshold:O?.autoCompactThreshold??-1,willRetriggerNextTurn:O!==void 0&&c>=O.autoCompactThreshold,isAutoCompact:$,querySource:o,queryChainId:K.queryTracking?.chainId??"",queryDepth:K.queryTracking?.depth??-1,isRecompactionInChain:O?.isRecompactionInChain??!1,turnsSincePreviousCompact:O?.turnsSincePreviousCompact??-1,previousCompactTurnId:O?.previousCompactTurnId??"",compactionInputTokens:K6?.input_tokens,compactionOutputTokens:K6?.output_tokens,compactionCacheReadTokens:K6?.cache_read_input_tokens??0,compactionCacheCreationTokens:K6?.cache_creation_input_tokens??0,compactionTotalTokens:K6?K6.input_tokens+(K6.cache_creation_input_tokens??0)+(K6.cache_read_input_tokens??0)+K6.output_tokens:0,promptCacheSharingEnabled:M,...(()=>{try{return YP4(zP4(q))}catch(n){return j6(n),{}}})()}),Je(),ig8(),K.onCompactProgress?.({type:"hooks_start",hookType:"post_compact"});let q6=await rg8({trigger:$?"auto":"manual",compactSummary:G},K.abortController.signal),t=[J,q6.userDisplayMessage].filter(Boolean).join(`
|
||||
`);return{boundaryMarker:m,summaryMessages:F,attachments:y,hookResults:I,userDisplayMessage:t||void 0,preCompactTokenCount:w,postCompactTokenCount:U,truePostCompactTokenCount:c,compactionUsage:K6}}catch(w){if(!$)$0K(w,K);throw w}finally{K.setStreamMode?.("requesting"),K.setResponseLength?.(()=>0),K.onCompactProgress?.({type:"compact_end"}),K.setSDKStatus?.(null)}}async function Y0K(q,K,_,z,Y,$="from"){try{let O=$==="up_to"?q.slice(0,K):q.slice(K),A=$==="up_to"?q.slice(K).filter((q6)=>q6.type!=="progress"&&!pJ(q6)&&!(q6.type==="user"&&q6.isCompactSummary)):q.slice(0,K).filter((q6)=>q6.type!=="progress");if(O.length===0)throw Error($==="up_to"?"Nothing to summarize before the selected message.":"Nothing to summarize after the selected message.");let w=SZ(q);_.onCompactProgress?.({type:"hooks_start",hookType:"pre_compact"}),_.setSDKStatus?.("compacting")
|
||||
|
||||
let j=await _S6({trigger:"manual",customInstructions:null},_.abortController.signal),H;if(j.newCustomInstructions&&Y)H=`${j.newCustomInstructions}
|
||||
|
||||
User context: ${Y}`;else if(j.newCustomInstructions)H=j.newCustomInstructions;else if(Y)H=`User context: ${Y}`;_.setStreamMode?.("requesting"),_.setResponseLength?.(()=>0),_.onCompactProgress?.({type:"compact_start"});let J=aZK(H,$),M=n8({content:J}),X={preCompactTokenCount:w,direction:$,messagesSummarized:O.length},P=$==="up_to"?O:q,W=$==="up_to"?{...z,forkContextMessages:O}:z,D,f,G=0;for(;;){if(D=await O0K({messages:P,summaryRequest:M,appState:_.getAppState(),context:_,preCompactTokenCount:w,cacheSafeParams:W}),f=KS6(D),!f?.startsWith(Dp))break;G++;let q6=G<=K0K?_0K(P,D):null;if(!q6)throw d("tengu_partial_compact_failed",{reason:"prompt_too_long",...X,ptlAttempts:G}),Error(z0K);d("tengu_compact_ptl_retry",{attempt:G,droppedMessages:P.length-q6.length,remainingMessages:q6.length,path:"partial"}),P=q6,W={...W,forkContextMessages:q6}}if(!f)throw d("tengu_partial_compact_failed",{reason:"no_summary",...X}),Error("Failed to generate conversation summary - response did not contain valid text content");else if(Ba(f))throw d("tengu_partial_compact_failed",{reason:"api_error",...X}),Error(f);let Z=Am1(_.readFileState);_.readFileState.clear(),_.loadedNestedMemoryPaths?.clear(),lo6(_.memorySelector);let[v,k]=await Promise.all([A0K(Z,_,q0K,A),H0K(_)]),V=[...v,...k],y=dg8(_.agentId);if(y)V.push(y);let E=await j0K(_);if(E)V.push(E);let R=w0K(_.agentId);if(R)V.push(R);for(let q6 of cg8(_.options.tools,_.options.mainLoopModel,A,{callSite:"compact_partial"}))V.push(P4(q6));for(let q6 of lg8(_,A))V.push(P4(q6));for(let q6 of ng8(_.options.mcpClients,_.options.tools,_.options.mainLoopModel,A))V.push(P4(q6));_.onCompactProgress?.({type:"hooks_start",hookType:"session_start"});let b=await Kf("compact",{model:_.options.mainLoopModel}),I=cN([D]),m=tC(D)
|
||||
|
||||
d("tengu_partial_compact",{preCompactTokenCount:w,postCompactTokenCount:I,messagesKept:A.length,messagesSummarized:O.length,direction:$,hasUserFeedback:!!Y,trigger:"message_selector",compactionInputTokens:m?.input_tokens,compactionOutputTokens:m?.output_tokens,compactionCacheReadTokens:m?.cache_read_input_tokens??0,compactionCacheCreationTokens:m?.cache_creation_input_tokens??0});let p=$==="up_to"?q.slice(0,K).findLast((q6)=>q6.type!=="progress")?.uuid:A.at(-1)?.uuid,C=F78("manual",w??0,p,Y,O.length),g=Rd(q);if(g.size>0)C.compactMetadata.preCompactDiscoveredTools=[...g].sort();let F=kY(),c=[n8({content:B78(f,!1,F,void 0,!1),isCompactSummary:!0,...A.length>0?{summarizeMetadata:{messagesSummarized:O.length,userContext:Y,direction:$}}:{isVisibleInTranscriptOnly:!0}})];Je(),ig8(),_.onCompactProgress?.({type:"hooks_start",hookType:"post_compact"});let K6=await rg8({trigger:"manual",compactSummary:f},_.abortController.signal),o=$==="up_to"?c.at(-1)?.uuid??C.uuid:C.uuid;return{boundaryMarker:b77(C,o,A),summaryMessages:c,messagesToKeep:A,attachments:V,hookResults:b,userDisplayMessage:K6.userDisplayMessage,preCompactTokenCount:w,postCompactTokenCount:I,compactionUsage:m}}catch(O){throw $0K(O,_),O}finally{_.setStreamMode?.("requesting"),_.setResponseLength?.(()=>0),_.onCompactProgress?.({type:"compact_end"}),_.setSDKStatus?.(null)}}function $0K(q,K){if(!Ee(q,ba)&&!Ee(q,qS6))K.addNotification?.({key:"error-compacting-conversation",text:"Error compacting conversation",priority:"immediate",color:"error"})}function rYY(){return async()=>({behavior:"deny",message:"Tool use is not allowed during compaction",decisionReason:{type:"other",reason:"compaction agent should only produce text summary"}})}async function O0K({messages:q,summaryRequest:K,appState:_,context:z,preCompactTokenCount:Y,cacheSafeParams:$,stripNonEssential:O=!1}){let A=!O&&L8("tengu_compact_cache_prefix",!0),w=pfK()?setInterval((j)=>{mfK(),j?.("compacting")},30000,z.setSDKStatus):void 0
|
||||
|
||||
return P4({type:"plan_mode",reminderType:"full",isSubAgent:!!q.agentId,planFilePath:_,planExists:z})}async function H0K(q){let K=q.getAppState();return Object.values(K.tasks).filter((z)=>z.type==="local_agent").flatMap((z)=>{if(z.retrieved||z.status==="pending"||z.agentId===q.agentId)return[];return[P4({type:"task_status",taskId:z.agentId,taskType:"local_agent",description:z.description,status:z.status,deltaSummary:z.status==="running"?z.progress?.summary??null:z.error??null,outputFilePath:aY(z.agentId)})]})}function oYY(q){let K=new Set;for(let z of q){if(z.type!=="user"||!Array.isArray(z.message.content))continue;for(let Y of z.message.content)if(Y.type==="tool_result"&&typeof Y.content==="string"&&l08(Y.content))K.add(Y.tool_use_id)}let _=new Set;for(let z of q){if(z.type!=="assistant"||!Array.isArray(z.message.content))continue;for(let Y of z.message.content){if(Y.type!=="tool_use"||Y.name!==pq||K.has(Y.id))continue;let $=Y.input;if($&&typeof $==="object"&&"file_path"in $&&typeof $.file_path==="string")_.add(Rq($.file_path))}}return _}function aYY(q,K){if(L3(q)<=K)return q;let _=K*4-eZK.length;return q.slice(0,_)+eZK}function sYY(q,K){let _=Rq(q);try{let z=Rq(PW(K));if(_===z)return!0}catch{}try{if(new Set(cZK.map((Y)=>Rq(CO6(Y)))).has(_))return!0}catch{}return!1}var q0K=5,FYY=50000,UYY=5000,QYY=5000,dYY=25000,cYY=2,qS6="Not enough messages to compact.",K0K=3,tZK="[earlier conversation truncated for compaction retry]",z0K="Conversation too long. Press esc twice to go up a few messages and try again.",ba="API Error: Request was aborted.",eR6="Compaction interrupted · This may be due to network issues — please try again.",eZK=`
|
||||
|
||||
[... skill content truncated for compaction; use Read on the skill path if you need the full text]`;var Ia=L(()=>{Xm();ov();T8();T8();hd();ZY();lP();$y8();qP();k1();jD();$P4();_8();E8();jk();qv();B$();h8();lZK();a1();i_();lH();nR6();sK6();t4();r8();Fj();CZ();eC();l1();k8();d2();Kb();yq6();$o();S77();UN();C77()});function pp(q){let K=q===void 0||q.startsWith("repl_main_thread")||q==="sdk"
|
||||
|
||||
function P0K(){return`IMPORTANT: This message and these instructions are NOT part of the actual user conversation. Do NOT include any references to "note-taking", "session notes extraction", or these update instructions in the notes content.
|
||||
|
||||
Based on the user conversation above (EXCLUDING this note-taking instruction message as well as system prompt, claude.md entries, or any past session summaries), update the session notes file.
|
||||
|
||||
The file {{notesPath}} has already been read for you. Here are its current contents:
|
||||
<current_notes_content>
|
||||
{{currentNotes}}
|
||||
</current_notes_content>
|
||||
|
||||
Your ONLY task is to use the Edit tool to update the notes file, then stop. You can make multiple edits (update every section as needed) - make all Edit tool calls in parallel in a single message. Do not call any other tools.
|
||||
|
||||
CRITICAL RULES FOR EDITING:
|
||||
- The file must maintain its exact structure with all sections, headers, and italic descriptions intact
|
||||
-- NEVER modify, delete, or add section headers (the lines starting with '#' like # Task specification)
|
||||
-- NEVER modify or delete the italic _section description_ lines (these are the lines in italics immediately following each header - they start and end with underscores)
|
||||
-- The italic _section descriptions_ are TEMPLATE INSTRUCTIONS that must be preserved exactly as-is - they guide what content belongs in each section
|
||||
-- ONLY update the actual content that appears BELOW the italic _section descriptions_ within each existing section
|
||||
-- Do NOT add any new sections, summaries, or information outside the existing structure
|
||||
- Do NOT reference this note-taking process or instructions anywhere in the notes
|
||||
- It's OK to skip updating a section if there are no substantial new insights to add. Do not add filler content like "No info yet", just leave sections blank/unedited if appropriate.
|
||||
- Write DETAILED, INFO-DENSE content for each section - include specifics like file paths, function names, error messages, exact commands, technical details, etc.
|
||||
- For "Key results", include the complete, exact output the user requested (e.g., full table, full answer, etc.)
|
||||
- Do not include information that's already in the CLAUDE.md files included in the context
|
||||
- Keep each section under ~${og8} tokens/words - if a section is approaching this limit, condense it by cycling out less important details while preserving the most critical information
|
||||
- Focus on actionable, specific information that would help someone understand or recreate the work discussed in the conversation
|
||||
- IMPORTANT: Always update "Current State" to reflect the most recent work - this is critical for continuity after compaction
|
||||
|
||||
Use the Edit tool with file_path: {{notesPath}}
|
||||
|
||||
STRUCTURE PRESERVATION REMINDER:
|
||||
Each section has TWO parts that must be preserved exactly as they appear in the current file:
|
||||
1. The section header (line starting with #)
|
||||
2. The italic description line (the _italicized text_ immediately after the header - this is a template instruction)
|
||||
|
||||
You ONLY update the actual content that comes AFTER these two preserved lines. The italic description lines starting and ending with underscores are part of the template structure, NOT content to be edited or removed.
|
||||
|
||||
REMEMBER: Use the Edit tool in parallel and stop. Do not continue after the edits. Only include insights from the actual user conversation, never from these note-taking instructions. Do not delete or change section headers or italic _section descriptions_.`}async function m77(){let q=f0K(q7(),"session-memory","config","template.md")
|
||||
|
||||
M+=`
|
||||
|
||||
Some session memory sections were truncated for length. The full session memory can be viewed at: ${f}`}let X=[n8({content:M,isCompactSummary:!0,isVisibleInTranscriptOnly:!0})],P=dg8($),W=P?[P]:[],D=Vo6(X);return{boundaryMarker:b77(w,X.at(-1).uuid,_),summaryMessages:X,attachments:W,hookResults:z,messagesToKeep:_,preCompactTokenCount:A,postCompactTokenCount:D,truePostCompactTokenCount:D}}async function tg8(q,K,_,z){if(!sg8())return null;await $$Y(),await VX4();let Y=vX4(),$=await _y8();if(!$)return d("tengu_sm_compact_no_session_memory",{}),null;if(await Z0K($))return d("tengu_sm_compact_empty_template",{}),null;try{let O;if(Y){if(O=q.findIndex((P)=>P.uuid===Y),O===-1)return d("tengu_sm_compact_summarized_id_not_found",{}),null}else O=q.length-1,d("tengu_sm_compact_resumed_session",{});let A=w$Y(q,O),w=q.slice(A).filter((P)=>!pJ(P)),j=await Kf("compact",{model:D5()}),H=kY(),J=j$Y(q,$,w,j,H,K,z),M=xa(J),X=Vo6(M);if(_!==void 0&&X>=_)return d("tengu_sm_compact_threshold_exceeded",{postCompactTokenCount:X,autoCompactThreshold:_}),null;return{...J,postCompactTokenCount:X,truePostCompactTokenCount:X}}catch(O){return d("tengu_sm_compact_error",{}),null}}var ag8,g77,T0K=!1;var eg8=L(()=>{_8();d8();E8();a1();dq();Nz();sK6();t4();CZ();eC();l1();k8();p77();SV6();Ia();aC();C77();ag8={minTokens:1e4,minTextBlockMessages:5,maxTokens:40000},g77={...ag8}});function y0K(q){let K=q.trim().toLowerCase(),_;if(K.endsWith("m"))_=parseFloat(K)*1e6;else if(K.endsWith("k"))_=parseFloat(K)*1000;else{let z=parseInt(K,10);_=z>=100&&z<=1000?z*1000:z}if(!Number.isFinite(_)||_<F77||_>N0K)return;return Math.round(_)}function I56(q,K){let _=QT(q,gW());if(process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW){let z=pU("CLAUDE_CODE_AUTO_COMPACT_WINDOW",process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW,F77,N0K);if(z.status!=="invalid"){let Y=Math.max(F77,z.effective);return{window:Math.min(_,Y),configured:Y,source:"env"}}}if(K!==void 0)return{window:Math.min(_,K),configured:K,source:"settings"}
|
||||
|
||||
return{window:_,configured:_,source:"model"}}function Sd(q,K){let _=Math.min(U78(q),H$Y),z=f0()?K:void 0,{window:Y}=I56(q,z);return Y-_}function P$Y(){return Date.now()-DR()>=X$Y}function a68(q,K){let _=Sd(q,K),z=_-Q77,Y=process.env.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE;if(Y){let $=parseFloat(Y);if(!isNaN($)&&$>0&&$<=100){let O=Math.floor(_*($/100));return Math.min(O,z)}}return z}function oH6(q,K,_){let z=f0(),Y=z?_:void 0,$=a68(K,Y),O=z?$:Sd(K,Y),A=Math.max(0,Math.round((O-q)/O*100)),w=O-J$Y,j=O-M$Y,H=q>=w,J=q>=j,M=z&&q>=$,P=Sd(K,Y)-d77,W=process.env.CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE,D=W?parseInt(W,10):NaN,f=!isNaN(D)&&D>0?D:P,G=q>=f;return{percentLeft:A,isAboveWarningThreshold:H,isAboveErrorThreshold:J,isAboveAutoCompactThreshold:M,isAtBlockingLimit:G}}function f0(){if(c6(process.env.DISABLE_COMPACT))return!1;if(c6(process.env.DISABLE_AUTO_COMPACT))return!1;return w8().autoCompactEnabled}async function W$Y(q,K,_,z,Y=0){if(z==="session_memory"||z==="compact")return!1;if(!f0())return!1;let $=SZ(q)-Y,O=a68(K,_),A=Sd(K,_);N(`autocompact: tokens=${$} threshold=${O} effectiveWindow=${A}${Y>0?` snipFreed=${Y}`:""}`);let{isAboveAutoCompactThreshold:w}=oH6($,K,_);return w}async function LZK(q,K,_,z,Y,$){if(c6(process.env.DISABLE_COMPACT))return{wasCompacted:!1};if(Y?.consecutiveFailures!==void 0&&Y.consecutiveFailures>=V0K)return{wasCompacted:!1};let O=K.options.mainLoopModel,A=K.getAppState().autoCompactWindow;if(!await W$Y(q,O,A,z,$))return{wasCompacted:!1};let H=Y?.compacted===!0&&Y.turnCounter<U77?(Y?.consecutiveRapidRefills??0)+1:0;if(H>=E0K)return N(`autocompact: rapid-refill breaker tripped — ${H} consecutive refills within <${U77} turns each (last was ${Y?.turnCounter} turns)`,{level:"warn"}),{wasCompacted:!1,rapidRefillBreakerTripped:!0};let J={isRecompactionInChain:Y?.compacted===!0,turnsSincePreviousCompact:Y?.turnCounter??-1,previousCompactTurnId:Y?.turnId,autoCompactThreshold:a68(O,A),querySource:z},M=await tg8(q,K.agentId,J.autoCompactThreshold,!1)
|
||||
|
||||
if(w)return N(`Auto tool search enabled: ${j}`+(Y?` [source: ${Y}]`:"")),O(!0,A,"auto_above_threshold",H),!0;return N(`Auto tool search disabled: ${j}`+(Y?` [source: ${Y}]`:"")),O(!1,A,"auto_below_threshold",H),!1}case"standard":return O(!1,A,"standard_mode"),!1}}function gp(q){return typeof q==="object"&&q!==null&&"type"in q&&q.type==="tool_reference"}function I$Y(q){return gp(q)&&"tool_name"in q&&typeof q.tool_name==="string"}function u$Y(q){return typeof q==="object"&&q!==null&&"type"in q&&q.type==="tool_result"&&"content"in q&&Array.isArray(q.content)}function Rd(q){let K=new Set,_=0;for(let z of q){if(z.type==="system"&&z.subtype==="compact_boundary"){let $=z.compactMetadata?.preCompactDiscoveredTools;if($){for(let O of $)K.add(O);_+=$.length}continue}if(z.type!=="user")continue;let Y=z.message?.content;if(!Array.isArray(Y))continue;for(let $ of Y)if(u$Y($)){for(let O of $.content)if(I$Y(O))K.add(O.tool_name)}}if(K.size>0)N(`Dynamic tool loading: found ${K.size} discovered tools in message history`+(_>0?` (${_} carried from compact boundary)`:""));return K}function i78(){return L8("tengu_glacier_2xr",!1)}function s77(q,K,_){let z=new Set,Y=0,$=0,O=new Set;for(let M of K){if(M.type!=="attachment")continue;if(Y++,O.add(M.attachment.type),M.attachment.type!=="deferred_tools_delta")continue;$++;for(let X of M.attachment.addedNames)z.add(X);for(let X of M.attachment.removedNames)z.delete(X)}let A=q.filter(oC),w=new Set(A.map((M)=>M.name)),j=new Set(q.map((M)=>M.name)),H=A.filter((M)=>!z.has(M.name)),J=[];for(let M of z){if(w.has(M))continue;if(!j.has(M))J.push(M)}if(H.length===0&&J.length===0)return null
|
||||
|
||||
return[n8({content:Nv(z.join(" ")),isMeta:!0})]}case"async_hook_response":{let _=q.response,z=[];if(_.systemMessage)z.push(n8({content:_.systemMessage,isMeta:!0}));if(_.hookSpecificOutput&&"additionalContext"in _.hookSpecificOutput&&_.hookSpecificOutput.additionalContext)z.push(n8({content:_.hookSpecificOutput.additionalContext,isMeta:!0}));return V9(z)}case"token_usage":return[n8({content:Nv(`Token usage: ${q.used}/${q.total}; ${q.remaining} remaining`),isMeta:!0})];case"budget_usd":return[n8({content:Nv(`USD budget: $${q.used}/$${q.total}; $${q.remaining} remaining`),isMeta:!0})];case"output_token_usage":{let _=q.budget!==null?`${pK(q.turn)} / ${pK(q.budget)}`:pK(q.turn);return[n8({content:Nv(`Output tokens — turn: ${_} · session: ${pK(q.session)}`),isMeta:!0})]}case"hook_blocking_error":return[n8({content:Nv(`${q.hookName} hook blocking error from command: "${q.blockingError.command}": ${q.blockingError.blockingError}`),isMeta:!0})];case"hook_success":if(q.hookEvent!=="SessionStart"&&q.hookEvent!=="UserPromptSubmit")return[];if(q.content==="")return[];return[n8({content:Nv(`${q.hookName} hook success: ${q.content}`),isMeta:!0})];case"hook_additional_context":{if(q.content.length===0)return[];return[n8({content:Nv(`${q.hookName} hook additional context: ${q.content.join(`
|
||||
`)}`),isMeta:!0})]}case"hook_stopped_continuation":return[n8({content:Nv(`${q.hookName} hook stopped continuation: ${q.message}`),isMeta:!0})];case"compaction_reminder":return V9([n8({content:"Auto-compact is enabled. When the context window is nearly full, older messages will be automatically summarized so you can continue working seamlessly. There is no need to stop or rush — you have unlimited context through automatic compaction.",isMeta:!0})]);case"context_efficiency":return[];case"date_change":return V9([n8({content:`The date has changed. Today's date is now ${q.newDate}. DO NOT mention this to the user explicitly because they are already aware.`,isMeta:!0})])
|
||||
|
||||
if(K[30]!==R||K[31]!==_)q6=()=>_(`Auto-compact window unchanged: ${R}`),K[30]=R,K[31]=_,K[32]=q6;else q6=K[32];let t,n;if(K[33]===Symbol.for("react.memo_cache_sentinel"))t=LA.createElement(T,null,"This command configures when auto-compaction happens. The actual threshold is the minimum of this setting and your model's context window."),n=!J&&LA.createElement(T,{color:"warning"},"Auto-compact is currently disabled (see /config)"),K[33]=t,K[34]=n;else t=K[33],n=K[34];let z6;if(K[35]!==K6||K[36]!==X)z6=X?LA.createElement(T,{color:"warning"},"CLAUDE_CODE_AUTO_COMPACT_WINDOW is set and takes precedence. Unset it to change this setting here."):LA.createElement(u,null,LA.createElement(T,null,"Select auto-compact window: "),LA.createElement(T,{bold:!0,color:"suggestion"},K6)),K[35]=K6,K[36]=X,K[37]=z6;else z6=K[37];let M6;if(K[38]===Symbol.for("react.memo_cache_sentinel"))M6=LA.createElement(u,{flexDirection:"column",marginTop:1},LA.createElement(T,{bold:!0},"Long context that holds up"),LA.createElement(T,null,"Both Opus 4.6 and Sonnet 4.6 achieve state-of-the-art scores on long-context retrieval benchmarks at 1M tokens — Opus 4.6 scores 78.3% on MRCR v2, the highest among frontier models at that length. Opus 4.6 includes 1M context at standard pricing; Sonnet 4.6 1M is available with overages."),LA.createElement(T,{dimColor:!0},"Learn more: ",SJY)),K[38]=M6;else M6=K[38];let J6;if(K[39]!==z6)J6=LA.createElement(u,{flexDirection:"column",gap:1},t,n,z6,M6),K[39]=z6,K[40]=J6;else J6=K[40];let G6;if(K[41]!==o||K[42]!==q6||K[43]!==J6)G6=LA.createElement(h1,{title:"Auto-compact",subtitle:o,onCancel:q6,inputGuide:bJY},J6),K[41]=o,K[42]=q6,K[43]=J6,K[44]=G6;else G6=K[44];return G6}function bJY(){return LA.createElement(T,{dimColor:!0},"↑/↓ to change · Enter to apply · Esc to cancel")}function xJY(q){return q.autoCompactWindow}var LA,rK7,SJY="https://claude.com/blog/1m-context-ga",lK7=1e5,nK7=1e5,iK7=1e6,mS6=0,IJY=async(q,K,_)=>{let z=_?.trim()||"";if(z){let Y=Bq8(z,K)
|
||||
|
||||
return{...r6,model:q8}}return{...S6,model:q8}})}function f8(P6){S8((V6)=>({...V6,verbose:P6})),J({...w8(),verbose:P6}),n((V6)=>({...V6,verbose:P6})),M6((V6)=>{if("verbose"in V6){let{verbose:S6,...q8}=V6;return q8}return{...V6,verbose:P6}})}let k6=[{id:"autoCompactEnabled",label:"Auto-compact",value:H.autoCompactEnabled,type:"boolean",onChange(P6){S8((V6)=>({...V6,autoCompactEnabled:P6})),J({...w8(),autoCompactEnabled:P6}),d("tengu_auto_compact_setting_changed",{enabled:P6})}},{id:"spinnerTipsEnabled",label:"Show tips",value:X?.spinnerTipsEnabled??!0,type:"boolean",onChange(P6){P7("localSettings",{spinnerTipsEnabled:P6}),P((V6)=>({...V6,spinnerTipsEnabled:P6})),d("tengu_tips_setting_changed",{enabled:P6})}},{id:"prefersReducedMotion",label:"Reduce motion",value:X?.prefersReducedMotion??!1,type:"boolean",onChange(P6){P7("localSettings",{prefersReducedMotion:P6}),P((V6)=>({...V6,prefersReducedMotion:P6})),n((V6)=>({...V6,settings:{...V6.settings,prefersReducedMotion:P6}})),d("tengu_reduce_motion_setting_changed",{enabled:P6})}},{id:"thinkingEnabled",label:"Thinking mode",value:c??!0,type:"boolean",onChange(P6){n((V6)=>({...V6,thinkingEnabled:P6})),P7("userSettings",{alwaysThinkingEnabled:P6?void 0:!1}),d("tengu_thinking_toggled",{enabled:P6})}},...gK()&&AM()?[{id:"fastMode",label:`Fast mode (${wu} only)`,value:!!K6,type:"boolean",onChange(P6){if(yY6(),P7("userSettings",{fastMode:P6?!0:void 0}),P6)n((V6)=>({...V6,mainLoopModel:$Q6(),mainLoopModelForSession:null,fastMode:!0})),M6((V6)=>({...V6,model:$Q6(),"Fast mode":"ON"}))
|
||||
|
||||
if(K[49]!==_.error||K[50]!==_.status)o=_.status==="failed"&&_.error&&Aw.default.createElement(u,{flexDirection:"column",marginTop:1},Aw.default.createElement(T,{bold:!0,color:"error"},"Error"),Aw.default.createElement(T,{color:"error",wrap:"wrap"},_.error)),K[49]=_.error,K[50]=_.status,K[51]=o;else o=K[51];let q6;if(K[52]!==z||K[53]!==g||K[54]!==F||K[55]!==U||K[56]!==K6||K[57]!==o||K[58]!==R)q6=Aw.default.createElement(h1,{title:R,subtitle:g,onCancel:z,color:"background",inputGuide:F},U,K6,o),K[52]=z,K[53]=g,K[54]=F,K[55]=U,K[56]=K6,K[57]=o,K[58]=R,K[59]=q6;else q6=K[59];let t;if(K[60]!==P||K[61]!==q6)t=Aw.default.createElement(u,{flexDirection:"column",tabIndex:0,autoFocus:!0,onKeyDown:P},q6),K[60]=P,K[61]=q6,K[62]=t;else t=K[62];return t}var Aw;var JuK=L(()=>{t6();RL6();i6();Kq();aq();Of();I7();Ra();IK();x4();dK();A_7();k36();Aw=w6(D6(),1)});import{randomUUID as CyY}from"crypto";function Cd8(q){return q.flatMap((K)=>{switch(K.type){case"assistant":return[{type:"assistant",message:K.message,uuid:K.uuid,requestId:void 0,timestamp:new Date().toISOString()}];case"user":return[{type:"user",message:K.message,uuid:K.uuid??CyY(),timestamp:K.timestamp??new Date().toISOString(),isMeta:K.isSynthetic}];case"system":if(K.subtype==="compact_boundary")return[{type:"system",content:"Conversation compacted",level:"info",subtype:"compact_boundary",compactMetadata:M_7(K.compact_metadata),uuid:K.uuid,timestamp:new Date().toISOString()}];return[];default:return[]}})}function bd8(q){let K=q.preservedSegment;return{trigger:q.trigger,pre_tokens:q.preTokens,...K&&{preserved_segment:{head_uuid:K.headUuid,anchor_uuid:K.anchorUuid,tail_uuid:K.tailUuid}}}}function M_7(q){let K=q.preserved_segment;return{trigger:q.trigger,preTokens:q.pre_tokens,...K&&{preservedSegment:{headUuid:K.head_uuid,anchorUuid:K.anchor_uuid,tailUuid:K.tail_uuid}}}}function X_7(q){return q.flatMap((K)=>{switch(K.type){case"assistant":return[{type:"assistant",message:byY(K),session_id:N8(),parent_tool_use_id:null,uuid:K.uuid,error:K.error}]
|
||||
|
||||
case"user":return[{type:"user",message:K.message,session_id:N8(),parent_tool_use_id:null,uuid:K.uuid,timestamp:K.timestamp,isSynthetic:K.isMeta||K.isVisibleInTranscriptOnly,...K.toolUseResult!==void 0&&{tool_use_result:K.toolUseResult}}];case"system":if(K.subtype==="compact_boundary"&&K.compactMetadata)return[{type:"system",subtype:"compact_boundary",session_id:N8(),uuid:K.uuid,compact_metadata:bd8(K.compactMetadata)}];if(K.subtype==="local_command"&&(K.content.includes(`<${iW}>`)||K.content.includes(`<${F_6}>`)))return[P_7(K.content,K.uuid)];return[];default:return[]}})}function P_7(q,K){let _=YA(q).replace(/<local-command-stdout>([\s\S]*?)<\/local-command-stdout>/,"$1").replace(/<local-command-stderr>([\s\S]*?)<\/local-command-stderr>/,"$1").trim();return{type:"assistant",message:Wv({content:_}).message,parent_tool_use_id:null,session_id:N8(),uuid:K}}function MuK(q){if(!q)return;return{status:q.status,...q.resetsAt!==void 0&&{resetsAt:q.resetsAt},...q.rateLimitType!==void 0&&{rateLimitType:q.rateLimitType},...q.utilization!==void 0&&{utilization:q.utilization},...q.overageStatus!==void 0&&{overageStatus:q.overageStatus},...q.overageResetsAt!==void 0&&{overageResetsAt:q.overageResetsAt},...q.overageDisabledReason!==void 0&&{overageDisabledReason:q.overageDisabledReason},...q.isUsingOverage!==void 0&&{isUsingOverage:q.isUsingOverage},...q.surpassedThreshold!==void 0&&{surpassedThreshold:q.surpassedThreshold}}}function byY(q){let K=q.message.content;if(!Array.isArray(K))return q.message;let _=K.map((z)=>{if(z.type!=="tool_use")return z;if(z.name===UX){let Y=KP();if(Y)return{...z,input:{...z.input,plan:Y}}}return z});return{...q.message,content:_}}var LC6=L(()=>{T8();O$();SE();a1();lH()});function xyY(q,K){if(q===UX)return"Review the plan in Claude Code on the web";if(!K||typeof K!=="object")return q;if(q===OO&&"questions"in K){let _=K.questions
|
||||
|
||||
if(F<0||F>=R)break;if(I<0)I=F;let U=F+J+36;if(U+j<=R&&q.compare(w,0,j,U,U+j)===0)if(m<0)m=F;else(p??=[m]).push(F);C=F+J}let g=p?mxY(q,W,p):m>=0?m:I;if(g>=0){let F=g+J,U=q.toString("latin1",F,F+36);P.set(U,M.length),M.push(W,R,b)}else X.push(W,R)}else X.push(W,R);W=R}let f=-1;for(let E=M.length-3;E>=0;E-=3){let R=q.indexOf(O,M[E]);if(R===-1||R>=M[E+1]){f=E;break}}if(f<0)return q;let G=new Set,Z=new Set,v=0,k=f;while(k!==void 0){if(G.has(k))break;G.add(k),Z.add(M[k]),v+=M[k+1]-M[k];let E=M[k+2];if(E<0)break;let R=q.toString("latin1",E,E+36);k=P.get(R)}if(D-v<D>>1)return q;let V=[],y=0;for(let E=0;E<M.length;E+=3){let R=M[E];while(y<X.length&&X[y]<R)V.push(q.subarray(X[y],X[y+1])),y+=2;if(Z.has(R))V.push(q.subarray(R,M[E+1]))}while(y<X.length)V.push(q.subarray(X[y],X[y+1])),y+=2;return Buffer.concat(V)}function BxY(q,K,_,z){let O=Buffer.from('{"type":"attribution-snapshot"'),A=Buffer.from('"compact_boundary"'),w=Buffer.allocUnsafe(1048576),j=Buffer.allocUnsafe(O.length),H=oz7(q,"r"),J=-1,M=0,X=-1,P=0,W=(D,f,G,Z)=>{if(G>=O.length&&D.compare(O,0,O.length,f,f+O.length)===0){J=Z,M=G;return}let v=D.toString("utf8",f,f+G);if(D.includes(A,f)&&D.indexOf(A,f)<f+G){let V=l8(v);if(V?.type==="system"&&V.subtype==="compact_boundary"){if(!V.compactMetadata?.preservedSegment)z(),J=-1,M=0}}let k=l8(v);if(k)_(k)};try{while(P<K){let D=FC6(H,w,0,1048576,P);if(D===0)break;let f=0;for(let G=0;G<D;G++)if(w[G]===10){if(X>=0){let Z=P+G-X,v=Math.min(O.length,Z);if(FC6(H,j,0,v,X),v===O.length&&j.compare(O,0,O.length,0,O.length)===0)J=X,M=Z;else{let k=Buffer.allocUnsafe(Z);FC6(H,k,0,Z,X),W(k,0,Z,X)}X=-1}else if(G>f)W(w,f,G-f,P+f);f=G+1}if(f<D&&X<0)X=P+f;P+=D}if(X>=0){let D=K-X,f=Buffer.allocUnsafe(D);FC6(H,f,0,D,X),W(f,0,D,X)}}finally{rz7(H)}return{lastAttributionOffset:J,lastAttributionLength:M}}function gxY(q,K,_){if(K<0||_<=0)return null;let z=oz7(q,"r");try{let Y=Buffer.allocUnsafe(_)
|
||||
|
||||
N(`[presence] pulse → ${K}`),O1.post(K,{client_id:uBY,connected_at:p$7},{headers:{...Yb6.getAuthHeaders(),"anthropic-version":"2023-06-01","anthropic-client-platform":"cli"},timeout:YnK,validateStatus:()=>!0}).then((_)=>{if(_.status>=400)N(`[presence] pulse got ${_.status}`)},()=>{})}var YnK=5000,uBY,Yb6=null,m$7=null,p$7=null,B$7=0;var $nK=L(()=>{VK();sr8();T8();_8();l1();uBY=cx6()});import{readFile as pBY,stat as BBY}from"fs/promises";async function AnK(q,K,_){let[z,Y]=await Promise.all([K.readMain(),K.readSubagents()]),$=new Set;for(let j of z??[]){let H=j.payload.uuid;if(typeof H==="string")$.add(H)}for(let j of Y??[]){let H=j.payload.uuid;if(typeof H==="string")$.add(H)}N(`[persistence-sync] Server has ${$.size} events since compaction`);let O=(j)=>{N(`[persistence-sync] Write failed: ${j}`)},A=await OnK(Df(N8()),$);for(let j of A)q("transcript",j,{...pJ(j)&&{isCompaction:!0}}).catch(O);let w=0;for(let j of _){let H=await OnK(fW(j),$);for(let J of H)q("transcript",J,{...pJ(J)&&{isCompaction:!0},agentId:j}).catch(O);w+=H.length}return N(`[persistence-sync] Uploaded ${A.length} main + ${w} subagent entries`),{uploadedMain:A.length,uploadedSubagents:w}}async function OnK(q,K){let _;try{_=(await BBY(q)).size}catch(A){if(K7(A))return[];throw A}if(_>fD6)return N(`[persistence-sync] Skipping ${q} — ${_} bytes exceeds ${fD6} threshold`),[];let z;try{z=await pBY(q,"utf8")}catch(A){if(K7(A))return[];throw A}let Y=z.split(`
|
||||
`).filter(Boolean),$=[],O=-1;for(let A=0;A<Y.length;A++){let w=Y[A];if(!w)continue;let j;try{j=l8(w)}catch{continue}if(!FBY(j))continue;if($.push(j),pJ(j))O=$.length-1}return $.slice(O+1).filter((A)=>!K.has(A.uuid))}function FBY(q){return typeof q==="object"&&q!==null&&"type"in q&&gBY.has(q.type)&&"uuid"in q&&typeof q.uuid==="string"}var gBY;var wnK=L(()=>{T8();_8();E8();a1();t4();W66();r8();gBY=new Set(["user","assistant","attachment","system"])});function kl8(q){if(q===null||typeof q!=="object")return q;let K=q;if("requestId"in K&&!("request_id"in K))K.request_id=K.requestId,delete K.requestId
|
||||
|
||||
d("tengu_post_compact_survey_event",{event_type:"responded",appearance_id:q,response:K,session_memory_compaction_enabled:_}),QO("feedback_survey",{event_type:"responded",appearance_id:q,response:K,survey_type:"post_compact"})}function DrY(q){let K=sg8();d("tengu_post_compact_survey_event",{event_type:"appeared",appearance_id:q,session_memory_compaction_enabled:K}),QO("feedback_survey",{event_type:"appeared",appearance_id:q,survey_type:"post_compact"})}var i36,jrY=3000,HrY="tengu_post_compact_survey",JrY=0.2;var S65=L(()=>{t6();l16();l1();k8();eg8();d8();a1();vm();Yi8();i36=w6(D6(),1)});function C65(q){let K=Y6(11),{onSelect:_,inputValue:z,setInputValue:Y}=q,$;if(K[0]!==_)$=(M)=>_(ZrY[M]),K[0]=_,K[1]=$;else $=K[1];let O;if(K[2]!==z||K[3]!==Y||K[4]!==$)O={inputValue:z,setInputValue:Y,isValidDigit:GrY,onDigit:$},K[2]=z,K[3]=Y,K[4]=$,K[5]=O;else O=K[5];xb6(O);let A;if(K[6]===Symbol.for("react.memo_cache_sentinel"))A=U0.default.createElement(u,null,U0.default.createElement(T,{color:"ansi:cyan"},C9," "),U0.default.createElement(T,{bold:!0},"Can Anthropic look at your session transcript to help us improve Claude Code?")),K[6]=A;else A=K[6];let w;if(K[7]===Symbol.for("react.memo_cache_sentinel"))w=U0.default.createElement(u,{marginLeft:2},U0.default.createElement(T,{dimColor:!0},"Learn more: https://code.claude.com/docs/en/data-usage#session-quality-surveys")),K[7]=w;else w=K[7];let j;if(K[8]===Symbol.for("react.memo_cache_sentinel"))j=U0.default.createElement(u,{width:10},U0.default.createElement(T,null,U0.default.createElement(T,{color:"ansi:cyan"},"1"),": Yes")),K[8]=j;else j=K[8];let H;if(K[9]===Symbol.for("react.memo_cache_sentinel"))H=U0.default.createElement(u,{width:10},U0.default.createElement(T,null,U0.default.createElement(T,{color:"ansi:cyan"},"2"),": No")),K[9]=H;else H=K[9];let J
|
||||
|
||||
a plain \`string\` implicitly converts.
|
||||
|
||||
---
|
||||
|
||||
## Context Editing / Compaction (Beta)
|
||||
|
||||
**Beta-namespace prefix is inconsistent** (source-verified against \`src/Anthropic/Models/Beta/Messages/*.cs\` @ 12.9.0). No prefix: \`MessageCreateParams\`, \`MessageCountTokensParams\`, \`Role\`. **Everything else has the \`Beta\` prefix**: \`BetaMessageParam\`, \`BetaMessage\`, \`BetaContentBlock\`, \`BetaToolUseBlock\`, all block param types. The unprefixed \`Role\` WILL collide with \`Anthropic.Models.Messages.Role\` if you import both namespaces (CS0104). Safest: import only Beta; if mixing, alias the beta \`Role\`:
|
||||
|
||||
\`\`\`csharp
|
||||
using Anthropic.Models.Beta.Messages;
|
||||
using NonBeta = Anthropic.Models.Messages; // only if you also need non-beta types
|
||||
// Now: MessageCreateParams, BetaMessageParam, Role (beta's), NonBeta.Role (if needed)
|
||||
\`\`\`
|
||||
|
||||
|
||||
\`BetaMessage.Content\` is \`IReadOnlyList<BetaContentBlock>\` — a 15-variant discriminated union. Narrow with \`TryPick*\`. **Response \`BetaContentBlock\` is NOT assignable to param \`BetaContentBlockParam\`** — there's no \`.ToParam()\` in C#. Round-trip by converting each block:
|
||||
|
||||
\`\`\`csharp
|
||||
using Anthropic.Models.Beta.Messages;
|
||||
|
||||
var betaParams = new MessageCreateParams // no Beta prefix — one of only 2 unprefixed
|
||||
{
|
||||
Model = Model.ClaudeOpus4_6,
|
||||
MaxTokens = 16000,
|
||||
Betas = ["compact-2026-01-12"],
|
||||
ContextManagement = new BetaContextManagementConfig
|
||||
{
|
||||
Edits = [new BetaCompact20260112Edit()],
|
||||
},
|
||||
Messages = messages,
|
||||
};
|
||||
BetaMessage resp = await client.Beta.Messages.Create(betaParams);
|
||||
|
||||
foreach (BetaContentBlock block in resp.Content)
|
||||
{
|
||||
if (block.TryPickCompaction(out BetaCompactionBlock? compaction))
|
||||
{
|
||||
// Content is nullable — compaction can fail server-side
|
||||
Console.WriteLine($"compaction summary: {compaction.Content}")
|
||||
|
||||
use \`anthropic.File()\` to attach a filename + content-type for the multipart encoding.
|
||||
|
||||
\`\`\`go
|
||||
f, _ := os.Open("./upload_me.txt")
|
||||
defer f.Close()
|
||||
|
||||
meta, err := client.Beta.Files.Upload(ctx, anthropic.BetaFileUploadParams{
|
||||
File: anthropic.File(f, "upload_me.txt", "text/plain"),
|
||||
Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaFilesAPI2025_04_14},
|
||||
})
|
||||
// meta.ID is the file_id to reference in subsequent message requests
|
||||
\`\`\`
|
||||
|
||||
Other \`Beta.Files\` methods: \`List\`, \`Delete\`, \`Download\`, \`GetMetadata\`.
|
||||
|
||||
---
|
||||
|
||||
## Context Editing / Compaction (Beta)
|
||||
|
||||
Use \`Beta.Messages.New\` with \`ContextManagement\` on \`BetaMessageNewParams\`. There is no \`NewBetaAssistantMessage\` — use \`.ToParam()\` for the round-trip.
|
||||
|
||||
\`\`\`go
|
||||
params := anthropic.BetaMessageNewParams{
|
||||
Model: anthropic.ModelClaudeOpus4_6, // also supported: ModelClaudeSonnet4_6
|
||||
MaxTokens: 16000,
|
||||
Betas: []anthropic.AnthropicBeta{"compact-2026-01-12"},
|
||||
ContextManagement: anthropic.BetaContextManagementConfigParam{
|
||||
Edits: []anthropic.BetaContextManagementConfigEditUnionParam{
|
||||
{OfCompact20260112: &anthropic.BetaCompact20260112EditParam{}},
|
||||
},
|
||||
},
|
||||
Messages: []anthropic.BetaMessageParam{ /* ... */ },
|
||||
}
|
||||
|
||||
resp, err := client.Beta.Messages.New(ctx, params)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Round-trip: append response to history via .ToParam()
|
||||
params.Messages = append(params.Messages, resp.ToParam())
|
||||
|
||||
// Read compaction blocks from the response
|
||||
for _, block := range resp.Content {
|
||||
if c, ok := block.AsAny().(anthropic.BetaCompactionBlock); ok {
|
||||
fmt.Println("compaction summary:", c.Content)
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
Other edit types: \`BetaClearToolUses20250919EditParam\`, \`BetaClearThinking20251015EditParam\`.
|
||||
`;var N45=()=>{}
|
||||
|
||||
you must pass it back on subsequent requests — append \`response.content\`, not just the text.
|
||||
|
||||
\`\`\`python
|
||||
import anthropic
|
||||
|
||||
client = anthropic.Anthropic()
|
||||
messages = []
|
||||
|
||||
def chat(user_message: str) -> str:
|
||||
messages.append({"role": "user", "content": user_message})
|
||||
|
||||
response = client.beta.messages.create(
|
||||
betas=["compact-2026-01-12"],
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=16000,
|
||||
messages=messages,
|
||||
context_management={
|
||||
"edits": [{"type": "compact_20260112"}]
|
||||
}
|
||||
)
|
||||
|
||||
# Append full content — compaction blocks must be preserved
|
||||
messages.append({"role": "assistant", "content": response.content})
|
||||
|
||||
return next(block.text for block in response.content if block.type == "text")
|
||||
|
||||
# Compaction triggers automatically when context grows large
|
||||
print(chat("Help me build a Python web scraper"))
|
||||
print(chat("Add support for JavaScript-rendered pages"))
|
||||
print(chat("Now add rate limiting and error handling"))
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Stop Reasons
|
||||
|
||||
The \`stop_reason\` field in the response indicates why the model stopped generating:
|
||||
|
||||
| Value | Meaning |
|
||||
|-------|---------|
|
||||
| \`end_turn\` | Claude finished its response naturally |
|
||||
| \`max_tokens\` | Hit the \`max_tokens\` limit — increase it or use streaming |
|
||||
| \`stop_sequence\` | Hit a custom stop sequence |
|
||||
| \`tool_use\` | Claude wants to call a tool — execute it and continue |
|
||||
| \`pause_turn\` | Model paused and can be resumed (agentic flows) |
|
||||
| \`refusal\` | Claude refused for safety reasons — output may not match your schema |
|
||||
|
||||
---
|
||||
|
||||
## Cost Optimization Strategies
|
||||
|
||||
### 1. Use Prompt Caching for Repeated Context
|
||||
|
||||
\`\`\`python
|
||||
# Automatic caching (simplest — caches the last cacheable block)
|
||||
response = client.messages.create(
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=16000,
|
||||
cache_control={"type": "ephemeral"},
|
||||
system=large_document_text, # e.g., 50KB of context
|
||||
messages=[{"role": "user", "content": "Summarize the key points"}]
|
||||
)
|
||||
|
||||
# First request: full cost
|
||||
# Subsequent requests: ~90% cheaper for cached portion
|
||||
\`\`\`
|
||||
|
||||
### 2. Choose the Right Model
|
||||
|
||||
\`\`\`python
|
||||
# Default to Opus for most tasks
|
||||
response = client.messages.create(
|
||||
model="{{OPUS_ID}}", # $5.00/$25.00 per 1M tokens
|
||||
max_tokens=16000,
|
||||
messages=[{"role": "user", "content": "Explain quantum computing"}]
|
||||
)
|
||||
|
||||
# Use Sonnet for high-volume production workloads
|
||||
standard_response = client.messages.create(
|
||||
model="{{SONNET_ID}}", # $3.00/$15.00 per 1M tokens
|
||||
max_tokens=16000,
|
||||
messages=[{"role": "user", "content": "Summarize this document"}]
|
||||
)
|
||||
|
||||
# Use Haiku only for simple, speed-critical tasks
|
||||
simple_response = client.messages.create(
|
||||
model="{{HAIKU_ID}}", # $1.00/$5.00 per 1M tokens
|
||||
max_tokens=256,
|
||||
messages=[{"role": "user", "content": "Classify this as positive or negative"}]
|
||||
)
|
||||
\`\`\`
|
||||
|
||||
### 3. Use Token Counting Before Requests
|
||||
|
||||
\`\`\`python
|
||||
count_response = client.messages.count_tokens(
|
||||
model="{{OPUS_ID}}",
|
||||
messages=messages,
|
||||
system=system
|
||||
)
|
||||
|
||||
estimated_input_cost = count_response.input_tokens * 0.000005 # $5/1M tokens
|
||||
print(f"Estimated input cost: \${estimated_input_cost:.4f}")
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Retry with Exponential Backoff
|
||||
|
||||
> **Note:** The Anthropic SDK automatically retries rate limit (429) and server errors (5xx) with exponential backoff. You can configure this with \`max_retries\` (default: 2). Only implement custom retry logic if you need behavior beyond what the SDK provides.
|
||||
|
||||
\`\`\`python
|
||||
import time
|
||||
import random
|
||||
import anthropic
|
||||
|
||||
def call_with_retry(
|
||||
client: anthropic.Anthropic,
|
||||
max_retries: int = 5,
|
||||
base_delay: float = 1.0,
|
||||
max_delay: float = 60.0,
|
||||
**kwargs
|
||||
):
|
||||
"""Call the API with exponential backoff retry."""
|
||||
last_exception = None
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return client.messages.create(**kwargs)
|
||||
except anthropic.RateLimitError as e:
|
||||
last_exception = e
|
||||
except anthropic.APIStatusError as e:
|
||||
if e.status_code >= 500:
|
||||
last_exception = e
|
||||
else:
|
||||
raise # Client errors (4xx except 429) should not be retried
|
||||
|
||||
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
|
||||
print(f"Retry {attempt + 1}/{max_retries} after {delay:.1f}s")
|
||||
time.sleep(delay)
|
||||
|
||||
raise last_exception
|
||||
\`\`\`
|
||||
`
|
||||
|
||||
Claude reads the full file when the task calls for it. |
|
||||
|
||||
Both patterns keep the fixed context small and load detail on demand.
|
||||
|
||||
---
|
||||
|
||||
## Long-Running Agents: Managing Context
|
||||
|
||||
| Pattern | When to use it | What to expect |
|
||||
| --- | --- | --- |
|
||||
| **Context editing** | Context grows stale over many turns (old tool results, completed thinking). | Tool results and thinking blocks are cleared based on configurable thresholds. Keeps the transcript lean without summarizing. |
|
||||
| **Compaction** | Conversation likely to reach or exceed the context window limit. | Earlier context is summarized into a compaction block server-side. See \`SKILL.md\` §Compaction for the critical \`response.content\` handling. |
|
||||
| **Memory** | State must persist across sessions (not just within one conversation). | Claude reads/writes files in a memory directory. Survives process restarts. |
|
||||
|
||||
**Choosing between them:** Context editing and compaction operate within a session — editing prunes stale turns, compaction summarizes when you're near the limit. Memory is for cross-session persistence. Many long-running agents use all three.
|
||||
|
||||
---
|
||||
|
||||
## Caching for Agents
|
||||
|
||||
**Read \`prompt-caching.md\` first.** It covers the prefix-match invariant, breakpoint placement, the silent-invalidator audit, and why changing tools or models mid-session breaks the cache. This section covers only the agent-specific workarounds for those constraints.
|
||||
|
||||
| Constraint (from \`prompt-caching.md\`) | Agent-specific workaround |
|
||||
| --- | --- |
|
||||
| Editing the system prompt mid-session invalidates the cache. | Append a \`<system-reminder>\` block in the \`messages\` array instead. The cached prefix stays intact. Claude Code uses this for time updates and mode transitions. |
|
||||
| Switching models mid-session invalidates the cache. | Spawn a **subagent** with the cheaper model for the sub-task
|
||||
|
||||
adding, removing, or reordering a tool invalidates the entire cache. Same for switching models (caches are model-scoped). If you need "modes", don't swap the tool set — give Claude a tool that records the mode transition, or pass the mode as message content. Serialize tools deterministically (sort by name).
|
||||
|
||||
**Fork operations must reuse the parent's exact prefix.** Side computations (summarization, compaction, sub-agents) often spin up a separate API call. If the fork rebuilds \`system\` / \`tools\` / \`model\` with any difference, it misses the parent's cache entirely. Copy the parent's \`system\`, \`tools\`, and \`model\` verbatim, then append fork-specific content at the end.
|
||||
|
||||
---
|
||||
|
||||
## Silent invalidators
|
||||
|
||||
When reviewing code, grep for these inside anything that feeds the prompt prefix:
|
||||
|
||||
| Pattern | Why it breaks caching |
|
||||
|---|---|
|
||||
| \`datetime.now()\` / \`Date.now()\` / \`time.time()\` in system prompt | Prefix changes every request |
|
||||
| \`uuid4()\` / \`crypto.randomUUID()\` / request IDs early in content | Same — every request is unique |
|
||||
| \`json.dumps(d)\` without \`sort_keys=True\` / iterating a \`set\` | Non-deterministic serialization → prefix bytes differ |
|
||||
| f-string interpolating session/user ID into system prompt | Per-user prefix; no cross-user sharing |
|
||||
| Conditional system sections (\`if flag: system += ...\`) | Every flag combination is a distinct prefix |
|
||||
| \`tools=build_tools(user)\` where set varies per user | Tools render at position 0
|
||||
|
||||
try {
|
||||
const response = await client.messages.create({...});
|
||||
} catch (error) {
|
||||
if (error instanceof Anthropic.BadRequestError) {
|
||||
console.error("Bad request:", error.message);
|
||||
} else if (error instanceof Anthropic.AuthenticationError) {
|
||||
console.error("Invalid API key");
|
||||
} else if (error instanceof Anthropic.RateLimitError) {
|
||||
console.error("Rate limited - retry later");
|
||||
} else if (error instanceof Anthropic.APIError) {
|
||||
console.error(\`API error \${error.status}:\`, error.message);
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
All classes extend \`Anthropic.APIError\` with a typed \`status\` field. Check from most specific to least specific. See [shared/error-codes.md](../../shared/error-codes.md) for the full error code reference.
|
||||
|
||||
---
|
||||
|
||||
## Multi-Turn Conversations
|
||||
|
||||
The API is stateless — send the full conversation history each time. Use \`Anthropic.MessageParam[]\` to type the messages array:
|
||||
|
||||
\`\`\`typescript
|
||||
const messages: Anthropic.MessageParam[] = [
|
||||
{ role: "user", content: "My name is Alice." },
|
||||
{ role: "assistant", content: "Hello Alice! Nice to meet you." },
|
||||
{ role: "user", content: "What's my name?" },
|
||||
];
|
||||
|
||||
const response = await client.messages.create({
|
||||
model: "{{OPUS_ID}}",
|
||||
max_tokens: 16000,
|
||||
messages: messages,
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
**Rules:**
|
||||
|
||||
- Consecutive same-role messages are allowed — the API combines them into a single turn
|
||||
- First message must be \`user\`
|
||||
- Use SDK types (\`Anthropic.MessageParam\`, \`Anthropic.Message\`, \`Anthropic.Tool\`, etc.) for all API data structures — don't redefine equivalent interfaces
|
||||
|
||||
---
|
||||
|
||||
### Compaction (long conversations)
|
||||
|
||||
> **Beta, Opus 4.6 and Sonnet 4.6.** When conversations approach the 200K context window, compaction automatically summarizes earlier context server-side. The API returns a \`compaction\` block; you must pass it back on subsequent requests — append \`response.content\`, not just the text.
|
||||
|
||||
\`\`\`typescript
|
||||
import Anthropic from "@anthropic-ai/sdk";
|
||||
|
||||
const client = new Anthropic();
|
||||
const messages: Anthropic.Beta.BetaMessageParam[] = []
|
||||
|
||||
async function chat(userMessage: string): Promise<string> {
|
||||
messages.push({ role: "user", content: userMessage });
|
||||
|
||||
const response = await client.beta.messages.create({
|
||||
betas: ["compact-2026-01-12"],
|
||||
model: "{{OPUS_ID}}",
|
||||
max_tokens: 16000,
|
||||
messages,
|
||||
context_management: {
|
||||
edits: [{ type: "compact_20260112" }],
|
||||
},
|
||||
});
|
||||
|
||||
// Append full content — compaction blocks must be preserved
|
||||
messages.push({ role: "assistant", content: response.content });
|
||||
|
||||
const textBlock = response.content.find(
|
||||
(b): b is Anthropic.Beta.BetaTextBlock => b.type === "text",
|
||||
);
|
||||
return textBlock?.text ?? "";
|
||||
}
|
||||
|
||||
// Compaction triggers automatically when context grows large
|
||||
console.log(await chat("Help me build a Python web scraper"));
|
||||
console.log(await chat("Add support for JavaScript-rendered pages"));
|
||||
console.log(await chat("Now add rate limiting and error handling"))
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
GK=class GK extends Error{constructor(q,K,_){super(`MCP error ${q}: ${K}`);this.code=q,this.data=_,this.name="McpError"}static fromError(q,K,_){if(q===z5.UrlElicitationRequired&&_){let z=_;if(z.elicitations)return new NZ7(z.elicitations,K)}return new GK(q,K,_)}};NZ7=class NZ7 extends GK{constructor(q,K=`URL elicitation${q.length>1?"s":""} required`){super(z5.UrlElicitationRequired,K,{elicitations:q})}get elicitations(){return this.data?.elicitations??[]}}});function ce(q){return q==="completed"||q==="failed"||q==="cancelled"}var kW5;var UY8=L(()=>{kW5=Symbol("Let zodToJsonSchema decide on which parser to use")});var v71=L(()=>{UY8()});var LR=()=>{};var T71=L(()=>{JX()});var k71=()=>{};var QY8=L(()=>{JX()});var V71=L(()=>{JX()});var N71=()=>{};var y71=L(()=>{JX()});var E71=L(()=>{JX();LR()});var L71=L(()=>{JX()});var pH$;var dY8=L(()=>{pH$=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789")});var cY8=L(()=>{JX();dY8();QY8();LR()});var h71=L(()=>{JX();cY8();LR()});var R71=L(()=>{LR()});var lY8=L(()=>{JX()});var S71=L(()=>{JX();lY8()});var C71=()=>{};var b71=L(()=>{JX()});var x71=L(()=>{JX();LR()});var I71=L(()=>{JX()});var u71=L(()=>{JX()});var m71=L(()=>{JX()});var p71=L(()=>{JX()});var B71=L(()=>{LR()});var g71=L(()=>{LR()});var F71=L(()=>{JX()});var U71=L(()=>{LR();T71();k71();QY8();V71();N71();y71();E71();L71();h71();R71();S71();C71();b71();x71();I71();u71();cY8();m71();dY8();p71();B71();lY8();g71();F71()});var JX=L(()=>{UY8();U71();LR()});var yZ7=()=>{};var Q71=L(()=>{JX();v71();LR()});var EZ7=L(()=>{Q71();UY8();v71();JX();yZ7();LR();T71();k71();QY8();V71();N71();y71();E71();L71();h71();R71();S71();C71();b71();x71();I71();u71();F71();cY8();m71();dY8();p71();B71();lY8();g71();U71();Q71()});function d71(q){let _=DW6(q)?.method;if(!_)throw Error("Schema is missing a method literal");let z=vf7(_);if(typeof z!=="string")throw Error("Schema method literal must be a string");return z}function c71(q,K){let _=KT(q,K);if(!_.success)throw _.error;return _.data}var LZ7=L(()=>{Gm6();EZ7()})
|
||||
|
||||
return` • tabId ${w.tabId}: "${w.title}" (${w.url})`}).join(`
|
||||
`);return{result:{content:[{type:"text",text:JSON.stringify({availableTabs:$})},{type:"text",text:`
|
||||
|
||||
Tab Context:
|
||||
- Available tabs:
|
||||
${O}`}]}}}for(let O of Y)if(O.status==="fulfilled")return O.value.result;throw new ev(`[${_}] All sockets failed for tabs_context_mcp`)}updateTabRoutes(q,K){let _=this.extractTabs(q);if(!_)return;for(let z of _)if(typeof z==="object"&&z!==null&&"tabId"in z){let Y=z.tabId;this.tabRoutes.set(Y,K)}}extractTabs(q){if(!q||typeof q!=="object")return null;let _=q.result?.content;if(!_||!Array.isArray(_))return null;for(let z of _)if(z.type==="text"&&z.text)try{let Y=JSON.parse(z.text);if(Array.isArray(Y))return Y;if(Y&&Array.isArray(Y.availableTabs))return Y.availableTabs}catch{}return null}getSocketPathForClient(q){for(let[K,_]of this.clients.entries())if(_===q)return K;return""}refreshClients(){let q=this.getAvailableSocketPaths(),{logger:K,serverName:_}=this.context;for(let z of q)if(!this.clients.has(z)){K.info(`[${_}] Adding socket to pool: ${z}`);let Y={...this.context,socketPath:z,getSocketPath:void 0,getSocketPaths:void 0},$=Wz8(Y);if($.disableAutoReconnect=!0,this.notificationHandler)$.setNotificationHandler(this.notificationHandler);this.clients.set(z,$)}for(let[z,Y]of this.clients.entries())if(!q.includes(z)){K.info(`[${_}] Removing stale socket from pool: ${z}`),Y.disconnect(),this.clients.delete(z);for(let[$,O]of this.tabRoutes.entries())if(O===z)this.tabRoutes.delete($)}}getAvailableSocketPaths(){return this.context.getSocketPaths?.()??[]}}function Wk7(q){return new Pk7(q)}var Dk7=L(()=>{hu6()});async function Bk5(q,K,_,z,Y){let $=await K.callTool(_,z,Y);if(q.logger.silly(`[${q.serverName}] Received result from socket bridge: ${JSON.stringify($)}`),$===null||$===void 0)return{content:[{type:"text",text:"Tool execution completed"}]};let{result:O,error:A}=$,w=A||O,j=!!A;if(!w)return{content:[{type:"text",text:"Tool execution completed"}]};if(j&&Uk5(w.content))q.onAuthenticationError();let{content:H}=w
|
||||
|
||||
function V2(q){let K=q.replace(/[^a-zA-Z0-9_-]/g,"_");if(q.startsWith("claude.ai "))K=K.replace(/_+/g,"_").replace(/^_|_$/g,"");return K}function NV(q){let K=q.split("__"),[_,z,...Y]=K;if(_!=="mcp"||!z)return null;let $=Y.length>0?Y.join("__"):void 0;return{serverName:z,toolName:$}}function dE(q){return`mcp__${V2(q)}__`}function $z6(q,K){return`${dE(q)}${V2(K)}`}function L31(q){return q.mcpInfo?$z6(q.mcpInfo.serverName,q.mcpInfo.toolName):q.name}function Aw8(q,K){let _=`mcp__${V2(K)}__`;return q.replace(_,"")}function ww8(q){let K=q.replace(/\s*\(MCP\)\s*$/,"");K=K.trim();let _=K.indexOf(" - ");if(_!==-1)return K.substring(_+3).trim();return K}var yV=()=>{};var H4="Agent",bI="Task",gB6="verification",Eb7;var UY=L(()=>{Eb7=new Set(["Explore","Plan"])});var EV="TaskOutput";var jg="TaskStop",Lb7=`
|
||||
- Stops a running background task by its ID
|
||||
- Takes a task_id parameter identifying the task to stop
|
||||
- Returns a success or failure status
|
||||
- Use this tool when you need to terminate a long-running task
|
||||
`;var An={};v8(An,{LEGACY_BRIEF_TOOL_NAME:()=>h31,DESCRIPTION:()=>R31,BRIEF_TOOL_PROMPT:()=>S31,BRIEF_TOOL_NAME:()=>gD6,BRIEF_PROACTIVE_SECTION:()=>_I5});var gD6="SendUserMessage",h31="Brief",R31="Send a message to the user",S31="Send a message the user will read. Text outside this tool is visible in the detail view, but most won't open it — the answer lives here.\n\n`message` supports markdown. `attachments` takes file paths (absolute or cwd-relative) for images, diffs, logs.\n\n`status` labels intent: 'normal' when replying to what they just asked; 'proactive' when you're initiating — a scheduled task finished, a blocker surfaced during background work, you need input on something they haven't asked about. Set it honestly; downstream routing uses it.",_I5
|
||||
|
||||
if(Y){if(z.ruleContent!==void 0||x31(q,"(")>0)return{valid:!1,error:"MCP rules do not support patterns in parentheses",suggestion:`Use "${z.toolName}" without parentheses, or use "mcp__${Y.serverName}__*" for all tools`,examples:[`mcp__${Y.serverName}`,`mcp__${Y.serverName}__*`,Y.toolName&&Y.toolName!=="*"?`mcp__${Y.serverName}__${Y.toolName}`:void 0].filter(Boolean)};return{valid:!0}}if(!z.toolName||z.toolName.length===0)return{valid:!1,error:"Tool name cannot be empty"};if(z.toolName[0]!==z.toolName[0]?.toUpperCase())return{valid:!1,error:"Tool names must start with uppercase",suggestion:`Use "${MG(String(z.toolName))}"`};let $=ub7(z.toolName);if($&&z.ruleContent!==void 0){let O=$(z.ruleContent);if(!O.valid)return O}if(Ib7(z.toolName)&&z.ruleContent!==void 0){let O=z.ruleContent;if(O.includes(":*")&&!O.endsWith(":*"))return{valid:!1,error:"The :* pattern must be at the end",suggestion:"Move :* to the end for prefix matching, or use * for wildcard matching",examples:["Bash(npm run:*) - prefix matching (legacy)","Bash(npm run *) - wildcard matching"]};if(O===":*")return{valid:!1,error:"Prefix cannot be empty before :*",suggestion:"Specify a command prefix before :*",examples:["Bash(npm:*)","Bash(git:*)"]}}if(xb7(z.toolName)&&z.ruleContent!==void 0){let O=z.ruleContent;if(O.includes(":*"))return{valid:!1,error:'The ":*" syntax is only for Bash prefix rules',suggestion:'Use glob patterns like "*" or "**" for file matching',examples:[`${z.toolName}(*.ts) - matches .ts files`,`${z.toolName}(src/**) - matches all files in src`,`${z.toolName}(**/*.test.ts) - matches test files`]};if(O.includes("*")&&!O.match(/^\*|\*$|\*\*|\/\*|\*\.|\*\)/)&&!O.includes("**"))return{valid:!1,error:"Wildcard placement might be incorrect",suggestion:"Wildcards are typically used at path boundaries",examples:[`${z.toolName}(*.js) - all .js files`,`${z.toolName}(src/*) - all files directly in src`,`${z.toolName}(src/**) - all files recursively in src`]}}return{valid:!0}}var Hw8;var u31=L(()=>{u7();yV();lf();mb7()
|
||||
|
||||
for(let[z,Y]of Object.entries(K.tasks))if(Y.type==="in_process_teammate"&&Y.status==="running"&&!Y.isIdle)_.push(z);if(_.length===0)return Promise.resolve();return new Promise((z)=>{let Y=_.length,$=()=>{if(Y--,Y===0)z()};q((O)=>{let A={...O.tasks};for(let w of _){let j=A[w];if(j&&j.type==="in_process_teammate")if(j.isIdle)$();else A[w]={...j,onIdleCallbacks:[...j.onIdleCallbacks??[],$]}}return{...O,tasks:A}})})}var NL=null;var fY=L(()=>{gG();d8();gG()});import{extname as PX_}from"path";function HK(q){if(q.startsWith("mcp__"))return"mcp_tool";return q}function z08(){return c6(process.env.OTEL_LOG_TOOL_DETAILS)}function WX_(q,K){if(process.env.CLAUDE_CODE_ENTRYPOINT==="local-agent")return!0;if(q==="claudeai-proxy")return!0;if(K&&yaq(K))return!0;return!1}function mF(q,K,_){let z=sy1(q);if(!z)return{};if(!DX_.has(z.serverName)&&!WX_(K,_))return{};return{mcpServerName:z.serverName,mcpToolName:z.mcpToolName}}function r16(){let{namespace:q,cluster:K}=wM7();return{...q&&{cooNamespace:q},...K&&{cooCluster:K}}}function sy1(q){if(!q.startsWith("mcp__"))return;let K=q.split("__");if(K.length<3)return;let _=K[1],z=K.slice(2).join("__");if(!_||!z)return;return{serverName:_,mcpToolName:z}}function Saq(q,K){if(q!=="Skill")return;if(typeof K==="object"&&K!==null&&"skill"in K&&typeof K.skill==="string")return K.skill;return}function ay1(q,K=0){if(typeof q==="string"){if(q.length>fX_)return`${q.slice(0,ZX_)}…[${q.length} chars]`;return q}if(typeof q==="number"||typeof q==="boolean"||q===null||q===void 0)return q;if(K>=GX_)return"<nested>";if(Array.isArray(q)){let _=q.slice(0,K08).map((z)=>ay1(z,K+1));if(q.length>K08)_.push(`…[${q.length} items]`);return _}if(typeof q==="object"){let _=Object.entries(q).filter(([Y])=>!Y.startsWith("_")),z=_.slice(0,K08).map(([Y,$])=>[Y,ay1($,K+1)]);if(_.length>K08)z.push(["…",`${_.length} keys`]);return Object.fromEntries(z)}return String(q)}function Caq(q){if(!z08())return;let K=ay1(q),_=g6(K);if(_.length>Raq)_=_.slice(0,Raq)+"…[truncated]";return _}function i16(q){let K=PX_(q).toLowerCase()
|
||||
|
||||
v8(vu1,{verifyMcpbFile:()=>cl_,verifyCertificateChain:()=>nH4,validateManifest:()=>Du1,unsignMcpbFile:()=>nl_,unpackExtension:()=>Mu1,signMcpbFile:()=>dl_,shouldExclude:()=>Sp_,replaceVariables:()=>ZN8,readPackageJson:()=>PY4,readMcpbIgnorePatterns:()=>Ex1,promptVisualAssets:()=>hY4,promptUserConfig:()=>SY4,promptUrls:()=>LY4,promptTools:()=>VY4,promptServerConfig:()=>kY4,promptPrompts:()=>NY4,promptOptionalFields:()=>yY4,promptLongDescription:()=>EY4,promptCompatibility:()=>RY4,promptBasicInfo:()=>vY4,promptAuthorInfo:()=>TY4,printNextSteps:()=>bY4,packExtension:()=>YJ4,initExtension:()=>ab1,hasRequiredConfigMissing:()=>OJ4,getMcpConfigForManifest:()=>Zn_,getDefaultServerConfig:()=>ZY4,getDefaultRepositoryUrl:()=>WY4,getDefaultOptionalFields:()=>GY4,getDefaultEntryPoint:()=>ob1,getDefaultBasicInfo:()=>DY4,getDefaultAuthorUrl:()=>ib1,getDefaultAuthorName:()=>lb1,getDefaultAuthorInfo:()=>fY4,getDefaultAuthorEmail:()=>nb1,getAllFilesWithCount:()=>WV8,getAllFiles:()=>Z$4,extractSignatureBlock:()=>Oo6,createMcpConfig:()=>rb1,cleanMcpb:()=>wn_,buildManifest:()=>CY4,McpbUserConfigurationOptionSchema:()=>HY4,McpbUserConfigValuesSchema:()=>Kp_,McpbSignatureInfoSchema:()=>_p_,McpbManifestToolSchema:()=>wY4,McpbManifestServerSchema:()=>OY4,McpbManifestSchema:()=>Zr6,McpbManifestRepositorySchema:()=>zY4,McpbManifestPromptSchema:()=>jY4,McpbManifestPlatformOverrideSchema:()=>YY4,McpbManifestMcpConfigSchema:()=>$Y4,McpbManifestCompatibilitySchema:()=>AY4,McpbManifestAuthorSchema:()=>_Y4,McpServerConfigSchema:()=>cb1,EXCLUDE_PATTERNS:()=>f$4,CURRENT_MANIFEST_VERSION:()=>UA6});var Tu1=L(()=>{sb1();Zu1();Xu1();hx1();Hu1();fu1();Gr6();AJ4()});async function Gn_(q){let{McpbManifestSchema:K}=await Promise.resolve().then(() => (Tu1(),vu1)),_=K.safeParse(q);if(!_.success){let z=_.error.flatten(),Y=[...Object.entries(z.fieldErrors).map(([$,O])=>`${$}: ${O?.join(", ")}`),...z.formErrors||[]].filter(Boolean).join("; ");throw Error(`Invalid manifest: ${Y}`)}return _.data}async function vn_(q){let K
|
||||
|
||||
let O=new Set(Object.keys($)),A=new Set(Object.keys(Y)),w=n3(),j=PJ4(q,K),H=w.read()?.pluginSecrets?.[j]??void 0,J=H?Object.fromEntries(Object.entries(H).filter(([D])=>!A.has(D))):void 0,M=J&&H&&Object.keys(J).length!==Object.keys(H).length;if(Object.keys($).length>0||M){let D=w.read()??{};if(!D.pluginSecrets)D.pluginSecrets={};D.pluginSecrets[j]={...J,...$};let f=w.update(D);if(!f.success)throw Error(`Failed to save sensitive config to secure storage for ${j}`);if(f.warning)N(`Server secrets save warning: ${f.warning}`,{level:"warn"});if(M)N(`saveMcpServerUserConfig: scrubbed ${Object.keys(H).length-Object.keys(J).length} stale non-sensitive key(s) from secureStorage for ${j}`)}let X=k7(),P=X.pluginConfigs?.[q]?.mcpServers?.[K]??{},W=Object.keys(P).filter((D)=>O.has(D));if(Object.keys(Y).length>0||W.length>0){if(!X.pluginConfigs)X.pluginConfigs={};if(!X.pluginConfigs[q])X.pluginConfigs[q]={};if(!X.pluginConfigs[q].mcpServers)X.pluginConfigs[q].mcpServers={};let D=Object.fromEntries(W.map((G)=>[G,void 0]));X.pluginConfigs[q].mcpServers[K]={...Y,...D};let f=P7("userSettings",X);if(f.error)throw f.error;if(W.length>0)N(`saveMcpServerUserConfig: scrubbed ${W.length} plaintext sensitive key(s) from settings.json for ${q}/${K}`)}N(`Saved user config for ${q}/${K} (${Object.keys(Y).length} non-sensitive, ${Object.keys($).length} sensitive)`)}catch(Y){let $=m1(Y);throw j6($),Error(`Failed to save user configuration for ${q}/${K}: ${$.message}`)}}function $w6(q,K){let _=[];for(let[z,Y]of Object.entries(K)){let $=q[z];if(Y.required&&($===void 0||$==="")){_.push(`${Y.title||z} is required but not provided`);continue}if($===void 0||$==="")continue;if(Y.type==="string"){if(Array.isArray($)){if(!Y.multiple)_.push(`${Y.title||z} must be a string, not an array`);else if(!$.every((O)=>typeof O==="string"))_.push(`${Y.title||z} must be an array of strings`)}else if(typeof $!=="string")_.push(`${Y.title||z} must be a string`)}else if(Y.type==="number"&&typeof $!=="number")_.push(`${Y.title||z} must be a number`)
|
||||
|
||||
production payments code needs everything.
|
||||
|
||||
Test suite results are context, not evidence. Run the suite, note pass/fail, then move on to your real verification. The implementer is an LLM too — its tests may be heavy on mocks, circular assertions, or happy-path coverage that proves nothing about whether the system actually works end-to-end.
|
||||
|
||||
=== VERIFICATION PROTOCOL ===
|
||||
For each modified file / change area you identified in your scan:
|
||||
1. Happy path: run it, confirm expected output.
|
||||
2. MANDATORY adversarial probe: at least ONE of — boundary value (0, -1, empty, MAX_INT, very long string, unicode), concurrency (parallel requests to create-if-not-exists), idempotency (same mutation twice), orphan op (delete/reference nonexistent ID). Document the result even if handled correctly.
|
||||
3. If the parent added tests: read them. Are they circular? Mocked to meaninglessness? Do they cover the change?
|
||||
|
||||
A report with zero adversarial probes is a happy-path confirmation, not verification. It will be rejected.
|
||||
|
||||
=== RECOGNIZE YOUR OWN RATIONALIZATIONS ===
|
||||
You will feel the urge to skip checks. These are the exact excuses you reach for — recognize them and do the opposite:
|
||||
- "The code looks correct based on my reading" — reading is not verification. Run it.
|
||||
- "The implementer's tests already pass" — the implementer is an LLM. Verify independently.
|
||||
- "This is probably fine" — probably is not verified. Run it.
|
||||
- "Let me start the server and check the code" — no. Start the server and hit the endpoint.
|
||||
- "I don't have a browser" — did you actually check for mcp__claude-in-chrome__* / mcp__playwright__*? If present, use them. If an MCP tool fails, troubleshoot (server running? selector right?). The fallback exists so you don't invent your own "can't do this" story.
|
||||
- "This would take too long" — not your call.
|
||||
If you catch yourself writing an explanation instead of a command, stop. Run the command.
|
||||
|
||||
=== ADVERSARIAL PROBES (adapt to the change type) ===
|
||||
Functional tests confirm the happy path. Also try to break it:
|
||||
- **Concurrency** (servers/APIs): parallel requests to create-if-not-exists paths — duplicate sessions? lost writes?
|
||||
- **Boundary values**: 0, -1, empty string, very long strings, unicode, MAX_INT
|
||||
- **Idempotency**: same mutating request twice — duplicate created? error? correct no-op?
|
||||
- **Orphan operations**: delete/reference IDs that don't exist
|
||||
These are seeds, not a checklist — pick the ones that fit what you're verifying.
|
||||
|
||||
=== BEFORE ISSUING PASS ===
|
||||
Your report must include at least one adversarial probe you ran (concurrency, boundary, idempotency, orphan op, or similar) and its result — even if the result was "handled correctly." If all your checks are "returns 200" or "test suite passes," you have confirmed the happy path, not verified correctness. Go back and try to break something.
|
||||
|
||||
=== BEFORE ISSUING FAIL ===
|
||||
You found something that looks broken. Before reporting FAIL, check you haven't missed why it's actually fine:
|
||||
- **Already handled**: is there defensive code elsewhere (validation upstream, error recovery downstream) that prevents this?
|
||||
- **Intentional**: does CLAUDE.md / comments / commit message explain this as deliberate?
|
||||
- **Not actionable**: is this a real limitation but unfixable without breaking an external contract (stable API, protocol spec, backwards compat)? If so, note it as an observation, not a FAIL — a "bug" that can't be fixed isn't actionable.
|
||||
Don't use these as excuses to wave away real issues — but don't FAIL on intentional behavior either.
|
||||
|
||||
=== OUTPUT FORMAT (REQUIRED) ===
|
||||
Every check MUST follow this structure. A check without a Command run block is not a PASS — it's a skip.
|
||||
|
||||
\`\`\`
|
||||
### Check: [what you're verifying]
|
||||
**Command run:**
|
||||
[exact command you executed]
|
||||
**Output observed:**
|
||||
[actual terminal output — copy-paste, not paraphrased. Truncate if very long but keep the relevant part.]
|
||||
**Result: PASS** (or FAIL — with Expected vs Actual)
|
||||
\`\`\`
|
||||
|
||||
Bad (rejected):
|
||||
\`\`\`
|
||||
### Check: POST /api/register validation
|
||||
**Result: PASS**
|
||||
Evidence: Reviewed the route handler in routes/auth.py. The logic correctly validates
|
||||
email format and password length before DB insert.
|
||||
\`\`\`
|
||||
(No command run. Reading code is not verification.)
|
||||
|
||||
Good:
|
||||
\`\`\`
|
||||
### Check: POST /api/register rejects short password
|
||||
**Command run:**
|
||||
curl -s -X POST localhost:8000/api/register -H 'Content-Type: application/json' \\
|
||||
-d '{"email":"t@t.co","password":"short"}' | python3 -m json.tool
|
||||
**Output observed:**
|
||||
{
|
||||
"error": "password must be at least 8 characters"
|
||||
}
|
||||
(HTTP 400)
|
||||
**Expected vs Actual:** Expected 400 with password-length error. Got exactly that.
|
||||
**Result: PASS**
|
||||
\`\`\`
|
||||
|
||||
End with exactly this line (parsed by caller):
|
||||
|
||||
VERDICT: PASS
|
||||
or
|
||||
VERDICT: FAIL
|
||||
or
|
||||
VERDICT: PARTIAL
|
||||
|
||||
PARTIAL is for environmental limitations only (no test framework, tool unavailable, server can't start) — not for "I'm unsure whether this is a bug." If you can run the check, you must decide PASS or FAIL.
|
||||
|
||||
PARTIAL is NOT a hedge. "I found a hardcoded key and a TODO but they might be intentional" is FAIL — a hardcoded secret-pattern and an admitted-incomplete TODO are actionable findings regardless of intent. "The tests are circular but the implementer may have known" is FAIL — circular tests are a defect. PARTIAL means "I could not run the check at all," not "I ran it and the result is ambiguous."
|
||||
|
||||
Use the literal string \`VERDICT: \` followed by exactly one of \`PASS\`, \`FAIL\`, \`PARTIAL\`. No markdown bold, no punctuation, no variation.
|
||||
- **FAIL**: include what failed, exact error output, reproduction steps.
|
||||
- **PARTIAL**: what was verified, what could not be and why (missing tool/env), what the implementer should know.`})
|
||||
|
||||
function Wo6(){return L8("tengu_amber_stoat",!0)}function bN8(){if(c6(process.env.CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS)&&g7())return[];let q=[hU,LJ4];if(Wo6())q.push(LU,CN8);if(process.env.CLAUDE_CODE_ENTRYPOINT!=="sdk-ts"&&process.env.CLAUDE_CODE_ENTRYPOINT!=="sdk-py"&&process.env.CLAUDE_CODE_ENTRYPOINT!=="sdk-cli")q.push(yJ4);return q}var xN8=L(()=>{T8();l1();d8();Eu1();Xo6();Po6();Lu1();hJ4();RJ4()});var uJ4={};v8(uJ4,{parseAgentsFromJson:()=>Go6,parseAgentFromMarkdown:()=>IJ4,parseAgentFromJson:()=>xJ4,isPluginAgent:()=>fo6,isCustomAgent:()=>Do6,isBuiltInAgent:()=>F2,hasRequiredMcpServers:()=>IN8,getAgentDefinitionsWithOverrides:()=>iC,getActiveAgentsFromList:()=>FN,filterAgentsByMcpRequirements:()=>Zo6,clearAgentDefinitionsCache:()=>Ru1});import{basename as Un_}from"path";function F2(q){return q.source==="built-in"}function Do6(q){return q.source!=="built-in"&&q.source!=="plugin"}function fo6(q){return q.source==="plugin"}function FN(q){let K=q.filter((j)=>j.source==="built-in"),_=q.filter((j)=>j.source==="plugin"),z=q.filter((j)=>j.source==="userSettings"),Y=q.filter((j)=>j.source==="projectSettings"),$=q.filter((j)=>j.source==="policySettings"),O=q.filter((j)=>j.source==="flagSettings"),A=[K,_,z,Y,O,$],w=new Map;for(let j of A)for(let H of j)w.set(H.agentType,H);return Array.from(w.values())}function IN8(q,K){if(!q.requiredMcpServers||q.requiredMcpServers.length===0)return!0;return q.requiredMcpServers.every((_)=>K.some((z)=>z.toLowerCase().includes(_.toLowerCase())))}function Zo6(q,K){return q.filter((_)=>IN8(_,K))}function Ru1(){iC.cache.clear?.(),hN8()}function cn_(q){let{name:K,description:_}=q;if(!K||typeof K!=="string")return'Missing required "name" field in frontmatter';if(!_||typeof _!=="string")return'Missing required "description" field in frontmatter';return"Unknown parsing error"}function ln_(q,K){if(!q.hooks)return;let _=QR().safeParse(q.hooks);if(!_.success){N(`Invalid hooks in agent '${K}': ${_.error.message}`)
|
||||
|
||||
function jo_(q,K,_){var z=-1,Y=FX4,$=q.length,O=!0,A=[],w=A;if(_)O=!1,Y=QX4;else if($>=wo_){var j=K?null:cX4(q);if(j)return iX6(j);O=!1,Y=q98,w=new e38}else w=K?[]:A;q:while(++z<$){var H=q[z],J=K?K(H):H;if(H=_||H!==0?H:0,O&&J===J){var M=w.length;while(M--)if(w[M]===J)continue q;if(K)w.push(J);A.push(H)}else if(!Y(w,J,_)){if(w!==A)w.push(J);A.push(H)}}return A}var wo_=200,nX4;var iX4=L(()=>{Ir8();UX4();dX4();ur8();lX4();_98();nX4=jo_});function Ho_(q,K){return q&&q.length?nX4(q,PR(K,2)):[]}var U2;var Xm=L(()=>{h96();iX4();U2=Ho_});function bq6(){return{stateByDir:new Map,lastUsage:null}}function lo6(q){if(!q)return;q.stateByDir.clear(),q.lastUsage=null}function oX4(q,K){return q.stateByDir.get(K)}function aX4(q,K,_,z,Y){let $={memories:_,byFilename:new Map(_.map((O)=>[O.filename,O])),messages:[{role:"user",content:[{type:"text",text:`Available memories:
|
||||
${z}`,...Y&&{cache_control:Y}}]}]};return q.stateByDir.set(K,$),$}function sX4(q,K,_,z){let Y=q.stateByDir.get(K);if(!Y)return;q.stateByDir.set(K,{...Y,messages:[...Y.messages,{role:"user",content:[{type:"text",text:_}]},{role:"assistant",content:[{type:"text",text:z}]}]})}var rX4="memdir_relevance";var KP4={};v8(KP4,{outputSchema:()=>qP4,inputSchema:()=>eX4,clearToolSearchDescriptionCache:()=>Xo_,ToolSearchTool:()=>no6});function Jo_(q){return q.map((K)=>K.name).sort().join(",")}function Mo_(q){let K=Jo_(q);if(Tm1!==K)N("ToolSearchTool: cache invalidated - deferred tools changed"),Yy8.cache.clear?.(),Tm1=K}function Xo_(){Yy8.cache.clear?.(),Tm1=null}function zy8(q,K,_,z){return{data:{matches:q,query:K,total_deferred_tools:_,...z&&z.length>0?{pending_mcp_servers:z}:{}}}}function tX4(q){if(q.startsWith("mcp__")){let _=q.replace(/^mcp__/,"").toLowerCase();return{parts:_.split("__").flatMap((Y)=>Y.split("_")).filter(Boolean),full:_.replace(/__/g," ").replace(/_/g," "),isMcp:!0}}let K=q.replace(/([a-z])([A-Z])/g,"$1 $2").replace(/_/g," ").toLowerCase().split(/\s+/).filter(Boolean);return{parts:K,full:K.join(" "),isMcp:!1}}function Po_(q){let K=new Map
|
||||
|
||||
for(let _ of q)if(!K.has(_))K.set(_,new RegExp(`\\b${FD6(_)}\\b`));return K}async function Wo_(q,K,_,z){let Y=q.toLowerCase().trim(),$=K.find((X)=>X.name.toLowerCase()===Y)??_.find((X)=>X.name.toLowerCase()===Y);if($)return[$.name];if(Y.startsWith("mcp__")&&Y.length>5){let X=K.filter((P)=>P.name.toLowerCase().startsWith(Y)).slice(0,z).map((P)=>P.name);if(X.length>0)return X}let O=Y.split(/\s+/).filter((X)=>X.length>0),A=[],w=[];for(let X of O)if(X.startsWith("+")&&X.length>1)A.push(X.slice(1));else w.push(X);let j=A.length>0?[...A,...w]:O,H=Po_(j),J=K;if(A.length>0)J=(await Promise.all(K.map(async(P)=>{let W=tX4(P.name),f=(await Yy8(P.name,_)).toLowerCase(),G=P.searchHint?.toLowerCase()??"";return A.every((v)=>{let k=H.get(v);return W.parts.includes(v)||W.parts.some((V)=>V.includes(v))||k.test(f)||G&&k.test(G)})?P:null}))).filter((P)=>P!==null);return(await Promise.all(J.map(async(X)=>{let P=tX4(X.name),D=(await Yy8(X.name,_)).toLowerCase(),f=X.searchHint?.toLowerCase()??"",G=0;for(let Z of j){let v=H.get(Z);if(P.parts.includes(Z))G+=P.isMcp?12:10;else if(P.parts.some((k)=>k.includes(Z)))G+=P.isMcp?6:5;if(P.full.includes(Z)&&G===0)G+=3;if(f&&v.test(f))G+=4;if(v.test(D))G+=2}return{name:X.name,score:G}}))).filter((X)=>X.score>0).sort((X,P)=>P.score-X.score).slice(0,z).map((X)=>X.name)}var eX4,qP4,Tm1=null,Yy8,no6;var $y8=L(()=>{c4();u7();k8();aq();_8();eC();CU();eX4=p6(()=>h.object({query:h.string().describe('Query to find deferred tools. Use "select:<tool_name>" for direct selection, or keywords to search.'),max_results:h.number().optional().default(5).describe("Maximum number of results to return (default: 5)")})),qP4=p6(()=>h.object({matches:h.array(h.string()),query:h.string(),total_deferred_tools:h.number(),pending_mcp_servers:h.array(h.string()).optional()}));Yy8=$1(async(q,K)=>{let _=sK(K,q);if(!_)return""
|
||||
|
||||
if(w.length>0)K.onAppsHidden?.(w)}let Y=await q.executor.getFrontmostApp(),$=new Map(K.allowedApps.map((w)=>[w.bundleId,w.tier])),O=Y?$.get(Y.bundleId):void 0;if(_.clipboardGuard)await Uy8(q,K,O==="click");if(!Y)return null;let{hostBundleId:A}=q.executor.capabilities;if(O!==void 0){if(vf4(O,z))return null;if(O==="read"){let w=aV6(Y.bundleId,Y.displayName)==="browser";return _4(`"${Y.displayName}" is granted at tier "read" — `+"visible in screenshots only, no clicks or typing."+(w?" Use the Claude-in-Chrome MCP for browser interaction (tools named `mcp__Claude_in_Chrome__*`; load via ToolSearch if deferred).":" No interaction is permitted; ask the user to take any actions in this app themselves.")+Nw6,"tier_insufficient")}if(z==="keyboard")return _4(`"${Y.displayName}" is granted at tier "click" — `+`typing, key presses, and paste require tier "full". The keys would go to this app's text fields or integrated terminal. To type into a different app, click it first to bring it forward. For shell commands, use the Bash tool.`+Nw6,"tier_insufficient");return _4(`"${Y.displayName}" is granted at tier "click" — `+'right-click, middle-click, and clicks with modifier keys require tier "full". Right-click opens a context menu with Paste/Cut, and modifier chords fire as keystrokes before the click. Plain left_click is allowed here.'+Nw6,"tier_insufficient")}if(Y.bundleId===Gf4)return null;if(Y.bundleId===A){if(z!=="keyboard")return null;return _4("Claude's own window still has keyboard focus. This should not happen after the pre-action defocus. Click on the target application first.","state_conflict")}return _4(`"${Y.displayName}" is not in the allowed applications and is `+"currently in front. Take a new screenshot — it may have appeared "+"since your last one.","app_not_granted")}async function yw6(q,K,_,z,Y,$){let O=await q.executor.appUnderPoint(z,Y);if(!O)return null;if(O.bundleId===Gf4)return null;let A=new Map(K.allowedApps.map((H)=>[H.bundleId,H.tier]))
|
||||
|
||||
for(let Z of P){if(!Z.resolved)continue;try{Z.resolved.iconDataUrl=await q.executor.getAppIcon(Z.resolved.path)}catch{}}let W=Date.now(),D=X.filter((Z)=>Z.resolved).map((Z)=>{return _.find((k)=>k.bundleId===Z.resolved.bundleId)??{bundleId:Z.resolved.bundleId,displayName:Z.resolved.displayName,grantedAt:W,tier:Z.proposedTier}}),f=[..._.map((Z)=>Z.bundleId),...J.filter((Z)=>Z.resolved).map((Z)=>Z.resolved.bundleId)],G=await q.executor.previewHideSet(f,Y);return{needDialog:P,skipDialogGrants:D,willHide:G,tieredApps:M,userDenied:H,policyDenied:w}}function Nf4(q){let K=q.filter(($)=>$.tier==="read"&&aV6($.bundleId,$.displayName)==="browser"),_=q.filter(($)=>$.tier==="read"&&aV6($.bundleId,$.displayName)!=="browser"),z=q.filter(($)=>$.tier==="click"),Y=[];if(K.length>0){let $=K.map((O)=>`"${O.displayName}"`).join(", ");Y.push(`${$} ${K.length===1?"is a browser":"are browsers"} — `+`granted at tier "read" (visible in screenshots only; no clicks or typing). You can read what's on screen but cannot navigate, click, or type into ${K.length===1?"it":"them"}. For browser interaction, use the Claude-in-Chrome MCP (tools named \`mcp__Claude_in_Chrome__*\`; load via ToolSearch if deferred).`)}if(_.length>0){let $=_.map((O)=>`"${O.displayName}"`).join(", ");Y.push(`${$} ${_.length===1?"is":"are"} granted at tier "read" (visible in screenshots only; no clicks or typing). You can read what's on screen but cannot interact. Ask the user to take any actions in ${_.length===1?"this app":"these apps"} themselves.`)}if(z.length>0){let $=z.map((O)=>`"${O.displayName}"`).join(", ");Y.push(`${$} ${z.length===1?"has":"have"} terminal or IDE `+'capabilities — granted at tier "click" (visible + plain left-click '+`only
|
||||
|
||||
one-shot tasks landing on :00 or :30 fire up to 90 s early. Picking an off-minute is still the bigger lever.
|
||||
|
||||
Recurring tasks auto-expire after ${O46} days — they fire one final time, then are deleted. This bounds session lifetime. Tell the user about the ${O46}-day limit when scheduling recurring jobs.
|
||||
|
||||
Returns a job ID you can pass to ${A46}.`}function pg1(q){return q?`Cancel a cron job previously scheduled with ${qy}. Removes it from .claude/scheduled_tasks.json (durable jobs) or the in-memory session store (session-only jobs).`:`Cancel a cron job previously scheduled with ${qy}. Removes it from the in-memory session store.`}function gg1(q){return q?`List all cron jobs scheduled via ${qy}, both durable (.claude/scheduled_tasks.json) and session-only.`:`List all cron jobs scheduled via ${qy} in this session.`}var MR4=300000,O46,qy="CronCreate",A46="CronDelete",ws6="CronList",mg1="Cancel a scheduled cron job by ID",Bg1="List scheduled cron jobs";var HQ=L(()=>{l1();$46();d8();O46=jQ.recurringMaxAgeMs/86400000});var bN6,Fg1,TL8,WR4,DR4;var js6=L(()=>{UY();wQ();ZY();PV6();bX();Vq6();Y2();CU();OQ();lP();HQ();bN6=new Set([EV,UX,_46,H4,OO,jg]),Fg1=new Set([...bN6]),TL8=new Set([pq,gL,Jb,$9,mj,Z_,...Mw6,N4,xK,WD,kM,zW,tP,ZL8,GL8,Rj]),WR4=new Set([eN,z46,Y46,oL,aP,qy,A46,ws6]),DR4=new Set([H4,jg,aP,zW,...[]])});var ym="TeamCreate";var aw6="TeamDelete";function xN6(){return!1}var Hs6=L(()=>{js6();l1();k8();UY();ZY();OQ();d8()});class Ug1{constructor(q){this._client=q}async*callToolStream(q,K=lB,_){let z=this._client,Y={..._,task:_?.task??(z.isToolTask(q.name)?{}:void 0)},$=z.requestStream({method:"tools/call",params:q},K,Y),O=z.getToolOutputValidator(q.name);for await(let A of $){if(A.type==="result"&&O){let w=A.result;if(!w.structuredContent&&!w.isError){yield{type:"error",error:new GK(z5.InvalidRequest,`Tool ${q.name} has an output schema but did not return structured content`)};return}if(w.structuredContent)try{let j=O(w.structuredContent)
|
||||
|
||||
if(!j.valid){yield{type:"error",error:new GK(z5.InvalidParams,`Structured content does not match the tool's output schema: ${j.errorMessage}`)};return}}catch(j){if(j instanceof GK){yield{type:"error",error:j};return}yield{type:"error",error:new GK(z5.InvalidParams,`Failed to validate structured content: ${j instanceof Error?j.message:String(j)}`)};return}}yield A}}async getTask(q,K){return this._client.getTask({taskId:q},K)}async getTaskResult(q,K,_){return this._client.getTaskResult({taskId:q},K,_)}async listTasks(q,K){return this._client.listTasks(q?{cursor:q}:void 0,K)}async cancelTask(q,K){return this._client.cancelTask({taskId:q},K)}requestStream(q,K,_){return this._client.requestStream(q,K,_)}}var fR4=L(()=>{HX()});function kL8(q,K){if(!q||K===null||typeof K!=="object")return;if(q.type==="object"&&q.properties&&typeof q.properties==="object"){let _=K,z=q.properties;for(let Y of Object.keys(z)){let $=z[Y];if(_[Y]===void 0&&Object.prototype.hasOwnProperty.call($,"default"))_[Y]=$.default;if(_[Y]!==void 0)kL8($,_[Y])}}if(Array.isArray(q.anyOf)){for(let _ of q.anyOf)if(typeof _!=="boolean")kL8(_,K)}if(Array.isArray(q.oneOf)){for(let _ of q.oneOf)if(typeof _!=="boolean")kL8(_,K)}}function z2z(q){if(!q)return{supportsFormMode:!1,supportsUrlMode:!1};let K=q.form!==void 0,_=q.url!==void 0;return{supportsFormMode:K||!K&&!_,supportsUrlMode:_}}var VL8;var ZR4=L(()=>{l71();HX();iq1();Gm6();fR4();VL8=class VL8 extends im6{constructor(q,K){super(K);if(this._clientInfo=q,this._cachedToolOutputValidators=new Map,this._cachedKnownTaskTools=new Set,this._cachedRequiredTaskTools=new Set,this._listChangedDebounceTimers=new Map,this._capabilities=K?.capabilities??{},this._jsonSchemaValidator=K?.jsonSchemaValidator??new fp6,K?.listChanged)this._pendingListChangedConfig=K.listChanged}_setupListChangedHandlers(q){if(q.tools&&this._serverCapabilities?.tools?.listChanged)this._setupListChangedHandler("tools",Qm6,q.tools,async()=>{return(await this.listTools()).tools})
|
||||
|
||||
C$8(this._capabilities.tasks?.requests,q,"Client")}async ping(q){return this.request({method:"ping"},Fl,q)}async complete(q,K){return this.request({method:"completion/complete",params:q},f71,K)}async setLoggingLevel(q,K){return this.request({method:"logging/setLevel",params:{level:q}},Fl,K)}async getPrompt(q,K){return this.request({method:"prompts/get",params:q},P71,K)}async listPrompts(q,K){return this.request({method:"prompts/list",params:q},gm6,K)}async listResources(q,K){return this.request({method:"resources/list",params:q},mm6,K)}async listResourceTemplates(q,K){return this.request({method:"resources/templates/list",params:q},w71,K)}async readResource(q,K){return this.request({method:"resources/read",params:q},pm6,K)}async subscribeResource(q,K){return this.request({method:"resources/subscribe",params:q},Fl,K)}async unsubscribeResource(q,K){return this.request({method:"resources/unsubscribe",params:q},Fl,K)}async callTool(q,K=lB,_){if(this.isToolTaskRequired(q.name))throw new GK(z5.InvalidRequest,`Tool "${q.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);let z=await this.request({method:"tools/call",params:q},K,_),Y=this.getToolOutputValidator(q.name);if(Y){if(!z.structuredContent&&!z.isError)throw new GK(z5.InvalidRequest,`Tool ${q.name} has an output schema but did not return structured content`);if(z.structuredContent)try{let $=Y(z.structuredContent);if(!$.valid)throw new GK(z5.InvalidParams,`Structured content does not match the tool's output schema: ${$.errorMessage}`)}catch($){if($ instanceof GK)throw $;throw new GK(z5.InvalidParams,`Failed to validate structured content: ${$ instanceof Error?$.message:String($)}`)}}return z}isToolTask(q){if(!this._serverCapabilities?.tasks?.requests?.tools?.call)return!1;return this._cachedKnownTaskTools.has(q)}isToolTaskRequired(q){return this._cachedRequiredTaskTools.has(q)}cacheToolMetadata(q){this._cachedToolOutputValidators.clear(),this._cachedKnownTaskTools.clear(),this._cachedRequiredTaskTools.clear()
|
||||
|
||||
for(let K of q){if(K.outputSchema){let z=this._jsonSchemaValidator.getValidator(K.outputSchema);this._cachedToolOutputValidators.set(K.name,z)}let _=K.execution?.taskSupport;if(_==="required"||_==="optional")this._cachedKnownTaskTools.add(K.name);if(_==="required")this._cachedRequiredTaskTools.add(K.name)}}getToolOutputValidator(q){return this._cachedToolOutputValidators.get(q)}async listTools(q,K){let _=await this.request({method:"tools/list",params:q},Um6,K);return this.cacheToolMetadata(_.tools),_}_setupListChangedHandler(q,K,_,z){let Y=VZ7.safeParse(_);if(!Y.success)throw Error(`Invalid ${q} listChanged options: ${Y.error.message}`);if(typeof _.onChanged!=="function")throw Error(`Invalid ${q} listChanged options: onChanged must be a function`);let{autoRefresh:$,debounceMs:O}=Y.data,{onChanged:A}=_,w=async()=>{if(!$){A(null,null);return}try{let H=await z();A(null,H)}catch(H){let J=H instanceof Error?H:Error(String(H));A(J,null)}},j=()=>{if(O){let H=this._listChangedDebounceTimers.get(q);if(H)clearTimeout(H);let J=setTimeout(w,O);this._listChangedDebounceTimers.set(q,J)}else w()};this.setNotificationHandler(K,j)}async sendRootsListChanged(){return this.notification({method:"notifications/roots/list_changed"})}}});function Qg1(q){}function NL8(q){if(typeof q=="function")throw TypeError("`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?");let{onEvent:K=Qg1,onError:_=Qg1,onRetry:z=Qg1,onComment:Y}=q,$="",O=!0,A,w="",j="";function H(W){let D=O?W.replace(/^\xEF\xBB\xBF/,""):W,[f,G]=Y2z(`${$}${D}`);for(let Z of f)J(Z);$=G,O=!1}function J(W){if(W===""){X();return}if(W.startsWith(":")){Y&&Y(W.slice(W.startsWith(": ")?2:1));return}let D=W.indexOf(":");if(D!==-1){let f=W.slice(0,D),G=W[D+1]===" "?2:1,Z=W.slice(D+G);M(f,Z,W);return}M(W,"",W)}function M(W,D,f){switch(W){case"event":j=D;break;case"data":w=`${w}${D}
|
||||
`;break;case"id":A=D.includes("\x00")?void 0:D;break
|
||||
|
||||
let A=M26(O);if(A&&!_.has(A))_.set(A,$)}let z={},Y=[];for(let[$,O]of Object.entries(q)){let A=M26(O),w=A!==null?_.get(A):void 0;if(w!==void 0){N(`Suppressing claude.ai connector "${$}": duplicates manually-configured "${w}"`),Y.push({name:$,duplicateOf:w});continue}z[$]=O}return{servers:z,suppressed:Y}}function bJz(q){let _=q.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${_}$`)}function pC4(q,K){return bJz(K).test(q)}function xJz(){if(mJz())return V1("policySettings")??{};return v7()}function IJz(){return v7()}function BC4(q,K){let _=IJz();if(!_.deniedMcpServers)return!1;for(let z of _.deniedMcpServers)if(QD6(z)&&z.serverName===q)return!0;if(K){let z=oF1(K);if(z){for(let $ of _.deniedMcpServers)if(Jw8($)&&mC4($.serverCommand,z))return!0}let Y=aF1(K);if(Y){for(let $ of _.deniedMcpServers)if(Mw8($)&&pC4(Y,$.serverUrl))return!0}}return!1}function $y6(q,K){if(BC4(q,K))return!1;let _=xJz();if(!_.allowedMcpServers)return!0;if(_.allowedMcpServers.length===0)return!1;let z=_.allowedMcpServers.some(Jw8),Y=_.allowedMcpServers.some(Mw8);if(K){let $=oF1(K),O=aF1(K);if($)if(z){for(let A of _.allowedMcpServers)if(Jw8(A)&&mC4(A.serverCommand,$))return!0;return!1}else{for(let A of _.allowedMcpServers)if(QD6(A)&&A.serverName===q)return!0;return!1}else if(O)if(Y){for(let A of _.allowedMcpServers)if(Mw8(A)&&pC4(O,A.serverUrl))return!0;return!1}else{for(let A of _.allowedMcpServers)if(QD6(A)&&A.serverName===q)return!0;return!1}else{for(let A of _.allowedMcpServers)if(QD6(A)&&A.serverName===q)return!0;return!1}}for(let $ of _.allowedMcpServers)if(QD6($)&&$.serverName===q)return!0;return!1}function D46(q){let K={},_=[];for(let[z,Y]of Object.entries(q)){let $=Y;if($.type==="sdk"||$y6(z,$))K[z]=Y;else _.push(z)}return{allowed:K,blocked:_}}function uJz(q){let K=[];function _(Y){let{expanded:$,missingVars:O}=_y6(Y);return K.push(...O),$}let z;switch(q.type){case void 0:case"stdio":{let Y=q;z={...Y,command:_(Y.command),args:Y.args.map(_),env:Y.env?SC(Y.env,_):void 0}
|
||||
|
||||
return q.filter((z)=>z.name?.startsWith(_))}function PQ(q,K){let _=V2(K),z=q.name;if(!z)return!1;return z.startsWith(`mcp__${_}__`)||z.startsWith(`${_}:`)}function xh8(q,K){return q.filter((_)=>PQ(_,K)&&!(_.type==="prompt"&&_.loadedFrom==="mcp"))}function Ih8(q,K){let _=`mcp__${V2(K)}__`;return q.filter((z)=>!z.name?.startsWith(_))}function wy6(q,K){return q.filter((_)=>!PQ(_,K))}function jy6(q,K){let _={...q};return delete _[K],_}function FC4(q){let{scope:K,..._}=q,z=g6(_,(Y,$)=>{if($&&typeof $==="object"&&!Array.isArray($)){let O=$,A={};for(let w of Object.keys(O).sort())A[w]=O[w];return A}return $});return pJz("sha256").update(z).digest("hex").slice(0,16)}function UC4(q,K){let _=q.clients.filter((A)=>{let w=K[A.name];if(!w)return A.config.scope==="dynamic";return FC4(A.config)!==FC4(w)});if(_.length===0)return{...q,stale:[]};let{tools:z,commands:Y,resources:$}=q;for(let A of _)z=Ih8(z,A.name),Y=wy6(Y,A.name),$=jy6($,A.name);let O=new Set(_.map((A)=>A.name));return{clients:q.clients.filter((A)=>!O.has(A.name)),tools:z,commands:Y,resources:$,stale:_}}function Tk(q){return q.name?.startsWith("mcp__")||q.isMcp===!0}function _v(q){switch(q){case"user":return xP();case"project":return BJz(Z8(),".mcp.json");case"local":return`${xP()} [project: ${Z8()}]`;case"dynamic":return"Dynamically configured";case"enterprise":return Ch8();case"claudeai":return"claude.ai";default:return q}}function ms6(q){switch(q){case"local":return"Local config (private to you in this project)";case"project":return"Project config (shared via .mcp.json)";case"user":return"User config (available in all your projects)";case"dynamic":return"Dynamic config (from command line)";case"enterprise":return"Enterprise config (managed by your organization)";case"claudeai":return"claude.ai config";default:return q}}function Hy6(q){if(!q)return"local";if(!v31().options.includes(q))throw Error(`Invalid scope: ${q}. Must be one of: ${v31().options.join(", ")}`);return q}function QC4(q){if(!q)return"stdio"
|
||||
|
||||
if(q!=="stdio"&&q!=="sse"&&q!=="http")throw Error(`Invalid transport type: ${q}. Must be one of: stdio, sse, http`);return q}function tF1(q){let K={};for(let _ of q){let z=_.indexOf(":");if(z===-1)throw Error(`Invalid header format: "${_}". Expected format: "Header-Name: value"`);let Y=_.substring(0,z).trim(),$=_.substring(z+1).trim();if(!Y)throw Error(`Invalid header: "${_}". Header name cannot be empty.`);K[Y]=$}return K}function bh8(q){let K=k7(),_=V2(q);if(K?.disabledMcpjsonServers?.some((z)=>V2(z)===_))return"rejected";if(K?.enabledMcpjsonServers?.some((z)=>V2(z)===_)||K?.enableAllProjectMcpServers)return"approved";if(rD6()&&WJ("projectSettings"))return"approved";if(g7()&&WJ("projectSettings"))return"approved";return"pending"}function eF1(q){if(!Tk({name:q}))return null;let K=NV(q);if(!K)return null;let _=$y(K.serverName);if(!_&&K.serverName.startsWith("claude_ai_"))return"claudeai";return _?.scope??null}function gJz(q){return q.type==="stdio"||q.type===void 0}function FJz(q){return q.type==="sse"}function UJz(q){return q.type==="http"}function QJz(q){return q.type==="ws"}function dC4(q){let K=new Map;for(let z of q){if(!z.mcpServers?.length)continue;for(let Y of z.mcpServers){if(typeof Y==="string")continue;let $=Object.entries(Y);if($.length!==1)continue;let[O,A]=$[0],w=K.get(O);if(w){if(!w.sourceAgents.includes(z.agentType))w.sourceAgents.push(z.agentType)}else K.set(O,{config:{...A,name:O},sourceAgents:[z.agentType]})}}let _=[];for(let[z,{config:Y,sourceAgents:$}]of K)if(gJz(Y))_.push({name:z,sourceAgents:$,transport:"stdio",command:Y.command,needsAuth:!1});else if(FJz(Y))_.push({name:z,sourceAgents:$,transport:"sse",url:Y.url,needsAuth:!0});else if(UJz(Y))_.push({name:z,sourceAgents:$,transport:"http",url:Y.url,needsAuth:!0});else if(QJz(Y))_.push({name:z,sourceAgents:$,transport:"ws",url:Y.url,needsAuth:!1});return _.sort((z,Y)=>z.name.localeCompare(Y.name))}function Oy(q){if(!("url"in q)||typeof q.url!=="string")return;try{let K=new URL(q.url)
|
||||
|
||||
var WI4=L(()=>{FPz=["/Applications/","/System/Applications/"],UPz=[/Helper(?:$|\s\()/,/Agent(?:$|\s\()/,/Service(?:$|\s\()/,/Uninstaller(?:$|\s\()/,/Updater(?:$|\s\()/,/^\./],QPz=new Set(["com.apple.Safari","com.google.Chrome","com.microsoft.edgemac","org.mozilla.firefox","company.thebrowser.Browser","com.tinyspeck.slackmacgap","us.zoom.xos","com.microsoft.teams2","com.microsoft.teams","com.apple.MobileSMS","com.apple.mail","com.microsoft.Word","com.microsoft.Excel","com.microsoft.Powerpoint","com.microsoft.Outlook","com.apple.iWork.Pages","com.apple.iWork.Numbers","com.apple.iWork.Keynote","com.google.GoogleDocs","notion.id","com.apple.Notes","md.obsidian","com.linear","com.figma.Desktop","com.microsoft.VSCode","com.apple.Terminal","com.googlecode.iterm2","com.github.GitHubDesktop","com.apple.finder","com.apple.iCal","com.apple.systempreferences"]),dPz=/^[\p{L}\p{M}\p{N}_ .&'()+-]+$/u});var UU1={};v8(UU1,{runComputerUseMcpServer:()=>aPz,createComputerUseMcpServerForCli:()=>fI4});import{homedir as rPz}from"os";async function oPz(){let K=Yt6().executor.listInstalledApps(),_,z=new Promise(($)=>{_=setTimeout($,DI4,void 0)}),Y=await Promise.race([K,z]).catch(()=>{return}).finally(()=>clearTimeout(_));if(!Y){K.catch(()=>{}),N(`[Computer Use MCP] app enumeration exceeded ${DI4}ms or failed; tool description omits list`);return}return PI4(Y,rPz())}async function fI4(){let q=Yt6(),K=Sy6(),_=vp1(q,K),z=await oPz(),Y=Ew6(q.executor.capabilities,K,z);return _.setRequestHandler(Ql,async()=>q.isDisabled()?{tools:[]}:{tools:Y}),_}async function aPz(){RO6(),hv6();let q=await fI4(),K=new y_6,_=!1,z=async()=>{if(_)return;_=!0,await Promise.all([zr(),K76()]),process.exit(0)};process.stdin.on("end",()=>void z()),process.stdin.on("error",()=>void z()),N("[Computer Use MCP] Starting MCP server"),await q.connect(K),N("[Computer Use MCP] MCP server started")}var DI4=1000;var QU1=L(()=>{Ha6();u$8();HX();Lv6();Yr();el6();k1();_8();WI4();Cy6();BU1()});import{mkdir as KWz,readFile as _Wz,unlink as zWz,writeFile as YWz}from"fs/promises"
|
||||
|
||||
let A=_?.signal,w=()=>$.abort(A?.reason);if(A?.addEventListener("abort",w),A?.aborted)$.abort(A.reason);let j=()=>{clearTimeout(O),A?.removeEventListener("abort",w)};try{let H=await q(K,{..._,headers:Y,signal:$.signal});return j(),H}catch(H){throw j(),H}}}function aU1(){return parseInt(process.env.MCP_SERVER_CONNECTION_BATCH_SIZE||"",10)||3}function XWz(){return parseInt(process.env.MCP_REMOTE_SERVER_CONNECTION_BATCH_SIZE||"",10)||20}function vI4(q){return!q.type||q.type==="stdio"||q.type==="sdk"}function WWz(q){return!q.name.startsWith("mcp__ide__")||PWz.includes(q.name)}function nU1(q,K){return`${q}-${g6(K)}`}async function $v(q,K){let _=nU1(q,K);try{let z=await Tb(q,K);if(z.type==="connected")await z.cleanup()}catch{}Tb.cache.delete(_),eL.cache.delete(q),uo.cache.delete(q),v26.cache.delete(q)}async function eN6(q){if(q.config.type==="sdk")return q;let K=await Tb(q.name,q.config);if(K.type!=="connected")throw new JV(`MCP server "${q.name}" is not connected`,"MCP server not connected");return K}function EI4(q,K){if(q.type!==K.type)return!1;let{scope:_,...z}=q,{scope:Y,...$}=K;return g6(z)===g6($)}function DWz(q,K){let _=Object.keys(q);return _.length>0?_.map((z)=>`${z}=${String(q[z])}`).join(" "):K}async function xm(q,K,_){return(await hI4({client:_,tool:q,args:K,signal:A3().signal})).content}async function Sm(q,K){try{rV(),await $v(q,K);let _=await Tb(q,K);if(_.type!=="connected")return{client:_,tools:[],commands:[]};if(K.type==="claudeai-proxy")lF1(q);let z=!!_.capabilities?.resources,[Y,$,O,A]=await Promise.all([eL(_),v26(_),Promise.resolve([]),z?uo(_):Promise.resolve([])]),w=[...$,...O],j=[];if(z){if(![Io,Uo].some((J)=>Y.some((M)=>a_(M,J.name))))j.push(Io,Uo)}return{client:_,tools:[...Y,...j],commands:w,resources:A.length>0?A:void 0}}catch(_){return oz(q,`Error during reconnection: ${F6(_)}`),{client:{name:q,type:"failed",config:K},tools:[],commands:[]}}}async function TI4(q,K,_){await fs6(q,_,{concurrency:K})}async function by6(q,K){let _=!1,z=Object.entries(K??(await Z46()).servers),Y=[]
|
||||
|
||||
return`{${z.join(", ")}${Y}}`}return typeof q}async function fWz(q,K,_){if(q&&typeof q==="object"){if("toolResult"in q)return{content:String(q.toolResult),type:"toolResult"};if("structuredContent"in q&&q.structuredContent!==void 0)return{content:g6(q.structuredContent),type:"structuredContent",schema:vR8(q.structuredContent)};if("content"in q&&Array.isArray(q.content)){let Y=(await Promise.all(q.content.map(($)=>LI4($,_)))).flat();return{content:Y,type:"contentArray",schema:vR8(Y)}}}let z=`MCP server "${_}" tool "${K}": unexpected response format`;throw oz(_,z),new JV(z,"MCP tool unexpected response format")}function ZWz(q){if(!q||typeof q==="string")return!1;return q.some((K)=>K.type==="image")}async function GWz(q,K,_){let{content:z,type:Y,schema:$}=await fWz(q,K,_);if(_==="ide")return z;if(!await hF1(z))return z;let O=Ls6(z);if(d_(process.env.ENABLE_MCP_LARGE_OUTPUT_FILES))return d("tengu_mcp_large_result_handled",{outcome:"truncated",reason:"env_disabled",sizeEstimateTokens:O}),await RF1(z);if(!z)return z;if(ZWz(z))return d("tengu_mcp_large_result_handled",{outcome:"truncated",reason:"contains_images",sizeEstimateTokens:O}),await RF1(z);let A=Date.now(),w=`mcp-${V2(_)}-${V2(K)}-${A}`,j=typeof z==="string"?z:g6(z,null,2),H=await Xy6(j,w);if(Wy6(H)){let M=j.length;return d("tengu_mcp_large_result_handled",{outcome:"truncated",reason:"persist_failed",sizeEstimateTokens:O}),`Error: result (${M.toLocaleString()} characters) exceeds maximum allowed tokens. Failed to save output to file: ${H.error}. If this MCP server provides pagination or filtering tools, use them to retrieve specific portions of the data.`}d("tengu_mcp_large_result_handled",{outcome:"persisted",reason:"file_saved",sizeEstimateTokens:O,persistedSizeChars:H.originalSize});let J=fb4(Y,$);return Zb4(H.filepath,H.originalSize,J)}async function vWz({client:q,clientConnection:K,tool:_,args:z,meta:Y,signal:$,setAppState:O,onProgress:A,callToolFn:w=hI4,handleElicitation:j}){for(let J=0;
|
||||
|
||||
m8(D,`Elicitation ${G} completed, retrying tool call`)}}}async function hI4({client:{client:q,name:K,config:_},tool:z,args:Y,meta:$,signal:O,onProgress:A}){let w=Date.now(),j;try{m8(K,`Calling MCP tool: ${z}`),j=setInterval((G,Z,v)=>{let k=Date.now()-G,y=`${Math.floor(k/1000)}s`;m8(Z,`Tool '${v}' still running (${y} elapsed)`)},30000,w,K,z);let H=tPz(),J,M=new Promise((G,Z)=>{J=setTimeout((v,k,V,y)=>{v(new JV(`MCP server "${k}" tool "${V}" timed out after ${Math.floor(y/1000)}s`,"MCP tool timeout"))},H,Z,K,z,H)}),X=await Promise.race([q.callTool({name:z,arguments:Y,_meta:$},lB,{signal:O,timeout:H,onprogress:A?(G)=>{A({type:"mcp_progress",status:"progress",serverName:K,toolName:z,progress:G.progress,total:G.total,progressMessage:G.message})}:void 0}),M]).finally(()=>{if(J)clearTimeout(J)});if("isError"in X&&X.isError){let G="Unknown error";if("content"in X&&Array.isArray(X.content)&&X.content.length>0){let Z=X.content.filter((v)=>v!=null&&typeof v==="object"&&("text"in v)).map((v)=>v.text);if(Z.length>0)G=Z.join(`
|
||||
`)}else if("error"in X)G=String(X.error);throw oz(K,G),new kR8(G,"MCP tool returned error","_meta"in X&&X._meta?{_meta:X._meta}:void 0)}let P=Date.now()-w,W=P<1000?`${P}ms`:P<60000?`${Math.floor(P/1000)}s`:`${Math.floor(P/60000)}m ${Math.floor(P%60000/1000)}s`;m8(K,`Tool '${z}' completed successfully in ${W}`);let D=Lb4(K);if(D)d("tengu_code_indexing_tool_used",{tool:D,source:"mcp",success:!0});return{content:await GWz(X,z,K),_meta:X._meta,structuredContent:X.structuredContent}}catch(H){if(j!==void 0)clearInterval(j);let J=Date.now()-w;if(H instanceof Error&&H.name!=="AbortError")m8(K,`Tool '${z}' failed after ${Math.floor(J/1000)}s: ${H.message}`);if(H instanceof Error){if(("code"in H?H.code:void 0)===401||H instanceof pD)throw m8(K,"Tool call returned 401 Unauthorized - token may have expired"),d("tengu_mcp_tool_call_auth_error",{}),new TR8(K,`MCP server "${K}" requires re-authorization (token expired)`)
|
||||
|
||||
yM();q26();yx4();GY6();go();Yy6();nZ();Ex4();Rm();_r();d8();r8();TR8=class TR8 extends Error{serverName;constructor(q,K){super(K);this.name="McpAuthError",this.serverName=q}};rU1=class rU1 extends Error{constructor(q){super(`MCP server "${q}" session expired`);this.name="McpSessionExpiredError"}};kR8=class kR8 extends JV{mcpMeta;constructor(q,K,_){super(q,K);this.mcpMeta=_;this.name="McpToolCallError"}};ZI4=Promise.resolve();JWz=new Set(["image/jpeg","image/png","image/gif","image/webp"]);PWz=["mcp__ide__executeCode","mcp__ide__getDiagnostics"];Tb=$1(async(q,K,_)=>{let z=Date.now(),Y;try{let $,O=FD();if(K.type==="sse"){let p=new W26(q,K),C=await zR8(q,K),g={authProvider:p,fetch:cU1($U1(tw6(),p)),requestInit:{headers:{"User-Agent":Q16(),...C}}};g.eventSourceInit={fetch:async(F,U)=>{let c={},K6=await p.tokens();if(K6)c.Authorization=`Bearer ${K6.access_token}`;let o=zY6();return fetch(F,{...U,...o,headers:{"User-Agent":Q16(),...c,...U?.headers,...C,Accept:"text/event-stream"}})}},$=new UL8(new URL(K.url),g),m8(q,"SSE transport initialized, awaiting connection")}else if(K.type==="sse-ide"){m8(q,`Setting up SSE-IDE transport to ${K.url}`);let p=zY6(),C=p.dispatcher?{eventSourceInit:{fetch:async(g,F)=>{return fetch(g,{...F,...p,headers:{"User-Agent":Q16(),...F?.headers}})}}}:{};$=new UL8(new URL(K.url),Object.keys(C).length>0?C:void 0)}else if(K.type==="ws-ide"){let p=IV(),C={"User-Agent":Q16(),...K.authToken&&{"X-Claude-Code-Ide-Authorization":K.authToken}},g;if(typeof Bun<"u")g=new globalThis.WebSocket(K.url,{protocols:["mcp"],headers:C,proxy:eI(K.url),tls:p||void 0});else g=await GI4(K.url,{headers:C,agent:tI(K.url),...p||{}});$=new KR8(g)}else if(K.type==="ws"){m8(q,`Initializing WebSocket transport to ${K.url}`);let p=await zR8(q,K),C=IV(),g={"User-Agent":Q16(),...O&&{Authorization:`Bearer ${O}`},...p},F=SC(g,(c,K6)=>K6.toLowerCase()==="authorization"?"[REDACTED]":c);m8(q,`WebSocket transport options: ${g6({url:K.url,headers:F,hasSessionAuth:!!O})}`);let U
|
||||
|
||||
if(typeof Bun<"u")U=new globalThis.WebSocket(K.url,{protocols:["mcp"],headers:g,proxy:eI(K.url),tls:C||void 0});else U=await GI4(K.url,{headers:g,agent:tI(K.url),...C||{}});$=new KR8(U)}else if(K.type==="http"){m8(q,`Initializing HTTP transport to ${K.url}`),m8(q,`Node version: ${process.version}, Platform: ${process.platform}`),m8(q,`Environment: ${g6({NODE_OPTIONS:process.env.NODE_OPTIONS||"not set",UV_THREADPOOL_SIZE:process.env.UV_THREADPOOL_SIZE||"default",HTTP_PROXY:process.env.HTTP_PROXY||"not set",HTTPS_PROXY:process.env.HTTPS_PROXY||"not set",NO_PROXY:process.env.NO_PROXY||"not set"})}`);let p=new W26(q,K),C=await zR8(q,K),g=!!await p.tokens(),F=zY6();m8(q,`Proxy options: ${F.dispatcher?"custom dispatcher":"default"}`);let U={authProvider:p,fetch:cU1($U1(tw6(),p)),requestInit:{...F,headers:{"User-Agent":Q16(),...O&&!g&&{Authorization:`Bearer ${O}`},...C}}},c=U.requestInit?.headers?SC(U.requestInit.headers,(K6,o)=>o.toLowerCase()==="authorization"?"[REDACTED]":K6):void 0;m8(q,`HTTP transport options: ${g6({url:K.url,headers:c,hasAuthProvider:!!p,timeoutMs:yI4})}`),$=new dL8(new URL(K.url),U),m8(q,"HTTP transport created successfully")}else if(K.type==="sdk")throw Error("SDK servers should be handled in print.ts");else if(K.type==="claudeai-proxy"){if(m8(q,`Initializing claude.ai proxy transport for server ${K.id}`),!t7())throw Error("No claude.ai OAuth token found");let C=m7(),g=`${C.MCP_PROXY_URL}${C.MCP_PROXY_PATH.replace("{server_id}",K.id)}`;m8(q,`Using claude.ai proxy at ${g}`);let F=HWz(globalThis.fetch),U=zY6(),c={fetch:cU1(F),requestInit:{...U,headers:{"User-Agent":Q16(),"X-Mcp-Client-Session-Id":N8()}}};$=new dL8(new URL(g),c),m8(q,"claude.ai proxy transport created successfully")}else if((K.type==="stdio"||!K.type)&&H26(q)){let{createChromeContext:p}=await Promise.resolve().then(() => (eU1(),tU1)),{createClaudeForChromeMcpServer:C}=await Promise.resolve().then(() => (Zp6(),vk7)),{createLinkedTransportPair:g}=await Promise.resolve().then(() => FU1),F=p(K.env);Y=C(F);let[U,c]=g()
|
||||
|
||||
await Y.connect(c),$=U,m8(q,"In-process Chrome MCP server started")}else if((K.type==="stdio"||!K.type)&&VO6(q)){let{createComputerUseMcpServerForCli:p}=await Promise.resolve().then(() => (QU1(),UU1)),{createLinkedTransportPair:C}=await Promise.resolve().then(() => FU1);Y=await p();let[g,F]=C();await Y.connect(F),$=g,m8(q,"In-process Computer Use MCP server started")}else if(K.type==="stdio"||!K.type){let p=process.env.CLAUDE_CODE_SHELL_PREFIX||K.command,C=process.env.CLAUDE_CODE_SHELL_PREFIX?[[K.command,...K.args].join(" ")]:K.args;$=new XF1({command:p,args:C,env:{...Im(),...K.env},stderr:"pipe"})}else throw Error(`Unsupported server type: ${K.type}`);let A,w="";if(K.type==="stdio"||!K.type){let p=$;if(p.stderr)A=(C)=>{if(w.length<67108864)try{w+=C.toString()}catch{}},p.stderr.on("data",A)}let j=new VL8({name:"claude-code",title:"Claude Code",version:{ISSUES_EXPLAINER:"report the issue at https://github.com/anthropics/claude-code/issues",PACKAGE_URL:"@anthropic-ai/claude-code",README_URL:"https://code.claude.com/docs/en/overview",VERSION:"2.1.91",FEEDBACK_CHANNEL:"https://github.com/anthropics/claude-code/issues",BUILD_TIME:"2026-04-02T21:58:41Z"}.VERSION??"unknown",description:"Anthropic's agentic coding tool",websiteUrl:_26},{capabilities:{roots:{},elicitation:{}}});if(K.type==="http")m8(q,"Client created, setting up request handler");if(j.setRequestHandler(Z71,async()=>{return m8(q,"Received ListRoots request from server"),{roots:[{uri:`file://${z7()}`}]}}),m8(q,`Starting connection with timeout of ${GR8()}ms`),K.type==="http"){m8(q,`Testing basic HTTP connectivity to ${K.url}`);try{let p=new URL(K.url);if(m8(q,`Parsed URL: host=${p.hostname}, port=${p.port||"default"}, protocol=${p.protocol}`),p.hostname==="127.0.0.1"||p.hostname==="localhost")m8(q,`Using loopback address: ${p.hostname}`)}catch(p){m8(q,`Failed to parse URL: ${p}`)}}let H=j.connect($),J=new Promise((p,C)=>{let g=setTimeout(()=>{let F=Date.now()-z;if(m8(q,`Connection timeout triggered after ${F}ms (limit: ${GR8()}ms)`),Y)Y.close().catch(()=>{})
|
||||
|
||||
return`${q.name} - ${w} (MCP)`},...H26(q.name)&&(q.config.type==="stdio"||!q.config.type)?ePz().getClaudeInChromeMCPToolOverrides(Y.name):{},...(q.config.type==="stdio"||!q.config.type)&&VO6(q.name)?qWz().getComputerUseMCPToolOverrides(Y.name):{}}}).filter(WWz)}catch(K){return oz(q.name,`Failed to fetch tools: ${F6(K)}`),[]}},(q)=>q.name,sU1),uo=SP(async(q)=>{if(q.type!=="connected")return[];try{if(!q.capabilities?.resources)return[];let K=await q.client.request({method:"resources/list"},mm6);if(!K.resources)return[];return K.resources.map((_)=>({..._,server:q.name}))}catch(K){return oz(q.name,`Failed to fetch resources: ${F6(K)}`),[]}},(q)=>q.name,sU1),v26=SP(async(q)=>{if(q.type!=="connected")return[];try{if(!q.capabilities?.prompts)return[];let K=await q.client.request({method:"prompts/list"},gm6);if(!K.prompts)return[];return L46(K.prompts).map((z)=>{let Y=Object.values(z.arguments??{}).map(($)=>$.name);return{type:"prompt",name:"mcp__"+V2(q.name)+"__"+z.name,description:z.description??"",hasUserSpecifiedDescription:!!z.description,contentLength:0,isEnabled:()=>!0,isHidden:!1,isMcp:!0,progressMessage:"running",userFacingName(){return`${q.name}:${z.name} (MCP)`},argNames:Y,source:"mcp",async getPromptForCommand($){let O=$.split(" ");try{let A=await eN6(q),w=await A.client.getPrompt({name:z.name,arguments:QR4(Y,O)});return(await Promise.all(w.messages.map((H)=>LI4(H.content,A.name)))).flat()}catch(A){throw oz(q.name,`Error running command '${z.name}': ${F6(A)}`),A}}}})}catch(K){return oz(q.name,`Failed to fetch commands: ${F6(K)}`),[]}},(q)=>q.name,sU1)});function Vk(q){return typeof q==="object"&&q!==null&&"type"in q&&q.type==="local_bash"}function Ht6(q,K){w3(q,K,(_)=>{if(_.status!=="running"||!Vk(_))return _;try{N(`LocalShellTask ${q} kill requested`),_.shellCommand?.kill(),_.shellCommand?.cleanup()}catch(z){j6(z)}if(_.unregisterCleanup?.(),_.cleanupTimeoutId)clearTimeout(_.cleanupTimeoutId)
|
||||
|
||||
if(_?.type!=="connected")return;return Oy(_.config)}async function*sa6(q,K,_,z){let Y=q.name,$=sK(z.options.tools,Y);if(!$){let J=sK(E56(),Y);if(J&&J.aliases?.includes(Y))$=J}let O=K.message.id,A=K.requestId,w=gzY(Y,z.options.mcpClients),j=FzY(Y,z.options.mcpClients);if(!$){let J=HK(Y),M=$77(Y,z.options.tools);N(`Unknown tool ${Y}: ${q.id}`),d("tengu_tool_use_error",{error:`No such tool available: ${J}`,toolName:J,toolUseID:q.id,isMcp:Y.startsWith("mcp__"),queryChainId:z.queryTracking?.chainId,queryDepth:z.queryTracking?.depth,...w&&{mcpServerType:w},...j&&{mcpServerBaseUrl:j},...A&&{requestId:A},...mF(Y,w,j)}),yield{message:n8({content:[{type:"tool_result",content:`<tool_use_error>Error: No such tool available: ${Y}${M}</tool_use_error>`,is_error:!0,tool_use_id:q.id}],toolUseResult:`Error: No such tool available: ${Y}${M}`,sourceToolAssistantUUID:K.uuid})};return}let H=q.input;try{if(z.abortController.signal.aborted){d("tengu_tool_use_cancelled",{toolName:HK($.name),toolUseID:q.id,isMcp:$.isMcp??!1,queryChainId:z.queryTracking?.chainId,queryDepth:z.queryTracking?.depth,...w&&{mcpServerType:w},...j&&{mcpServerBaseUrl:j},...A&&{requestId:A},...mF($.name,w,j)});let J=O77(q.id);J.content=rR6(sj6),yield{message:n8({content:[J],toolUseResult:sj6,sourceToolAssistantUUID:K.uuid})};return}for await(let J of UzY($,q.id,H,z,_,K,O,A,w,j))yield J}catch(J){j6(J);let M=J instanceof Error?J.message:String(J),P=`Error calling tool${$?` (${$.name})`:""}: ${M}`;yield{message:n8({content:[{type:"tool_result",content:`<tool_use_error>${P}</tool_use_error>`,is_error:!0,tool_use_id:q.id}],toolUseResult:P,sourceToolAssistantUUID:K.uuid})}}}function UzY(q,K,_,z,Y,$,O,A,w,j){let H=new R78
|
||||
|
||||
function Hq7(){return`# Claude in Chrome browser automation
|
||||
|
||||
You have access to browser automation tools (mcp__claude-in-chrome__*) for interacting with web pages in Chrome. Follow these guidelines for effective browser automation.
|
||||
|
||||
## GIF recording
|
||||
|
||||
When performing multi-step browser interactions that the user may want to review or share, use mcp__claude-in-chrome__gif_creator to record them.
|
||||
|
||||
You must ALWAYS:
|
||||
* Capture extra frames before and after taking actions to ensure smooth playback
|
||||
* Name the file meaningfully to help the user identify it later (e.g., "login_process.gif")
|
||||
|
||||
## Console log debugging
|
||||
|
||||
You can use mcp__claude-in-chrome__read_console_messages to read console output. Console output may be verbose. If you are looking for specific log entries, use the 'pattern' parameter with a regex-compatible pattern. This filters results efficiently and avoids overwhelming output. For example, use pattern: "[MyApp]" to filter for application-specific logs rather than reading all console output.
|
||||
|
||||
## Alerts and dialogs
|
||||
|
||||
IMPORTANT: Do not trigger JavaScript alerts, confirms, prompts, or browser modal dialogs through your actions. These browser dialogs block all further browser events and will prevent the extension from receiving any subsequent commands. Instead, when possible, use console.log for debugging and then use the mcp__claude-in-chrome__read_console_messages tool to read those log messages. If a page has dialog-triggering elements:
|
||||
1. Avoid clicking buttons or links that may trigger alerts (e.g., "Delete" buttons with confirmation dialogs)
|
||||
2. If you must interact with such elements, warn the user first that this may interrupt the session
|
||||
3. Use mcp__claude-in-chrome__javascript_tool to check for and dismiss any existing dialogs before proceeding
|
||||
|
||||
If you accidentally trigger a dialog and lose responsiveness, inform the user they need to manually dismiss it in the browser.
|
||||
|
||||
## Avoid rabbit holes and loops
|
||||
|
||||
When using browser automation tools, stay focused on the specific task. If you encounter any of the following, stop and ask the user for guidance:
|
||||
- Unexpected complexity or tangential browser exploration
|
||||
- Browser tool calls failing or returning errors after 2-3 attempts
|
||||
- No response from the browser extension
|
||||
- Page elements not responding to clicks or input
|
||||
- Pages not loading or timing out
|
||||
- Unable to complete the browser task despite multiple approaches
|
||||
|
||||
Explain what you attempted, what went wrong, and ask how the user would like to proceed. Do not keep retrying the same failing browser action or explore unrelated pages without checking in first.
|
||||
|
||||
## Tab context and session startup
|
||||
|
||||
IMPORTANT: At the start of each browser automation session, call mcp__claude-in-chrome__tabs_context_mcp first to get information about the user's current browser tabs. Use this context to understand what the user might want to work with before creating new tabs.
|
||||
|
||||
Never reuse tab IDs from a previous/other session. Follow these guidelines:
|
||||
1. Only reuse an existing tab if the user explicitly asks to work with it
|
||||
2. Otherwise, create a new tab with mcp__claude-in-chrome__tabs_create_mcp
|
||||
3. If a tool returns an error indicating the tab doesn't exist or is invalid, call tabs_context_mcp to get fresh tab IDs
|
||||
4. When a tab is closed by the user or a navigation error occurs, call tabs_context_mcp to see what tabs are available`}var OGK=`# Claude in Chrome browser automation
|
||||
|
||||
You have access to browser automation tools (mcp__claude-in-chrome__*) for interacting with web pages in Chrome. Follow these guidelines for effective browser automation.
|
||||
|
||||
## GIF recording
|
||||
|
||||
When performing multi-step browser interactions that the user may want to review or share, use mcp__claude-in-chrome__gif_creator to record them.
|
||||
|
||||
You must ALWAYS:
|
||||
* Capture extra frames before and after taking actions to ensure smooth playback
|
||||
* Name the file meaningfully to help the user identify it later (e.g., "login_process.gif")
|
||||
|
||||
## Console log debugging
|
||||
|
||||
You can use mcp__claude-in-chrome__read_console_messages to read console output. Console output may be verbose. If you are looking for specific log entries, use the 'pattern' parameter with a regex-compatible pattern. This filters results efficiently and avoids overwhelming output. For example, use pattern: "[MyApp]" to filter for application-specific logs rather than reading all console output.
|
||||
|
||||
## Alerts and dialogs
|
||||
|
||||
IMPORTANT: Do not trigger JavaScript alerts, confirms, prompts, or browser modal dialogs through your actions. These browser dialogs block all further browser events and will prevent the extension from receiving any subsequent commands. Instead, when possible, use console.log for debugging and then use the mcp__claude-in-chrome__read_console_messages tool to read those log messages. If a page has dialog-triggering elements:
|
||||
1. Avoid clicking buttons or links that may trigger alerts (e.g., "Delete" buttons with confirmation dialogs)
|
||||
2. If you must interact with such elements, warn the user first that this may interrupt the session
|
||||
3. Use mcp__claude-in-chrome__javascript_tool to check for and dismiss any existing dialogs before proceeding
|
||||
|
||||
If you accidentally trigger a dialog and lose responsiveness, inform the user they need to manually dismiss it in the browser.
|
||||
|
||||
## Avoid rabbit holes and loops
|
||||
|
||||
When using browser automation tools, stay focused on the specific task. If you encounter any of the following, stop and ask the user for guidance:
|
||||
- Unexpected complexity or tangential browser exploration
|
||||
- Browser tool calls failing or returning errors after 2-3 attempts
|
||||
- No response from the browser extension
|
||||
- Page elements not responding to clicks or input
|
||||
- Pages not loading or timing out
|
||||
- Unable to complete the browser task despite multiple approaches
|
||||
|
||||
Explain what you attempted, what went wrong, and ask how the user would like to proceed. Do not keep retrying the same failing browser action or explore unrelated pages without checking in first.
|
||||
|
||||
## Tab context and session startup
|
||||
|
||||
IMPORTANT: At the start of each browser automation session, call mcp__claude-in-chrome__tabs_context_mcp first to get information about the user's current browser tabs. Use this context to understand what the user might want to work with before creating new tabs.
|
||||
|
||||
Never reuse tab IDs from a previous/other session. Follow these guidelines:
|
||||
1. Only reuse an existing tab if the user explicitly asks to work with it
|
||||
2. Otherwise, create a new tab with mcp__claude-in-chrome__tabs_create_mcp
|
||||
3. If a tool returns an error indicating the tab doesn't exist or is invalid, call tabs_context_mcp to get fresh tab IDs
|
||||
4. When a tab is closed by the user or a navigation error occurs, call tabs_context_mcp to see what tabs are available`,AGK=`**IMPORTANT: Before using any chrome browser tools, you MUST first load them using ToolSearch.**
|
||||
|
||||
Chrome browser tools are MCP tools that require loading before use. Before calling any mcp__claude-in-chrome__* tool:
|
||||
1. Use ToolSearch with \`select:mcp__claude-in-chrome__<tool_name>\` to load the specific tool
|
||||
2. Then call the tool
|
||||
|
||||
For example, to get tab context:
|
||||
1. First: ToolSearch with query "select:mcp__claude-in-chrome__tabs_context_mcp"
|
||||
2. Then: Call mcp__claude-in-chrome__tabs_context_mcp`,wGK='**Browser Automation**: Chrome browser tools are available via the "claude-in-chrome" skill. CRITICAL: Before using any mcp__claude-in-chrome__* tools, invoke the skill by calling the Skill tool with skill: "claude-in-chrome". The skill provides browser automation instructions and enables the tools.'
|
||||
|
||||
var jGK=`You have a computer-use MCP available (tools named \`mcp__computer-use__*\`). It lets you take screenshots of the user's desktop and control it with mouse clicks, keyboard input, and scrolling.
|
||||
|
||||
**Pick the right tool for the app.** Each tier trades speed/precision against coverage:
|
||||
|
||||
1. **Dedicated MCP for the app** — if the task is in an app that has its own MCP (Slack, Gmail, Calendar, Linear, etc.) and that MCP is connected, use it. API-backed tools are fast and precise.
|
||||
2. **Chrome MCP** (\`mcp__claude-in-chrome__*\`) — if the target is a web app and there's no dedicated MCP for it, use the browser tools. DOM-aware, much faster than clicking pixels. If the Chrome extension isn't connected, ask the user to install it rather than falling through to computer use.
|
||||
3. **Computer use** — for native desktop apps (Maps, Notes, Finder, Photos, System Settings, any third-party native app) and cross-app workflows. Computer use IS the right tool here — don't decline a native-app task just because there's no dedicated MCP for it.
|
||||
|
||||
This is about what's available, not error handling — if a dedicated MCP tool errors, debug or report it rather than silently retrying via a slower tier.
|
||||
|
||||
**Look before you assert.** If the user asks about app state (what's open, what's connected, what an app can do), take a screenshot and check before answering. Don't answer from memory — the user's setup or app version may differ from what you expect. If you're about to say an app doesn't support an action, that claim should be grounded in what you just saw on screen, not general knowledge. Similarly, \`list_granted_applications\` or a fresh \`screenshot\` is cheaper than a wrong assertion about what's running.
|
||||
|
||||
**Loading via ToolSearch — load in bulk, not one-by-one:** if computer-use tools are in the deferred list, load them ALL in a single ToolSearch call: \`{ query: "computer-use", max_results: 30 }\`. The keyword search matches the server-name substring in every tool name, so one query returns the entire toolkit. Don't use \`select:\` for individual tools — that's one round-trip per tool.
|
||||
|
||||
**Access flow:** before any computer-use action you must call \`request_access\` with the list of applications you need. The user approves each application explicitly, and you may need to call it again mid-task if you discover you need another application.
|
||||
|
||||
**Tiered apps:** some apps are granted at a restricted tier based on their category — the tier is displayed in the approval dialog and returned in the \`request_access\` response:
|
||||
- **Browsers** (Safari, Chrome, Firefox, Edge, Arc, etc.) → tier **"read"**: visible in screenshots, but clicks and typing are blocked. You can read what's already on screen. For navigation, clicking, or form-filling, use the claude-in-chrome MCP (tools named \`mcp__claude-in-chrome__*\`
|
||||
|
||||
if(!M){if(w&&w.type==="connected"&&_)w.client.onclose=()=>{},$v("ide",w.config),j((W)=>({...W,mcp:{...W.mcp,clients:W.mcp.clients.filter((D)=>D.name!=="ide"),tools:W.mcp.tools.filter((D)=>!D.name?.startsWith("mcp__ide__")),commands:W.mcp.commands.filter((D)=>!D.name?.startsWith("mcp__ide__"))}}));Y(X),$(_?`Disconnected from ${_.name}.`:"No IDE selected.");return}let P=M.url;X.ide={type:P.startsWith("ws:")?"ws-ide":"sse-ide",url:P,ideName:M.name,authToken:M.authToken,ideRunningInWindows:M.ideRunningInWindows,scope:"dynamic"},H.current=!0,A(M),Y(X)},[z,_,w,j,Y,$]);if(O)return V_.default.createElement(T,{dimColor:!0},"Connecting to ",O.name,"…");return V_.default.createElement(HDY,{availableIDEs:q,unavailableIDEs:K,selectedIDE:_,onClose:()=>$("IDE selection cancelled",{display:"system"}),onSelect:J})}function I57(q,K=100){if(q.length===0)return"";let _=Z8(),z=q.slice(0,2),Y=q.length>2,$=Y?3:0,O=(z.length-1)*2,A=K-O-$,w=Math.floor(A/z.length),j=_.normalize("NFC"),J=z.map((M)=>{let X=M.normalize("NFC");if(X.startsWith(j+eEK.sep))M=X.slice(j.length+1);if(M.length<=w)return M;return"…"+M.slice(-(w-1))}).join(", ");if(Y)J+=", …";return J}var V_,TDY=35000;var KLK=L(()=>{t6();I3();k8();b_();x4();tEK();i6();gD();E7();F7();PK();i2();D0();V_=w6(D6(),1)});var VDY,_LK;var zLK=L(()=>{VDY={type:"local-jsx",name:"ide",description:"Manage IDE integrations and show status",argumentHint:"[open]",load:()=>Promise.resolve().then(() => (KLK(),qLK))},_LK=VDY})
|
||||
|
||||
let f=k0.useCallback(async(Z)=>{let v=_.getState().mcp.clients.find((y)=>y.name===Z);if(!v)throw Error(`MCP server ${Z} not found`);let k=O.current.get(Z);if(k)clearTimeout(k),O.current.delete(Z);let V=await Sm(Z,v.config);return W(V),V},[_,W]),G=k0.useCallback(async(Z)=>{let v=_.getState().mcp.clients.find((V)=>V.name===Z);if(!v)throw Error(`MCP server ${Z} not found`);if(v.type!=="disabled"){let V=O.current.get(Z);if(V)clearTimeout(V),O.current.delete(Z);if(Ay6(Z,!1),v.type==="connected")await $v(Z,v.config);P({name:Z,type:"disabled",config:v.config})}else{Ay6(Z,!0),P({name:Z,type:"pending",config:v.config});let V=await Sm(Z,v.config);W(V)}},[_,P,W]);return{reconnectMcpServer:f,toggleMcpServer:G}}function wfY(q){switch(q){case"http":return"HTTP";case"ws":case"ws-ide":return"WebSocket";default:return"SSE"}}var k0,$fY=null,cS6=5,OfY=1000,AfY=30000;var vhK=L(()=>{T8();gD();HX();KQ1();Xh8();k8();nZ();_8();T8();Z$();E7();E8();h8();c2();Y48();d57();Yy6();_R8();yV();yM();k0=w6(D6(),1)});function lS6(){let q=LJ6.useContext(c57);if(!q)throw Error("useMcpReconnect must be used within MCPConnectionManager");return q.reconnectMcpServer}function Y36(){let q=LJ6.useContext(c57);if(!q)throw Error("useMcpToggleEnabled must be used within MCPConnectionManager");return q.toggleMcpServer}function XQ8(q){let K=Y6(6),{children:_,dynamicMcpConfig:z,isStrictMcpConfig:Y}=q,{reconnectMcpServer:$,toggleMcpServer:O}=GhK(z,Y),A;if(K[0]!==$||K[1]!==O)A={reconnectMcpServer:$,toggleMcpServer:O},K[0]=$,K[1]=O,K[2]=A;else A=K[2];let w=A,j;if(K[3]!==_||K[4]!==w)j=LJ6.default.createElement(c57.Provider,{value:w},_),K[3]=_,K[4]=w,K[5]=j;else j=K[5];return j}var LJ6,c57;var $36=L(()=>{t6();vhK();LJ6=w6(D6(),1),c57=LJ6.createContext(null)});function l57(q){let K=Y6(25),{serverName:_,onComplete:z}=q,[Y]=Aq(),$=Jz(),O=lS6(),[A,w]=V0.useState(!0),[j,H]=V0.useState(null),J,M
|
||||
|
||||
if(q.client.type==="disabled")v6.push({label:"Enable",value:"toggle-enabled"});if(q.client.type==="connected"&&K>0)v6.push({label:"View tools",value:"tools"});if(q.config.type==="claudeai-proxy"){if(q.client.type==="connected")v6.push({label:"Clear authentication",value:"claudeai-clear-auth"});else if(q.client.type!=="disabled")v6.push({label:"Authenticate",value:"claudeai-auth"})}else{if(z6)v6.push({label:"Re-authenticate",value:"reauth"}),v6.push({label:"Clear authentication",value:"clear-auth"});if(!z6)v6.push({label:"Authenticate",value:"auth"})}if(q.client.type!=="disabled"){if(q.client.type!=="needs-auth")v6.push({label:"Reconnect",value:"reconnectMcpServer"});v6.push({label:"Disable",value:"toggle-enabled"})}if(v6.length===0)v6.push({label:"Back",value:"back"})
|
||||
|
||||
break;case"auth":case"reauth":await O6();break;case"clear-auth":await X6();break;case"claudeai-auth":await l();break;case"claudeai-clear-auth":i();break;case"reconnectMcpServer":G(!0);try{let R6=await M6(q.name);if(q.config.type==="claudeai-proxy")d("tengu_claudeai_mcp_reconnect",{success:R6.client.type==="connected"});let{message:W6}=WQ8(R6,q.name);Y?.(W6)}catch(R6){if(q.config.type==="claudeai-proxy")d("tengu_claudeai_mcp_reconnect",{success:!1});Y?.(O48(R6,q.name))}finally{G(!1)}break;case"toggle-enabled":await A6();break;case"back":z();break}},onCancel:z}))),t1.default.createElement(u,{marginTop:1},t1.default.createElement(T,{dimColor:!0,italic:!0},A.pending?t1.default.createElement(t1.default.Fragment,null,"Press ",A.keyName," again to exit"):t1.default.createElement(p1,null,t1.default.createElement(e8,{shortcut:"↑↓",action:"navigate"}),t1.default.createElement(e8,{shortcut:"Enter",action:"select"}),t1.default.createElement(Z1,{action:"confirm:no",context:"Confirmation",fallback:"Esc",description:"back"})))))}var t1;var DQ8=L(()=>{Iq();k8();z3();J2();u4();XM();i6();Kq();go();gD();$36();yM();E7();T7();xH();E8();h8();q3();b_();IK();dK();r2();uH();i57();t1=w6(D6(),1)});function A48({server:q,serverToolsCount:K,onViewTools:_,onCancel:z,onComplete:Y,borderless:$=!1}){let[O]=Aq(),A=e5(),w=H8((f)=>f.mcp),j=lS6(),H=Y36(),[J,M]=h3.useState(!1),X=h3.default.useCallback(async()=>{let f=q.client.type!=="disabled";try{await H(q.name),z()}catch(G){Y(`Failed to ${f?"disable":"enable"} MCP server '${q.name}': ${F6(G)}`)}},[q.client.type,q.name,H,z,Y]),P=MG(String(q.name)),W=xh8(w.commands,q.name).length,D=[];if(q.client.type!=="disabled"&&K>0)D.push({label:"View tools",value:"tools"});if(q.client.type!=="disabled")D.push({label:"Reconnect",value:"reconnectMcpServer"});if(D.push({label:q.client.type!=="disabled"?"Disable":"Enable",value:"toggle-enabled"}),D.length===0)D.push({label:"Back",value:"back"})
|
||||
|
||||
return h3.default.createElement(u,{flexDirection:"column"},h3.default.createElement(u,{flexDirection:"column",paddingX:1,borderStyle:$?void 0:"round"},h3.default.createElement(u,{marginBottom:1},h3.default.createElement(T,{bold:!0},P," MCP Server")),h3.default.createElement(u,{flexDirection:"column",gap:0},h3.default.createElement(u,null,h3.default.createElement(T,{bold:!0},"Status: "),q.client.type==="disabled"?h3.default.createElement(T,null,b7("inactive",O)(o6.radioOff)," disabled"):q.client.type==="connected"?h3.default.createElement(T,null,b7("success",O)(o6.tick)," connected"):q.client.type==="pending"?h3.default.createElement(h3.default.Fragment,null,h3.default.createElement(T,{dimColor:!0},o6.radioOff),h3.default.createElement(T,null," connecting…")):h3.default.createElement(T,null,b7("error",O)(o6.cross)," failed")),h3.default.createElement(u,null,h3.default.createElement(T,{bold:!0},"Command: "),h3.default.createElement(T,{dimColor:!0},q.config.command)),q.config.args&&q.config.args.length>0&&h3.default.createElement(u,null,h3.default.createElement(T,{bold:!0},"Args: "),h3.default.createElement(T,{dimColor:!0},q.config.args.join(" "))),h3.default.createElement(u,null,h3.default.createElement(T,{bold:!0},"Config location: "),h3.default.createElement(T,{dimColor:!0},_v($y(q.name)?.scope??"dynamic"))),q.client.type==="connected"&&h3.default.createElement(PQ8,{serverToolsCount:K,serverPromptsCount:W,serverResourcesCount:w.resources[q.name]?.length||0}),q.client.type==="connected"&&K>0&&h3.default.createElement(u,null,h3.default.createElement(T,{bold:!0},"Tools: "),h3.default.createElement(T,{dimColor:!0},K," tools"))),D.length>0&&h3.default.createElement(u,{marginTop:1},h3.default.createElement(j1,{options:D,onChange:async(f)=>{if(f==="tools")_();else if(f==="reconnectMcpServer"){M(!0);try{let G=await j(q.name),{message:Z}=WQ8(G,q.name);Y?.(Z)}catch(G){Y?.(O48(G,q.name))}finally{M(!1)}}else if(f==="toggle-enabled")await X()
|
||||
|
||||
if(K[24]!==F||K[25]!==A||K[26]!==M||K[27]!==m||K[28]!==V||K[29]!==k||K[30]!==P||K[31]!==C.edit||K[32]!==C.execution||K[33]!==C.mcp||K[34]!==C.other||K[35]!==C.readOnly){U=[],U.push({id:"continue",label:"Continue",action:m,isContinue:!0});let i;if(K[37]!==A||K[38]!==V)i=()=>{let R6=A.map(eLY);b(R6,!V)},K[37]=A,K[38]=V,K[39]=i;else i=K[39];U.push({id:"bucket-all",label:`${V?o6.checkboxOn:o6.checkboxOff} All tools`,action:i});let A6=xpK();[{id:"bucket-readonly",name:A6.READ_ONLY.name,tools:C.readOnly},{id:"bucket-edit",name:A6.EDIT.name,tools:C.edit},{id:"bucket-execution",name:A6.EXECUTION.name,tools:C.execution},{id:"bucket-mcp",name:A6.MCP.name,tools:C.mcp},{id:"bucket-other",name:A6.OTHER.name,tools:C.other}].forEach((R6)=>{let{id:W6,name:N6,tools:Z6}=R6;if(Z6.length===0)return;let l6=w7(Z6,(K8)=>k.has(K8.name))===Z6.length;U.push({id:W6,label:`${l6?o6.checkboxOn:o6.checkboxOff} ${N6}`,action:F(Z6)})});let X6=U.length,v6;if(K[40]!==M||K[41]!==P||K[42]!==X6)v6=()=>{if(W(!P),P&&M>X6)X(X6)},K[40]=M,K[41]=P,K[42]=X6,K[43]=v6;else v6=K[43];U.push({id:"toggle-individual",label:P?"Hide advanced options":"Show advanced options",action:v6,isToggle:!0});let x6=oLY(A);if(P){if(x6.length>0)U.push({id:"mcp-servers-header",label:"MCP Servers:",action:tLY,isHeader:!0}),x6.forEach((R6)=>{let{serverName:W6,tools:N6}=R6,I6=w7(N6,(l6)=>k.has(l6.name))===N6.length;U.push({id:`mcp-server-${W6}`,label:`${I6?o6.checkboxOn:o6.checkboxOff} ${W6} (${N6.length} ${H7(N6.length,"tool")})`,action:()=>{let l6=N6.map(sLY);b(l6,!I6)}})}),U.push({id:"tools-header",label:"Individual Tools:",action:aLY,isHeader:!0});A.forEach((R6)=>{let W6=R6.name;if(R6.name.startsWith("mcp__")){let N6=NV(R6.name);W6=N6?`${N6.toolName} (${N6.serverName})`:R6.name}U.push({id:`tool-${R6.name}`,label:`${k.has(R6.name)?o6.checkboxOn:o6.checkboxOff} ${W6}`,action:()=>E(R6.name)})})}K[24]=F,K[25]=A,K[26]=M,K[27]=m,K[28]=V,K[29]=k,K[30]=P,K[31]=C.edit,K[32]=C.execution,K[33]=C.mcp,K[34]=C.other,K[35]=C.readOnly,K[36]=U}else U=K[36];let c
|
||||
|
||||
let f=auY(z),G=dY7(f,{ISSUES_EXPLAINER:"report the issue at https://github.com/anthropics/claude-code/issues",PACKAGE_URL:"@anthropic-ai/claude-code",README_URL:"https://code.claude.com/docs/en/overview",VERSION:"2.1.91",FEEDBACK_CHANNEL:"https://github.com/anthropics/claude-code/issues",BUILD_TIME:"2026-04-02T21:58:41Z"}.VERSION),Z=x08(G),v=[Z?{type:"text",text:Z}:null,...H?[]:[{type:"text",text:b08({isNonInteractive:!1,hasAppendSystemPrompt:!1})}],...Array.isArray(_)?_:_?[{type:"text",text:_}]:[]].filter((m)=>m!==null),k;if(M===!1)k={type:"disabled"};else if(M!==void 0)k={type:"enabled",budget_tokens:Math.min(M,A-1)};let V=AZ(K),y=Date.now(),E=await W.beta.messages.create({model:V,max_tokens:A,system:v,messages:z,...Y&&{tools:Y},...$&&{tool_choice:$},...O&&{output_config:{format:O}},...J!==void 0&&{temperature:J},...X&&{stop_sequences:X},...k&&{thinking:k},...D.length>0&&{betas:D},metadata:eq6(),...P},{signal:j}),R=E._request_id??void 0,b=Date.now(),I=x96();return d("tengu_api_success",{requestId:R,querySource:q.querySource,model:V,inputTokens:E.usage.input_tokens,outputTokens:E.usage.output_tokens,cachedInputTokens:E.usage.cache_read_input_tokens??0,uncachedInputTokens:E.usage.cache_creation_input_tokens??0,durationMsIncludingRetries:b-y,timeSinceLastApiCallMs:I!==null?b-I:void 0}),ax6(b),E}var oo=L(()=>{T8();b86();I08();k8();d2();lG6();BG();cY7();dq()});var tU1={};v8(tU1,{runClaudeInChromeMcpServer:()=>zmY,createChromeContext:()=>qcK});import{format as VK8}from"util";function qmY(q){return edK.some((K)=>K===q)}function KmY(){if(!L8("tengu_copper_bridge",!1))return;if(c6(process.env.USE_LOCAL_OAUTH)||c6(process.env.LOCAL_BRIDGE))return"ws://localhost:8765";if(c6(process.env.USE_STAGING_OAUTH))return"wss://bridge-staging.claudeusercontent.com";return"wss://bridge.claudeusercontent.com"}function _mY(){return c6(process.env.USE_LOCAL_OAUTH)||c6(process.env.LOCAL_BRIDGE)}function qcK(q){let K=new KcK,_=KmY();K.info(`Bridge URL: ${_??"none (using native socket)"}`)
|
||||
|
||||
for(let[j,H]of this.mcpClients)try{H.socket.write(w)}catch(J){zj(`Failed to send to MCP client ${j}:`,J)}}break}case"notification":{if(this.mcpClients.size>0){zj(`Forwarding notification to ${this.mcpClients.size} MCP clients`);let{type:Y,...$}=z,O=Buffer.from(g6($),"utf-8"),A=Buffer.alloc(4);A.writeUInt32LE(O.length,0);let w=Buffer.concat([A,O]);for(let[j,H]of this.mcpClients)try{H.socket.write(w)}catch(J){zj(`Failed to send notification to MCP client ${j}:`,J)}}break}default:zj(`Unknown message type: ${z.type}`),Ht(g6({type:"error",error:`Unknown message type: ${z.type}`}))}}handleMcpClient(q){let K=this.nextClientId++,_={id:K,socket:q,buffer:Buffer.alloc(0)};this.mcpClients.set(K,_),zj(`MCP client ${K} connected. Total clients: ${this.mcpClients.size}`),Ht(g6({type:"mcp_connected"})),q.on("data",(z)=>{_.buffer=Buffer.concat([_.buffer,z]);while(_.buffer.length>=4){let Y=_.buffer.readUInt32LE(0);if(Y===0||Y>rY7){zj(`Invalid message length from MCP client ${K}: ${Y}`),q.destroy();return}if(_.buffer.length<4+Y)break;let $=_.buffer.slice(4,4+Y);_.buffer=_.buffer.slice(4+Y);try{let O=l8($.toString("utf-8"));zj(`Forwarding tool request from MCP client ${K}: ${O.method}`),Ht(g6({type:"tool_request",method:O.method,params:O.params}))}catch(O){zj(`Failed to parse tool request from MCP client ${K}:`,O)}}}),q.on("error",(z)=>{zj(`MCP client ${K} error: ${z}`)}),q.on("close",()=>{zj(`MCP client ${K} disconnected. Remaining clients: ${this.mcpClients.size-1}`),this.mcpClients.delete(K),Ht(g6({type:"mcp_disconnected"}))})}}class OcK{buffer=Buffer.alloc(0);pendingResolve=null;closed=!1;constructor(){process.stdin.on("data",(q)=>{this.buffer=Buffer.concat([this.buffer,q]),this.tryProcessMessage()}),process.stdin.on("end",()=>{if(this.closed=!0,this.pendingResolve)this.pendingResolve(null),this.pendingResolve=null}),process.stdin.on("error",()=>{if(this.closed=!0,this.pendingResolve)this.pendingResolve(null),this.pendingResolve=null})}tryProcessMessage(){if(!this.pendingResolve)return;if(this.buffer.length<4)return
|
||||
|
||||
function _aK(q){return q.find((K)=>K.type==="connected"&&K.name.includes("slack"))}async function qcY(q,K){let _=_aK(q);if(!_||_.type!=="connected")return[];try{let Y=(await _.client.callTool({name:edY,arguments:{query:K,limit:20,channel_types:"public_channel,private_channel"}},void 0,{timeout:5000})).content;if(!Array.isArray(Y))return[];let $=Y.filter((O)=>O.type==="text").map((O)=>O.text).join(`
|
||||
`);return zcY(_cY($))}catch(z){return N(`Failed to fetch Slack channels: ${z}`),[]}}function _cY(q){let K=q.trim();if(!K.startsWith("{"))return q;try{let _=KcY().safeParse(l8(K));if(_.success)return _.data.results}catch{}return q}function zcY(q){let K=[],_=new Set;for(let z of q.split(`
|
||||
`)){let Y=z.match(/^Name:\s*#?([a-z0-9][a-z0-9_-]{0,79})\s*$/);if(Y&&!_.has(Y[1]))_.add(Y[1]),K.push(Y[1])}return K}function Jn8(q){return _aK(q)!==void 0}function zaK(){return eoK}function YaK(q){let K=[],_=/(^|\s)#([a-z0-9][a-z0-9_-]{0,79})(?=\s|$)/g,z;while((z=_.exec(q))!==null){if(!Hn8.has(z[2]))continue;let Y=z.index+z[1].length;K.push({start:Y,end:Y+1+z[2].length})}return K}function YcY(q){let K=Math.max(q.lastIndexOf("-"),q.lastIndexOf("_"));return K>0?q.slice(0,K):q}function $cY(q,K){let _,z=0;for(let[Y,$]of hb6)if(q.startsWith(Y)&&Y.length>z&&$.some((O)=>O.startsWith(K)))_=$,z=Y.length;return _}async function $aK(q,K){if(!K)return[];let _=YcY(K),z=K.toLowerCase(),Y=hb6.get(_)??$cY(_,z);if(!Y)if(jn8===_&&H58)Y=await H58;else{jn8=_,H58=qcY(q,_),Y=await H58,hb6.set(_,Y);let $=Hn8.size;for(let O of Y)Hn8.add(O);if(Hn8.size!==$)eoK++,qaK.emit();if(hb6.size>50)hb6.delete(hb6.keys().next().value);if(jn8===_)jn8=null,H58=null}return Y.filter(($)=>$.startsWith(z)).sort().slice(0,10).map(($)=>({id:`slack-channel-${$}`,displayText:`#${$}`}))}var edY="slack_search_channels",hb6,Hn8,eoK=0,qaK,KaK,jn8=null,H58=null,KcY;var sO7=L(()=>{LA6();_8();r8();hb6=new Map,Hn8=new Set,qaK=L_(),KaK=qaK.subscribe;KcY=p6(()=>bK.object({results:bK.string()}))});import{basename as OcY}from"path"
|
||||
|
||||
if(K[5]===Symbol.for("react.memo_cache_sentinel"))H=Q0.createElement(u,null,Q0.createElement(T,{dimColor:!0},"Press ",Q0.createElement(e8,{shortcut:"Esc",action:"cancel"})," anytime")),K[5]=H;else H=K[5];let J;if(K[6]!==Y)J=Q0.createElement(u,{flexDirection:"column",marginTop:1},j,H,Q0.createElement(u,null,Q0.createElement(T,{dimColor:!0},"Reason: ",Y))),K[6]=Y,K[7]=J;else J=K[7];return J}function D15(q){return!1;switch(q){case"feedback_survey_bad":return!1;case"feedback_survey_good":return!1;default:return!1}}function f15(q){return"/issue"}function Z15(q){switch(q){case"feedback_survey_bad":return'You responded "Bad" to the feedback survey';case"feedback_survey_good":return'You responded "Good" to the feedback survey';default:return"Unknown reason"}}var Q0,ki8;var G15=L(()=>{t6();dK();i6();Kq();Q0=w6(D6(),1),ki8=w6(D6(),1)});function v15(){return null}function EaY(q){for(let K of q){if(K.type!=="assistant")continue;let _=K.message.content;if(!Array.isArray(_))continue;for(let z of _){if(z.type!=="tool_use"||!("name"in z))continue;let Y=z.name;if(Y.startsWith("mcp__"))return!1;if(Y===Yq){let O=z.input?.command||"";if(NaY.some((A)=>A.test(O)))return!1}}}return!0}function LaY(q){for(let K=q.length-1;K>=0;K--){let _=q[K];if(_.type!=="user")continue;let z=yQ(_);if(!z)continue;return yaY.some((Y)=>Y.test(z))}return!1}function T15(q,K){return!1}var n58,NaY,yaY,haY=3,RaY=1800000;var k15=L(()=>{a1();n58=w6(D6(),1),NaY=[/\bcurl\b/,/\bwget\b/,/\bssh\b/,/\bkubectl\b/,/\bsrun\b/,/\bdocker\b/,/\bbq\b/,/\bgsutil\b/,/\bgcloud\b/,/\baws\b/,/\bgit\s+push\b/,/\bgit\s+pull\b/,/\bgit\s+fetch\b/,/\bgh\s+(pr|issue)\b/,/\bnc\b/,/\bncat\b/,/\btelnet\b/,/\bftp\b/],yaY=[/^no[,!]\s/i,/\bthat'?s (wrong|incorrect|not (what|right|correct))\b/i,/\bnot what I (asked|wanted|meant|said)\b/i,/\bI (said|asked|wanted|told you|already said)\b/i,/\bwhy did you\b/i,/\byou should(n'?t| not)? have\b/i,/\byou were supposed to\b/i,/\btry again\b/i,/\b(undo|revert) (that|this|it|what you)\b/i]});var SaY,CaY;var V15=L(()=>{t6();T8();i6()
|
||||
|
||||
if(q[0]===Symbol.for("react.memo_cache_sentinel"))K=nw7.default.createElement(T,null,"MCP servers may execute code or access system resources. All tool calls require approval. Learn more in the"," ",nw7.default.createElement(Sq,{url:"https://code.claude.com/docs/en/mcp"},"MCP documentation"),"."),q[0]=K;else K=q[0];return K}var nw7;var iw7=L(()=>{t6();i6();nw7=w6(D6(),1)});function A75(q){let K=Y6(13),{serverName:_,onDone:z}=q,Y;if(K[0]!==z||K[1]!==_)Y=function(X){d("tengu_mcp_dialog_choice",{choice:X});q:switch(X){case"yes":case"yes_all":{let W=(k7()||{}).enabledMcpjsonServers||[];if(!W.includes(_))P7("localSettings",{enabledMcpjsonServers:[...W,_]});if(X==="yes_all")P7("localSettings",{enableAllProjectMcpServers:!0});z();break q}case"no":{let W=(k7()||{}).disabledMcpjsonServers||[];if(!W.includes(_))P7("localSettings",{disabledMcpjsonServers:[...W,_]});z()}}},K[0]=z,K[1]=_,K[2]=Y;else Y=K[2];let $=Y,O=`New MCP server found in .mcp.json: ${_}`,A;if(K[3]!==$)A=()=>$("no"),K[3]=$,K[4]=A;else A=K[4];let w;if(K[5]===Symbol.for("react.memo_cache_sentinel"))w=Ri8.default.createElement(hi8,null),K[5]=w;else w=K[5];let j;if(K[6]===Symbol.for("react.memo_cache_sentinel"))j=[{label:"Use this and all future MCP servers in this project",value:"yes_all"},{label:"Use this MCP server",value:"yes"},{label:"Continue without using this MCP server",value:"no"}],K[6]=j;else j=K[6];let H;if(K[7]!==$)H=Ri8.default.createElement(j1,{options:j,onChange:(M)=>$(M),onCancel:()=>$("no")}),K[7]=$,K[8]=H;else H=K[8];let J;if(K[9]!==O||K[10]!==A||K[11]!==H)J=Ri8.default.createElement(h1,{title:O,color:"warning",onCancel:A},w,H),K[9]=O,K[10]=A,K[11]=H,K[12]=J;else J=K[12];return J}var Ri8;var w75=L(()=>{t6();k8();i1();b_();x4();iw7();Ri8=w6(D6(),1)});function j75(q){let K=Y6(21),{serverNames:_,onDone:z}=q,Y;if(K[0]!==z||K[1]!==_)Y=function(D){let f=k7()||{},G=f.enabledMcpjsonServers||[],Z=f.disabledMcpjsonServers||[],[v,k]=cd8(_,(V)=>D.includes(V))
|
||||
|
||||
if(K[1]===Symbol.for("react.memo_cache_sentinel"))O=Object.keys($),K[1]=O;else O=K[1];let A=O.length>0,w;if(K[2]===Symbol.for("react.memo_cache_sentinel"))w=p75(),K[2]=w;else w=K[2];let H=w.length>0,J;if(K[3]===Symbol.for("react.memo_cache_sentinel"))J=B75(),K[3]=J;else J=K[3];let M=J,X;if(K[4]===Symbol.for("react.memo_cache_sentinel"))X=F75(),K[4]=X;else X=K[4];let W=X.length>0,D;if(K[5]===Symbol.for("react.memo_cache_sentinel"))D=U75(),K[5]=D;else D=K[5];let G=D.length>0,Z;if(K[6]===Symbol.for("react.memo_cache_sentinel"))Z=Q75(),K[6]=Z;else Z=K[6];let k=Z.length>0,V;if(K[7]===Symbol.for("react.memo_cache_sentinel"))V=g75(),K[7]=V;else V=K[7];let E=V.length>0,R;if(K[8]===Symbol.for("react.memo_cache_sentinel"))R=d75(),K[8]=R;else R=K[8];let I=R.length>0,m;if(K[9]!==z)m=z?.some(OtY)??!1,K[9]=z,K[10]=m;else m=K[10];let p=m,C;if(K[11]!==z)C=z?.some(YtY)??!1,K[11]=z,K[12]=C;else C=K[12];let g=C,F=M.length>0||p||g,U=KO(),c,K6;if(K[13]!==F)c=()=>{let l=l75()===Z8();d("tengu_trust_dialog_shown",{isHomeDir:l,hasMcpServers:A,hasHooks:H,hasBashExecution:F,hasApiKeyHelper:W,hasAwsCommands:G,hasGcpCommands:k,hasOtelHeadersHelper:E,hasDangerousEnvVars:I})},K6=[A,H,F,W,G,k,E,I],K[13]=F,K[14]=c,K[15]=K6;else c=K[14],K6=K[15];rk.default.useEffect(c,K6);let o;if(K[16]!==F||K[17]!==_)o=function(i){if(i==="exit"){eK(1);return}let A6=l75()===Z8();if(d("tengu_trust_dialog_accept",{isHomeDir:A6,hasMcpServers:A,hasHooks:H,hasBashExecution:F,hasApiKeyHelper:W,hasAwsCommands:G,hasGcpCommands:k,hasOtelHeadersHelper:E,hasDangerousEnvVars:I}),A6)HI6(!0);else Vw(ztY);_()},K[16]=F,K[17]=_,K[18]=o;else o=K[18];let q6=o,t=e5(_tY),n;if(K[19]===Symbol.for("react.memo_cache_sentinel"))n={context:"Confirmation"},K[19]=n;else n=K[19];if(f1("confirm:no",KtY,n),U)return setTimeout(_),null;let z6,M6,J6
|
||||
|
||||
if(K&&Y.enableAllProjectMcpServers===void 0)$.enableAllProjectMcpServers=q.enableAllProjectMcpServers,O.push("enableAllProjectMcpServers");else if(K)O.push("enableAllProjectMcpServers");if(_&&q.enabledMcpjsonServers){let A=Y.enabledMcpjsonServers||[];$.enabledMcpjsonServers=[...new Set([...A,...q.enabledMcpjsonServers])],O.push("enabledMcpjsonServers")}if(z&&q.disabledMcpjsonServers){let A=Y.disabledMcpjsonServers||[];$.disabledMcpjsonServers=[...new Set([...A,...q.disabledMcpjsonServers])],O.push("disabledMcpjsonServers")}if(Object.keys($).length>0)P7("localSettings",$);if(O.includes("enableAllProjectMcpServers")||O.includes("enabledMcpjsonServers")||O.includes("disabledMcpjsonServers"))Vw((A)=>{let{enableAllProjectMcpServers:w,enabledMcpjsonServers:j,disabledMcpjsonServers:H,...J}=A;return J});d("tengu_migrate_mcp_approval_fields_success",{migratedCount:O.length})}catch(Y){j6(Y),d("tengu_migrate_mcp_approval_fields_error",{})}}var lK5=L(()=>{k8();k1();h8();i1()});var nK5=L(()=>{i1()});function iK5(){if(Dq()!=="firstParty")return;if(!bX8())return;let q=V1("userSettings")?.model;if(q!=="claude-opus-4-20250514"&&q!=="claude-opus-4-1-20250805"&&q!=="claude-opus-4-0"&&q!=="claude-opus-4-1")return;P7("userSettings",{model:"opus"}),S8((K)=>({...K,legacyOpusMigrationTimestamp:Date.now()})),d("tengu_legacy_opus_migration",{from_model:q})}var rK5=L(()=>{k8();k1();dq();P_();i1()});function oK5(){if(!vJ())return;if(V1("userSettings")?.model!=="opus")return;let K="opus[1m]",_=Y5(K)===Y5(RG())?void 0:K;P7("userSettings",{model:_}),d("tengu_opus_to_opus1m_migration",{})}var aK5=L(()=>{k8();dq();i1()});function sK5(){S8((q)=>{let K=q.replBridgeEnabled;if(K===void 0)return q;if(q.remoteControlAtStartup!==void 0)return q;let _={...q,remoteControlAtStartup:Boolean(K)};return delete _.replBridgeEnabled,_})}var tK5=L(()=>{k1()});function eK5(){if(w8().sonnet1m45MigrationComplete)return;if(V1("userSettings")?.model==="sonnet[1m]")P7("userSettings",{model:"sonnet-4-5-20250929[1m]"});if(tx()==="sonnet[1m]")yP("sonnet-4-5-20250929[1m]")
|
||||
|
||||
return{response:{added:[...J,...D.response.added],removed:[...M,...D.response.removed],errors:{...O,...D.response.errors}},newSdkState:{configs:X,clients:P,tools:W},newDynamicState:D.newState,sdkServersChanged:J.length>0||M.length>0}}async function H35(q,K,_){let z=new Set(Object.keys(K.configs)),Y=new Set(Object.keys(q)),$=[...z].filter((D)=>!Y.has(D)),O=[...Y].filter((D)=>!z.has(D)),w=[...z].filter((D)=>Y.has(D)).filter((D)=>{let f=K.configs[D],G=q[D];if(!f||!G)return!0;let Z=Z27(G);return!EI4(f,Z)}),j=[],H=[],J={},M=[...K.clients],X=[...K.tools];for(let D of[...$,...w]){let f=M.find((v)=>v.name===D),G=K.configs[D];if(f&&G){if(f.type==="connected")try{await f.cleanup()}catch(v){j6(v)}await $v(D,G)}let Z=`mcp__${D}__`;if(X=X.filter((v)=>!v.name.startsWith(Z)),M=M.filter((v)=>v.name!==D),$.includes(D))j.push(D)}for(let D of[...O,...w]){let f=q[D];if(!f)continue;let G=Z27(f);if(f.type==="sdk"){H.push(D);continue}try{let Z=await Tb(D,G);if(M.push(Z),Z.type==="connected"){let v=await eL(Z);X.push(...v)}else if(Z.type==="failed")J[D]=Z.error||"Connection failed";H.push(D)}catch(Z){let v=m1(Z);J[D]=v.message,j6(v)}}let P={};for(let D of Y){let f=q[D];if(f)P[D]=Z27(f)}let W={clients:M,tools:X,configs:P};return _((D)=>{let f=new Set([...Object.keys(K.configs),...Object.keys(P)]),G=D.mcp.tools.filter((v)=>{for(let k of f)if(v.name.startsWith(`mcp__${k}__`))return!1;return!0}),Z=D.mcp.clients.filter((v)=>{return!f.has(v.name)})
|
||||
|
||||
Of();l2();jk();h8();a1();dq();lj();Ck();r8();S78();l78();R8$=[vd8]});var y35={};v8(y35,{readClaudeDesktopMcpServers:()=>I8$,getClaudeDesktopConfigPath:()=>N35});import{readdir as C8$,readFile as b8$,stat as k35}from"fs/promises";import{homedir as x8$}from"os";import{join as V35}from"path";async function N35(){let q=v1();if(!sK1.includes(q))throw Error(`Unsupported platform: ${q} - Claude Desktop integration only works on macOS and WSL.`);if(q==="macos")return V35(x8$(),"Library","Application Support","Claude","claude_desktop_config.json");let K=process.env.USERPROFILE?process.env.USERPROFILE.replace(/\\/g,"/"):null;if(K){let z=`/mnt/c${K.replace(/^[A-Z]:/,"")}/AppData/Roaming/Claude/claude_desktop_config.json`;try{return await k35(z),z}catch{}}try{try{let z=await C8$("/mnt/c/Users",{withFileTypes:!0});for(let Y of z){if(Y.name==="Public"||Y.name==="Default"||Y.name==="Default User"||Y.name==="All Users")continue;let $=V35("/mnt/c/Users",Y.name,"AppData","Roaming","Claude","claude_desktop_config.json");try{return await k35($),$}catch{}}}catch{}}catch(_){j6(_)}throw Error("Could not find Claude Desktop config file in Windows. Make sure Claude Desktop is installed on Windows.")}async function I8$(){if(!sK1.includes(v1()))throw Error("Unsupported platform - Claude Desktop integration only works on macOS and WSL.");try{let q=await N35(),K;try{K=await b8$(q,{encoding:"utf8"})}catch($){if(d1($)==="ENOENT")return{};throw $}let _=p5(K);if(!_||typeof _!=="object")return{};let z=_.mcpServers;if(!z||typeof z!=="object")return{};let Y={};for(let[$,O]of Object.entries(z)){if(!O||typeof O!=="object")continue;let A=T31().safeParse(O);if(A.success)Y[$]=A.data}return Y}catch(q){return j6(q),{}}}var E35=L(()=>{zz6();E8();mA();h8();NK()});var o36={};v8(o36,{mcpServeHandler:()=>p8$,mcpResetChoicesHandler:()=>d8$,mcpRemoveHandler:()=>B8$,mcpListHandler:()=>g8$,mcpGetHandler:()=>F8$,mcpAddJsonHandler:()=>U8$,mcpAddFromDesktopHandler:()=>Q8$});import{stat as u8$}from"fs/promises";import{cwd as m8$}from"process"
|
||||
|
||||
for(let[Y,$]of Object.entries(K.env))console.log(` ${Y}=${$}`)}}console.log(`
|
||||
To remove this server, run: claude mcp remove "${q}" -s ${K.scope}`),await uK(0)}async function U8$(q,K,_){try{let z=Hy6(_.scope),Y=p5(K),O=_.clientSecret&&Y&&typeof Y==="object"&&"type"in Y&&(Y.type==="sse"||Y.type==="http")&&"url"in Y&&typeof Y.url==="string"&&"oauth"in Y&&Y.oauth&&typeof Y.oauth==="object"&&"clientId"in Y.oauth?await Fs6():void 0;await f46(q,Y,z);let A=Y&&typeof Y==="object"&&"type"in Y?String(Y.type||"stdio"):"stdio";if(O&&Y&&typeof Y==="object"&&"type"in Y&&(Y.type==="sse"||Y.type==="http")&&"url"in Y&&typeof Y.url==="string")Us6(q,{type:Y.type,url:Y.url},O);d("tengu_mcp_add",{scope:z,source:"json",type:A}),sO(`Added ${A} MCP server ${q} to ${z} config`)}catch(z){a3(z.message)}}async function Q8$(q){try{let K=Hy6(q.scope),_=v1();d("tengu_mcp_add",{scope:K,platform:_,source:"desktop"});let{readClaudeDesktopMcpServers:z}=await Promise.resolve().then(() => (E35(),y35)),Y=await z();if(Object.keys(Y).length===0)sO("No MCP servers found in Claude Desktop configuration or configuration file does not exist.");let{unmount:$}=await iu(ri8.default.createElement(IJ,null,ri8.default.createElement(hM,null,ri8.default.createElement(Z35,{servers:Y,scope:K,onDone:()=>{$()}}))),{exitOnCtrlC:!0})}catch(K){a3(K.message)}}async function d8$(){d("tengu_mcp_reset_mcpjson_choices",{}),Vw((q)=>({...q,enabledMcpjsonServers:[],disabledMcpjsonServers:[],enableAllProjectMcpServers:!1})),sO(`All project-scoped (.mcp.json) server approvals and rejections have been reset.
|
||||
You will be prompted for approval next time you start Claude Code.`)}var ri8;var a36=L(()=>{WF1();G35();i6();LQ();k8();go();gD();nZ();yM();E7();k1();E8();AO();mA();NK();ri8=w6(D6(),1)});var xx={}
|
||||
|
||||
if(q.length===1&&(q[0]==="--version"||q[0]==="-v"||q[0]==="-V")){console.log(`${{ISSUES_EXPLAINER:"report the issue at https://github.com/anthropics/claude-code/issues",PACKAGE_URL:"@anthropic-ai/claude-code",README_URL:"https://code.claude.com/docs/en/overview",VERSION:"2.1.91",FEEDBACK_CHANNEL:"https://github.com/anthropics/claude-code/issues",BUILD_TIME:"2026-04-02T21:58:41Z"}.VERSION} (Claude Code)`);return}let{profileCheckpoint:K}=await Promise.resolve().then(() => ($I(),xP7));if(K("cli_entry"),process.argv[2]==="--claude-in-chrome-mcp"){K("cli_claude_in_chrome_mcp_path");let{runClaudeInChromeMcpServer:$}=await Promise.resolve().then(() => (eU1(),tU1));await $();return}else if(process.argv[2]==="--chrome-native-host"){K("cli_chrome_native_host_path");let{runChromeNativeHost:$}=await Promise.resolve().then(() => (wcK(),AcK));await $();return}else if(process.argv[2]==="--computer-use-mcp"){K("cli_computer_use_mcp_path");let{runComputerUseMcpServer:$}=await Promise.resolve().then(() => (QU1(),UU1));await $();return}if(q[0]==="remote-control"||q[0]==="rc"||q[0]==="remote"||q[0]==="sync"||q[0]==="bridge"){K("cli_bridge_path");let{enableConfigs:$}=await Promise.resolve().then(() => (k1(),q76));$();let{getBridgeDisabledReason:O,checkBridgeMinVersion:A}=await Promise.resolve().then(() => (ip(),eK7)),{BRIDGE_LOGIN_ERROR:w}=await Promise.resolve().then(() => uIK),{bridgeMain:j}=await Promise.resolve().then(() => (w$7(),A$7)),{exitWithError:H}=await Promise.resolve().then(() => Fs8),{getClaudeAIOAuthTokens:J}=await Promise.resolve().then(() => (T7(),kL));if(!J()?.accessToken)H(w);let M=await O();if(M)H(`Error: ${M}`);let X=A();if(X)H(X);let{waitForPolicyLimitsToLoad:P,isPolicyAllowed:W}=await Promise.resolve().then(() => (dD(),gQ1));if(await P(),!W("allow_remote_control"))H("Error: Remote Control is disabled by your organization's policy.");await j(q.slice(1))
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"sizeBytes": 13162543,
|
||||
"lines": 16967,
|
||||
"functions": 19906,
|
||||
"asyncFunctions": 1903,
|
||||
"arrowFunctions": 25893,
|
||||
"classes": 1632,
|
||||
"extends": 852,
|
||||
"sourceFile": "cli.js",
|
||||
"extractedAt": "2026-04-02T23:29:03.816Z",
|
||||
"modules": {
|
||||
"tool-dispatch": {
|
||||
"fragments": 57,
|
||||
"sizeBytes": 281582
|
||||
},
|
||||
"permission-system": {
|
||||
"fragments": 615,
|
||||
"sizeBytes": 1407756
|
||||
},
|
||||
"agent-loop": {
|
||||
"fragments": 101,
|
||||
"sizeBytes": 200371
|
||||
},
|
||||
"streaming-handler": {
|
||||
"fragments": 24,
|
||||
"sizeBytes": 53447
|
||||
},
|
||||
"context-manager": {
|
||||
"fragments": 35,
|
||||
"sizeBytes": 69207
|
||||
},
|
||||
"mcp-client": {
|
||||
"fragments": 48,
|
||||
"sizeBytes": 102315
|
||||
},
|
||||
"telemetry": {
|
||||
"fragments": 861,
|
||||
"sizeBytes": 26734
|
||||
},
|
||||
"commands": {
|
||||
"fragments": 93,
|
||||
"sizeBytes": 8176
|
||||
},
|
||||
"class-hierarchy": {
|
||||
"fragments": 1467,
|
||||
"sizeBytes": 23004
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,543 @@
|
|||
while(($=EM7(K))!==-1)yield K.slice(0,$),K=K.slice($)}if(K.length>0)yield K}class hM7{constructor(){this.event=null,this.data=[],this.chunks=[]}decode(q){if(q.endsWith("\r"))q=q.substring(0,q.length-1);if(!q){if(!this.event&&!this.data.length)return null;let Y={event:this.event,data:this.data.join(`
|
||||
`),raw:this.chunks};return this.event=null,this.data=[],this.chunks=[],Y}if(this.chunks.push(q),q.startsWith(":"))return null;let[K,_,z]=rO5(q,":");if(z.startsWith(" "))z=z.substring(1);if(K==="event")this.event=z;else if(K==="data")this.data.push(z);return null}}function rO5(q,K){let _=q.indexOf(K);if(_!==-1)return[q.substring(0,_),K,q.substring(_+K.length)];return[q,"",""]}var hI6,rv;var Fa8=L(()=>{Dl();FW();Ba8();U96();w_8();FW();rv=class rv{constructor(q,K,_){this.iterator=q,hI6.set(this,void 0),this.controller=K,J4(this,hI6,_,"f")}static fromSSEResponse(q,K,_){let z=!1,Y=_?UW(_):console;async function*$(){if(z)throw new mq("Cannot iterate over a consumed stream, use `.tee()` to split the stream.");z=!0;let O=!1;try{for await(let A of nO5(q,K)){if(A.event==="completion")try{yield JSON.parse(A.data)}catch(w){throw Y.error("Could not parse message into JSON:",A.data),Y.error("From chunk:",A.raw),w}if(A.event==="message_start"||A.event==="message_delta"||A.event==="message_stop"||A.event==="content_block_start"||A.event==="content_block_delta"||A.event==="content_block_stop")try{yield JSON.parse(A.data)}catch(w){throw Y.error("Could not parse message into JSON:",A.data),Y.error("From chunk:",A.raw),w}if(A.event==="ping")continue;if(A.event==="error")throw new nq(void 0,Y_8(A.data)??A.data,void 0,q.headers)}O=!0}catch(A){if(fl(A))return;throw A}finally{if(!O)K.abort()}}return new rv($,K,_)}static fromReadableStream(q,K,_){let z=!1;async function*Y(){let O=new Ze,A=yI6(q);for await(let w of A)for(let j of O.decode(w))yield j;for(let w of O.flush())yield w}async function*$(){if(z)throw new mq("Cannot iterate over a consumed stream, use `.tee()` to split the stream.");z=!0;let O=!1
|
||||
|
||||
if(q==="abort"){let z=K[0];if(!x1(this,c96,"f")&&!_?.length)Promise.reject(z);x1(this,pI6,"f").call(this,z),x1(this,gI6,"f").call(this,z),this._emit("end");return}if(q==="error"){let z=K[0];if(!x1(this,c96,"f")&&!_?.length)Promise.reject(z);x1(this,pI6,"f").call(this,z),x1(this,gI6,"f").call(this,z),this._emit("end")}}_emitFinal(){if(this.receivedMessages.at(-1))this._emit("finalMessage",x1(this,ZR,"m",zs8).call(this))}async _fromReadableStream(q,K){let _=K?.signal,z;if(_){if(_.aborted)this.controller.abort();z=this.controller.abort.bind(this.controller),_.addEventListener("abort",z)}try{x1(this,ZR,"m",Ys8).call(this),this._connected(null);let Y=rv.fromReadableStream(q,this.controller);for await(let $ of Y)x1(this,ZR,"m",$s8).call(this,$);if(Y.controller.signal?.aborted)throw new c_;x1(this,ZR,"m",Os8).call(this)}finally{if(_&&z)_.removeEventListener("abort",z)}}[(Te=new WeakMap,VP6=new WeakMap,mI6=new WeakMap,G_8=new WeakMap,pI6=new WeakMap,BI6=new WeakMap,v_8=new WeakMap,gI6=new WeakMap,Gl=new WeakMap,FI6=new WeakMap,T_8=new WeakMap,k_8=new WeakMap,c96=new WeakMap,V_8=new WeakMap,N_8=new WeakMap,UI6=new WeakMap,y_8=new WeakMap,ZR=new WeakSet,zs8=function(){if(this.receivedMessages.length===0)throw new mq("stream ended without producing a Message with role=assistant");return this.receivedMessages.at(-1)},BM7=function(){if(this.receivedMessages.length===0)throw new mq("stream ended without producing a Message with role=assistant");let K=this.receivedMessages.at(-1).content.filter((_)=>_.type==="text").map((_)=>_.text);if(K.length===0)throw new mq("stream ended without producing a content block with type=text");return K.join(" ")},Ys8=function(){if(this.ended)return;J4(this,Te,void 0,"f")},$s8=function(K){if(this.ended)return;let _=x1(this,ZR,"m",gM7).call(this,K);switch(this._emit("streamEvent",K,_),K.type){case"content_block_delta":{let z=_.content.at(-1);switch(K.delta.type){case"text_delta":{if(z.type==="text")this._emit("text",K.delta.text,z.text||"")
|
||||
|
||||
break}case"citations_delta":{if(z.type==="text")this._emit("citation",K.delta.citation,z.citations??[]);break}case"input_json_delta":{if(UM7(z)&&z.input)this._emit("inputJson",K.delta.partial_json,z.input);break}case"thinking_delta":{if(z.type==="thinking")this._emit("thinking",K.delta.thinking,z.thinking);break}case"signature_delta":{if(z.type==="thinking")this._emit("signature",z.signature);break}case"compaction_delta":{if(z.type==="compaction"&&z.content)this._emit("compaction",z.content);break}default:QM7(K.delta)}break}case"message_stop":{this._addMessageParam(_),this._addMessage(ea8(_,x1(this,VP6,"f"),{logger:x1(this,UI6,"f")}),!0);break}case"content_block_stop":{this._emit("contentBlock",_.content.at(-1));break}case"message_start":{J4(this,Te,_,"f");break}case"content_block_start":case"message_delta":break}},Os8=function(){if(this.ended)throw new mq("stream has ended, this shouldn't happen");let K=x1(this,Te,"f");if(!K)throw new mq("request ended without sending any chunks");return J4(this,Te,void 0,"f"),ea8(K,x1(this,VP6,"f"),{logger:x1(this,UI6,"f")})},gM7=function(K){let _=x1(this,Te,"f");if(K.type==="message_start"){if(_)throw new mq(`Unexpected event order, got ${K.type} before receiving "message_stop"`);return K.message}if(!_)throw new mq(`Unexpected event order, got ${K.type} before "message_start"`);switch(K.type){case"message_stop":return _;case"message_delta":if(_.container=K.delta.container,_.stop_reason=K.delta.stop_reason,_.stop_sequence=K.delta.stop_sequence,_.usage.output_tokens=K.usage.output_tokens,_.context_management=K.context_management,K.usage.input_tokens!=null)_.usage.input_tokens=K.usage.input_tokens;if(K.usage.cache_creation_input_tokens!=null)_.usage.cache_creation_input_tokens=K.usage.cache_creation_input_tokens;if(K.usage.cache_read_input_tokens!=null)_.usage.cache_read_input_tokens=K.usage.cache_read_input_tokens;if(K.usage.server_tool_use!=null)_.usage.server_tool_use=K.usage.server_tool_use;if(K.usage.iterations!=null)_.usage.iterations=K.usage.iterations;return _
|
||||
|
||||
case"content_block_start":return _.content.push(K.content_block),_;case"content_block_delta":{let z=_.content.at(K.index);switch(K.delta.type){case"text_delta":{if(z?.type==="text")_.content[K.index]={...z,text:(z.text||"")+K.delta.text};break}case"citations_delta":{if(z?.type==="text")_.content[K.index]={...z,citations:[...z.citations??[],K.delta.citation]};break}case"input_json_delta":{if(z&&UM7(z)){let Y=z[FM7]||"";Y+=K.delta.partial_json;let $={...z};if(Object.defineProperty($,FM7,{value:Y,enumerable:!1,writable:!0}),Y)try{$.input=f_8(Y)}catch(O){let A=new mq(`Unable to parse tool parameter JSON from model. Please retry your request or adjust your prompt. Error: ${O}. JSON: ${Y}`);x1(this,y_8,"f").call(this,A)}_.content[K.index]=$}break}case"thinking_delta":{if(z?.type==="thinking")_.content[K.index]={...z,thinking:z.thinking+K.delta.thinking};break}case"signature_delta":{if(z?.type==="thinking")_.content[K.index]={...z,signature:K.delta.signature};break}case"compaction_delta":{if(z?.type==="compaction")_.content[K.index]={...z,content:(z.content||"")+K.delta.content};break}default:QM7(K.delta)}return _}case"content_block_stop":return _}},Symbol.asyncIterator)](){let q=[],K=[],_=!1;return this.on("streamEvent",(z)=>{let Y=K.shift();if(Y)Y.resolve(z);else q.push(z)}),this.on("end",()=>{_=!0;for(let z of K)z.resolve(void 0);K.length=0}),this.on("abort",(z)=>{_=!0;for(let Y of K)Y.reject(z);K.length=0}),this.on("error",(z)=>{_=!0;for(let Y of K)Y.reject(z);K.length=0}),{next:async()=>{if(!q.length){if(_)return{value:void 0,done:!0};return new Promise((Y,$)=>K.push({resolve:Y,reject:$})).then((Y)=>Y?{value:Y,done:!1}:{value:void 0,done:!0})}return{value:q.shift(),done:!1}},return:async()=>{return this.abort(),{value:void 0,done:!0}}}}toReadableStream(){return new rv(this[Symbol.asyncIterator].bind(this),this.controller).toReadableStream()}}});var NP6;var E_8=L(()=>{NP6=class NP6 extends Error{constructor(q){let K=typeof q==="string"?q:q.map((_)=>{if(_.type==="text")return _.text;return`[${_.type}]`}).join(" ")
|
||||
|
||||
if(q==="abort"){let z=K[0];if(!x1(this,n96,"f")&&!_?.length)Promise.reject(z);x1(this,aI6,"f").call(this,z),x1(this,tI6,"f").call(this,z),this._emit("end");return}if(q==="error"){let z=K[0];if(!x1(this,n96,"f")&&!_?.length)Promise.reject(z);x1(this,aI6,"f").call(this,z),x1(this,tI6,"f").call(this,z),this._emit("end")}}_emitFinal(){if(this.receivedMessages.at(-1))this._emit("finalMessage",x1(this,GR,"m",Gs8).call(this))}async _fromReadableStream(q,K){let _=K?.signal,z;if(_){if(_.aborted)this.controller.abort();z=this.controller.abort.bind(this.controller),_.addEventListener("abort",z)}try{x1(this,GR,"m",Ts8).call(this),this._connected(null);let Y=rv.fromReadableStream(q,this.controller);for await(let $ of Y)x1(this,GR,"m",ks8).call(this,$);if(Y.controller.signal?.aborted)throw new c_;x1(this,GR,"m",Vs8).call(this)}finally{if(_&&z)_.removeEventListener("abort",z)}}[(ye=new WeakMap,hP6=new WeakMap,oI6=new WeakMap,L_8=new WeakMap,aI6=new WeakMap,sI6=new WeakMap,h_8=new WeakMap,tI6=new WeakMap,Tl=new WeakMap,eI6=new WeakMap,R_8=new WeakMap,S_8=new WeakMap,n96=new WeakMap,C_8=new WeakMap,b_8=new WeakMap,qu6=new WeakMap,vs8=new WeakMap,GR=new WeakSet,Gs8=function(){if(this.receivedMessages.length===0)throw new mq("stream ended without producing a Message with role=assistant");return this.receivedMessages.at(-1)},sM7=function(){if(this.receivedMessages.length===0)throw new mq("stream ended without producing a Message with role=assistant");let K=this.receivedMessages.at(-1).content.filter((_)=>_.type==="text").map((_)=>_.text);if(K.length===0)throw new mq("stream ended without producing a content block with type=text");return K.join(" ")},Ts8=function(){if(this.ended)return;J4(this,ye,void 0,"f")},ks8=function(K){if(this.ended)return;let _=x1(this,GR,"m",tM7).call(this,K);switch(this._emit("streamEvent",K,_),K.type){case"content_block_delta":{let z=_.content.at(-1);switch(K.delta.type){case"text_delta":{if(z.type==="text")this._emit("text",K.delta.text,z.text||"")
|
||||
|
||||
break}case"citations_delta":{if(z.type==="text")this._emit("citation",K.delta.citation,z.citations??[]);break}case"input_json_delta":{if(qX7(z)&&z.input)this._emit("inputJson",K.delta.partial_json,z.input);break}case"thinking_delta":{if(z.type==="thinking")this._emit("thinking",K.delta.thinking,z.thinking);break}case"signature_delta":{if(z.type==="thinking")this._emit("signature",z.signature);break}default:KX7(K.delta)}break}case"message_stop":{this._addMessageParam(_),this._addMessage(Ds8(_,x1(this,hP6,"f"),{logger:x1(this,qu6,"f")}),!0);break}case"content_block_stop":{this._emit("contentBlock",_.content.at(-1));break}case"message_start":{J4(this,ye,_,"f");break}case"content_block_start":case"message_delta":break}},Vs8=function(){if(this.ended)throw new mq("stream has ended, this shouldn't happen");let K=x1(this,ye,"f");if(!K)throw new mq("request ended without sending any chunks");return J4(this,ye,void 0,"f"),Ds8(K,x1(this,hP6,"f"),{logger:x1(this,qu6,"f")})},tM7=function(K){let _=x1(this,ye,"f");if(K.type==="message_start"){if(_)throw new mq(`Unexpected event order, got ${K.type} before receiving "message_stop"`);return K.message}if(!_)throw new mq(`Unexpected event order, got ${K.type} before "message_start"`);switch(K.type){case"message_stop":return _;case"message_delta":if(_.stop_reason=K.delta.stop_reason,_.stop_sequence=K.delta.stop_sequence,_.usage.output_tokens=K.usage.output_tokens,K.usage.input_tokens!=null)_.usage.input_tokens=K.usage.input_tokens;if(K.usage.cache_creation_input_tokens!=null)_.usage.cache_creation_input_tokens=K.usage.cache_creation_input_tokens;if(K.usage.cache_read_input_tokens!=null)_.usage.cache_read_input_tokens=K.usage.cache_read_input_tokens;if(K.usage.server_tool_use!=null)_.usage.server_tool_use=K.usage.server_tool_use;return _;case"content_block_start":return _.content.push({...K.content_block}),_;case"content_block_delta":{let z=_.content.at(K.index);switch(K.delta.type){case"text_delta":{if(z?.type==="text")_.content[K.index]={...z,text:(z.text||"")+K.delta.text}
|
||||
|
||||
break}case"citations_delta":{if(z?.type==="text")_.content[K.index]={...z,citations:[...z.citations??[],K.delta.citation]};break}case"input_json_delta":{if(z&&qX7(z)){let Y=z[eM7]||"";Y+=K.delta.partial_json;let $={...z};if(Object.defineProperty($,eM7,{value:Y,enumerable:!1,writable:!0}),Y)$.input=f_8(Y);_.content[K.index]=$}break}case"thinking_delta":{if(z?.type==="thinking")_.content[K.index]={...z,thinking:z.thinking+K.delta.thinking};break}case"signature_delta":{if(z?.type==="thinking")_.content[K.index]={...z,signature:K.delta.signature};break}default:KX7(K.delta)}return _}case"content_block_stop":return _}},Symbol.asyncIterator)](){let q=[],K=[],_=!1;return this.on("streamEvent",(z)=>{let Y=K.shift();if(Y)Y.resolve(z);else q.push(z)}),this.on("end",()=>{_=!0;for(let z of K)z.resolve(void 0);K.length=0}),this.on("abort",(z)=>{_=!0;for(let Y of K)Y.reject(z);K.length=0}),this.on("error",(z)=>{_=!0;for(let Y of K)Y.reject(z);K.length=0}),{next:async()=>{if(!q.length){if(_)return{value:void 0,done:!0};return new Promise((Y,$)=>K.push({resolve:Y,reject:$})).then((Y)=>Y?{value:Y,done:!1}:{value:void 0,done:!0})}return{value:q.shift(),done:!1}},return:async()=>{return this.abort(),{value:void 0,done:!0}}}}toReadableStream(){return new rv(this[Symbol.asyncIterator].bind(this),this.controller).toReadableStream()}}});var _u6;var Ns8=L(()=>{uB();NE();js8();ve();Ge();_u6=class _u6 extends AH{create(q,K){return this._client.post("/v1/messages/batches",{body:q,...K})}retrieve(q,K){return this._client.get(jj`/v1/messages/batches/${q}`,K)}list(q={},K){return this._client.getAPIList("/v1/messages/batches",qI,{query:q,...K})}delete(q,K){return this._client.delete(jj`/v1/messages/batches/${q}`,K)}cancel(q,K){return this._client.post(jj`/v1/messages/batches/${q}/cancel`,K)}async results(q,K){let _=await this.retrieve(q);if(!_.results_url)throw new mq(`No batch \`results_url\`; Has it finished processing? ${_.processing_status} - ${_.id}`)
|
||||
|
||||
return!0})),z=F$Y(_.map((O)=>O.message.content),t77),Y=g0K(process.env.CLAUDE_CODE_TEST_FIXTURES_ROOT??Z8(),`fixtures/${z.map((O)=>I0K("sha1").update(g6(O)).digest("hex").slice(0,6)).join("-")}.json`);try{let O=l8(await m0K(Y,{encoding:"utf8"}));return O.output.forEach(g$Y),O.output.map((A,w)=>x0K(A,Q$Y,w,p$Y()))}catch(O){if(d1(O)!=="ENOENT")throw O}if(Y7.isCI&&!c6(process.env.VCR_RECORD))throw Error(`Anthropic API fixture missing: ${Y}. Re-run tests with VCR_RECORD=1, then commit the result. Input messages:
|
||||
${g6(z,null,2)}`);let $=await K();if(Y7.isCI&&!c6(process.env.VCR_RECORD))return $;return await u0K(B0K(Y),{recursive:!0}),await p0K(Y,g6({input:z,output:$.map((O,A)=>x0K(O,t77,A))},null,2),{encoding:"utf8"}),$}function g$Y(q){if(q.type==="stream_event")return;let K=q.message.model,_=q.message.usage,z=x86(K,_);Fh6(z,_,K)}function F$Y(q,K){return q.map((_)=>{if(typeof _==="string")return K(_);return _.map((z)=>{switch(z.type){case"tool_result":if(typeof z.content==="string")return{...z,content:K(z.content)};if(Array.isArray(z.content))return{...z,content:z.content.map((Y)=>{switch(Y.type){case"text":return{...Y,text:K(Y.text)};case"image":return Y;default:return}})};return z;case"text":return{...z,text:K(z.text)};case"tool_use":return{...z,input:YF8(z.input,K)};case"image":return z;default:return}})})}function YF8(q,K){return SC(q,(_,z)=>{if(Array.isArray(_))return _.map((Y)=>YF8(Y,K));if(HD6(_))return YF8(_,K);return K(_,z,q)})}function U$Y(q,K,_,z){return{uuid:z??`UUID-${_}`,requestId:"REQUEST_ID",timestamp:q.timestamp,message:{...q.message,content:q.message.content.map((Y)=>{switch(Y.type){case"text":return{...Y,text:K(Y.text),citations:Y.citations||[]};case"tool_use":return{...Y,input:YF8(Y.input,K)};default:return Y}}).filter(Boolean)},type:"assistant"}}function x0K(q,K,_,z){if(q.type==="assistant")return U$Y(q,K,_,z);else return q}function t77(q){if(typeof q!=="string")return q
|
||||
|
||||
for(let A of O){if(A.type==="tool_use")_.add(A.id);if(A.type==="tool_result")z.add(A.tool_use_id)}}let Y=new Set([..._].filter(($)=>!z.has($)&&!K?.has($)));if(Y.size===0)return q;return q.filter(($)=>{if($.type!=="assistant")return!0;let O=$.message.content;if(!Array.isArray(O))return!0;let A=[];for(let w of O)if(w.type==="tool_use")A.push(w.id);if(A.length===0)return!0;return!A.every((w)=>Y.has(w))})}function KS6(q){if(q.type!=="assistant")return null;if(Array.isArray(q.message.content))return q.message.content.filter((K)=>K.type==="text").map((K)=>K.type==="text"?K.text:"").join(`
|
||||
`).trim()||null;return null}function yQ(q){if(q.type!=="user")return null;let K=q.message.content;return Hd(K)}function H47(q){let K=yQ(q);if(K===null)return null;let _=qK(K,"bash-input");if(_)return{text:_,mode:"bash"};let z=qK(K,zG);if(z){let Y=qK(K,gO8)??"";return{text:`${z} ${Y}`,mode:"prompt"}}return{text:dL7(K),mode:"prompt"}}function Z3(q,K=""){return q.filter((_)=>_.type==="text").map((_)=>_.text).join(K)}function Hd(q){if(typeof q==="string")return q;if(Array.isArray(q))return Z3(q,`
|
||||
`).trim()||null;return null}function fS6(q,K,_,z,Y,$,O,A,w){if(q.type!=="stream_event"&&q.type!=="stream_request_start"){if(q.type==="tombstone"){$?.(q.message);return}if(q.type==="tool_use_summary")return;if(q.type==="assistant"){let j=q.message.content.find((H)=>H.type==="thinking");if(j&&j.type==="thinking")O?.(()=>({thinking:j.thinking,isStreaming:!1,streamingEndedAt:Date.now()}))}w?.(()=>null),K(q);return}if(q.type==="stream_request_start"){z("requesting");return}if(q.event.type==="message_start"){if(q.ttftMs!=null)A?.({ttftMs:q.ttftMs})}if(q.event.type==="message_stop"){z("tool-use"),Y(()=>[]);return}switch(q.event.type){case"content_block_start":switch(w?.(()=>null),q.event.content_block.type){case"thinking":case"redacted_thinking":z("thinking");return;case"text":z("responding");return;case"tool_use":{z("tool-input");let j=q.event.content_block,H=q.event.index;Y((J)=>[...J,{index:H,contentBlock:j,unparsedToolInput:""}])
|
||||
|
||||
return}case"server_tool_use":case"web_search_tool_result":case"code_execution_tool_result":case"mcp_tool_use":case"mcp_tool_result":case"container_upload":case"web_fetch_tool_result":case"bash_code_execution_tool_result":case"text_editor_code_execution_tool_result":case"tool_search_tool_result":case"compaction":z("tool-input");return}return;case"content_block_delta":switch(q.event.delta.type){case"text_delta":{let j=q.event.delta.text;_(j),w?.((H)=>(H??"")+j);return}case"input_json_delta":{let j=q.event.delta.partial_json,H=q.event.index;_(j),Y((J)=>{let M=J.find((X)=>X.index===H);if(!M)return J;return[...J.filter((X)=>X!==M),{...M,unparsedToolInput:M.unparsedToolInput+j}]});return}case"thinking_delta":_(q.event.delta.thinking);return;case"signature_delta":return;default:return}case"content_block_stop":return;case"message_delta":z("responding");return;default:z("responding");return}}function Nv(q){return`<system-reminder>
|
||||
${q}
|
||||
</system-reminder>`}function V9(q){return q.map((K)=>{if(typeof K.message.content==="string")return{...K,message:{...K.message,content:Nv(K.message.content)}};else if(Array.isArray(K.message.content)){let _=K.message.content.map((z)=>{if(z.type==="text")return{...z,text:Nv(z.text)};return z});return{...K,message:{...K.message,content:_}}}return K})}function A2Y(q){if(q.isSubAgent)return D2Y(q);if(q.reminderType==="sparse")return W2Y(q);return M2Y(q)}function J2Y(){let q=QB8();switch(q){case"trim":return w2Y;case"cut":return j2Y;case"cap":return H2Y;case null:return mvK;default:return mvK}}function M2Y(q){if(q.isSubAgent)return[];if(s2())return P2Y(q)
|
||||
|
||||
if(oO8(b8,$.querySource),K8=b8.max_tokens,g3("query_api_request_sent"),!$.agentId)vM("api_request_sent");let E1=Dq();e=E1==="firstParty"&&OM()||E1==="anthropicAws"&&!process.env.ANTHROPIC_AWS_BASE_URL?ql8():void 0;let _7=await r6.beta.messages.create({...b8,stream:!0},{signal:Y,...e&&{headers:{[cG6]:e}}}).withResponse();return g3("query_response_headers_received"),H6=_7.request_id,a=_7.response,_7.data},{model:$.model,fallbackModel:$.fallbackModel,thinkingConfig:_,...gK()?{fastMode:g}:!1,signal:Y,querySource:$.querySource}),b6;do if(b6=await m6.next(),!("controller"in b6.value))yield b6.value;while(!b6.done);G6=b6.value,X6.length=0,v6=0,x6=void 0,R6.length=0,W6=wf,Z6=null,k6=!1;let T6=c6(process.env.CLAUDE_ENABLE_STREAM_WATCHDOG),s=parseInt(process.env.CLAUDE_STREAM_IDLE_TIMEOUT_MS||"",10)||90000,$6=s/2,h6=!1,P6=null,V6=null,S6=null;e6(),Vg8("api_call");try{let r6=!0,R8=null,C8=30000,b8=0,E1=0;for await(let D1 of G6){e6();let M7=Date.now();if(R8!==null){let N7=M7-R8;if(N7>C8)E1++,b8+=N7,N(`Streaming stall detected: ${(N7/1000).toFixed(1)}s gap between events (stall #${E1})`,{level:"warn"}),d("tengu_streaming_stall",{stall_duration_ms:N7,stall_count:E1,total_stall_time_ms:b8,event_type:D1.type,model:$.model,request_id:H6??"unknown"})}if(R8=M7,r6){if(N("Stream started - received first chunk"),g3("query_first_chunk_received"),!$.agentId)vM("first_chunk");tfK(),r6=!1}switch(D1.type){case"message_start":{x6=D1.message,v6=Date.now()-z6,W6=x56(W6,D1.message?.usage);break}case"content_block_start":switch(D1.content_block.type){case"tool_use":R6[D1.index]={...D1.content_block,input:""};break;case"server_tool_use":if(R6[D1.index]={...D1.content_block,input:""},D1.content_block.name==="advisor")k6=!0,N("[AdvisorTool] Advisor tool called"),d("tengu_advisor_tool_call",{model:$.model,advisor_model:H??"unknown"});break;case"text":R6[D1.index]={...D1.content_block,text:""};break;case"thinking":R6[D1.index]={...D1.content_block,thinking:"",signature:""};break
|
||||
|
||||
default:if(R6[D1.index]={...D1.content_block},D1.content_block.type==="advisor_tool_result")k6=!1,N("[AdvisorTool] Advisor tool result received");break}break;case"content_block_delta":{let N7=R6[D1.index],P1=D1.delta;if(!N7)throw d("tengu_streaming_error",{error_type:"content_block_not_found_delta",part_type:D1.type,part_index:D1.index}),RangeError("Content block not found");switch(P1.type){case"citations_delta":break;case"input_json_delta":if(N7.type!=="tool_use"&&N7.type!=="server_tool_use")throw d("tengu_streaming_error",{error_type:"content_block_type_mismatch_input_json",expected_type:"tool_use",actual_type:N7.type}),Error("Content block is not a input_json block");if(typeof N7.input!=="string")throw d("tengu_streaming_error",{error_type:"content_block_input_not_string",input_type:typeof N7.input}),Error("Content block input is not a string");N7.input+=P1.partial_json;break;case"text_delta":if(N7.type!=="text")throw d("tengu_streaming_error",{error_type:"content_block_type_mismatch_text",expected_type:"text",actual_type:N7.type}),Error("Content block is not a text block");N7.text+=P1.text;break;case"signature_delta":if(N7.type!=="thinking")throw d("tengu_streaming_error",{error_type:"content_block_type_mismatch_thinking_signature",expected_type:"thinking",actual_type:N7.type}),Error("Content block is not a thinking block");N7.signature=P1.signature;break;case"thinking_delta":if(N7.type!=="thinking")throw d("tengu_streaming_error",{error_type:"content_block_type_mismatch_thinking_delta",expected_type:"thinking",actual_type:N7.type}),Error("Content block is not a thinking block");N7.thinking+=P1.thinking;break}break}case"content_block_stop":{let N7=R6[D1.index];if(!N7)throw d("tengu_streaming_error",{error_type:"content_block_not_found_stop",part_type:D1.type,part_index:D1.index}),RangeError("Content block not found");if(!x6)throw d("tengu_streaming_error",{error_type:"partial_message_not_found",part_type:D1.type}),Error("Message not found")
|
||||
|
||||
let P1={message:{...x6,content:UF8([N7],z,$.agentId)},requestId:H6??void 0,type:"assistant",uuid:ql8(),timestamp:new Date().toISOString(),...!1,...H&&{advisorModel:H}};X6.push(P1),yield P1;break}case"message_delta":{W6=x56(W6,D1.usage),Z6=D1.delta.stop_reason;let N7=X6.at(-1);if(N7)N7.message.usage=W6,N7.message.stop_reason=Z6;let P1=x86(A,W6);N6+=Fh6(P1,W6,$.model);let D7=WTK(D1.delta.stop_reason,$.model);if(D7)yield D7;if(Z6==="max_tokens")d("tengu_max_tokens_reached",{max_tokens:K8}),yield U9({content:`${MW}: Claude's response exceeded the ${K8} output token maximum. To configure this behavior, set the CLAUDE_CODE_MAX_OUTPUT_TOKENS environment variable.`,apiError:"max_output_tokens",error:"max_output_tokens"});if(Z6==="model_context_window_exceeded")d("tengu_context_window_exceeded",{max_tokens:K8,output_tokens:W6.output_tokens}),yield U9({content:`${MW}: The model has reached its context window limit.`,apiError:"max_output_tokens",error:"max_output_tokens"});break}case"message_stop":break}yield{type:"stream_event",event:D1,...D1.type==="message_start"?{ttftMs:v6}:void 0}}if(q8(),h6){let D1=P6!==null?Math.round(performance.now()-P6):-1;throw a8("info","cli_stream_loop_exited_after_watchdog_clean"),d("tengu_stream_loop_exited_after_watchdog",{request_id:H6??"unknown",exit_delay_ms:D1,exit_path:"clean",model:$.model}),P6=null,Error("Stream idle timeout - no chunks received")}if(!x6||X6.length===0&&!Z6)throw N(!x6?"Stream completed without receiving message_start event - triggering non-streaming fallback":"Stream completed with message_start but no content blocks completed - triggering non-streaming fallback",{level:"error"}),d("tengu_stream_no_events",{model:$.model,request_id:H6??"unknown"}),Error("Stream ended without receiving any events");if(E1>0)N(`Streaming completed with ${E1} stall(s), total stall time: ${(b8/1000).toFixed(1)}s`,{level:"warn"}),d("tengu_streaming_stall_summary",{stall_count:E1,total_stall_time_ms:b8,model:$.model,request_id:H6??"unknown"});let _7=a
|
||||
|
||||
if(_=_.replace("/ws/","/session/"),!_.endsWith("/events"))_=_.endsWith("/")?_+"events":_+"/events";return`${K}//${q.host}${_}${q.search}`}var eBY=100,qgY=15000,KgY=3000,FK8;var Q$7=L(()=>{VK();_8();w$();tL();F$7();U$7();FK8=class FK8 extends gK8{postUrl;uploader;streamEventBuffer=[];streamEventTimer=null;constructor(q,K={},_,z,Y){super(q,K,_,z,Y);let{maxConsecutiveFailures:$,onBatchDropped:O}=Y??{};this.postUrl=_gY(q),this.uploader=new MM6({maxBatchSize:500,maxQueueSize:1e5,baseDelayMs:500,maxDelayMs:8000,jitterMs:1000,maxConsecutiveFailures:$,onBatchDropped:(A,w)=>{a8("error","cli_hybrid_batch_dropped_max_failures",{batchSize:A,failures:w}),O?.(A,w)},send:(A)=>this.postOnce(A)}),N(`HybridTransport: POST URL = ${this.postUrl}`),a8("info","cli_hybrid_transport_initialized")}async write(q){if(q.type==="stream_event"){if(this.streamEventBuffer.push(q),!this.streamEventTimer)this.streamEventTimer=setTimeout(()=>this.flushStreamEvents(),eBY);return}return await this.uploader.enqueue([...this.takeStreamEvents(),q]),this.uploader.flush()}async writeBatch(q){return await this.uploader.enqueue([...this.takeStreamEvents(),...q]),this.uploader.flush()}get droppedBatchCount(){return this.uploader.droppedBatchCount}flush(){return this.uploader.enqueue(this.takeStreamEvents()),this.uploader.flush()}takeStreamEvents(){if(this.streamEventTimer)clearTimeout(this.streamEventTimer),this.streamEventTimer=null;let q=this.streamEventBuffer;return this.streamEventBuffer=[],q}flushStreamEvents(){this.streamEventTimer=null,this.uploader.enqueue(this.takeStreamEvents())}close(){if(this.streamEventTimer)clearTimeout(this.streamEventTimer),this.streamEventTimer=null;this.streamEventBuffer=[];let q=this.uploader,K;Promise.race([q.flush(),new Promise((_)=>{K=setTimeout(_,KgY)})]).finally(()=>{clearTimeout(K),q.close()}),super.close()}async postOnce(q){let K=FD();if(!K){N("HybridTransport: No session token available for POST"),a8("warn","cli_hybrid_post_no_token");return}let _={Authorization:`Bearer ${K}`,"Content-Type":"application/json"},z
|
||||
|
||||
try{z=await O1.post(this.postUrl,{events:q},{headers:_,validateStatus:()=>!0,timeout:qgY})}catch(Y){throw N(`HybridTransport: POST error: ${Y.message}`),a8("warn","cli_hybrid_post_network_error"),Y}if(z.status>=200&&z.status<300){N(`HybridTransport: POST success count=${q.length}`);return}if(z.status>=400&&z.status<500&&z.status!==429){N(`HybridTransport: POST returned ${z.status} (permanent), dropping`),a8("warn","cli_hybrid_post_client_error",{status:z.status});return}throw N(`HybridTransport: POST returned ${z.status} (retryable)`),a8("warn","cli_hybrid_post_retryable_error",{status:z.status}),Error(`POST failed with ${z.status}`)}}});class d$7{inflight=null;pending=null;closed=!1;config;constructor(q){this.config=q}enqueue(q){if(this.closed)return;this.pending=this.pending?JnK(this.pending,q):q,this.drain()}close(){this.closed=!0,this.pending=null}async drain(){if(this.inflight||this.closed)return;if(!this.pending)return;let q=this.pending;this.pending=null,this.inflight=this.sendWithRetry(q).then(()=>{if(this.inflight=null,this.pending&&!this.closed)this.drain()})}async sendWithRetry(q){let K=q,_=0;while(!this.closed){if(await this.config.send(K))return;if(_++,await C7(this.retryDelay(_)),this.pending&&!this.closed)K=JnK(K,this.pending),this.pending=null}}retryDelay(q){let K=Math.min(this.config.baseDelayMs*2**(q-1),this.config.maxDelayMs),_=Math.random()*this.config.jitterMs;return K+_}}function JnK(q,K){let _={...q};for(let[z,Y]of Object.entries(K))if((z==="external_metadata"||z==="internal_metadata")&&_[z]&&typeof _[z]==="object"&&typeof Y==="object"&&Y!==null)_[z]={..._[z],...Y};else _[z]=Y;return _}var MnK=()=>{};import{randomUUID as XnK}from"crypto";function PnK(){return!0}function OgY(){return{byMessage:new Map,scopeToMessage:new Map}}function Ll8(q){return`${q.session_id}:${q.parent_tool_use_id??""}`}function AgY(q,K){let _=[],z=new Map;for(let Y of q)switch(Y.event.type){case"message_start":{let $=Y.event.message.id,O=K.scopeToMessage.get(Ll8(Y));if(O)K.byMessage.delete(O)
|
||||
|
||||
K.scopeToMessage.set(Ll8(Y),$),K.byMessage.set($,[]),_.push(Y);break}case"content_block_delta":{if(Y.event.delta.type!=="text_delta"){_.push(Y);break}let $=K.scopeToMessage.get(Ll8(Y)),O=$?K.byMessage.get($):void 0;if(!O){_.push(Y);break}let A=O[Y.event.index]??=[];A.push(Y.event.delta.text);let w=z.get(A);if(w){w.event.delta.text=A.join("");break}let j={type:"stream_event",uuid:Y.uuid,session_id:Y.session_id,parent_tool_use_id:Y.parent_tool_use_id,event:{type:"content_block_delta",index:Y.event.index,delta:{type:"text_delta",text:A.join("")}}};z.set(A,j),_.push(j);break}default:_.push(Y)}return _}function wgY(q,K){q.byMessage.delete(K.message.id);let _=Ll8(K);if(q.scopeToMessage.get(_)===K.message.id)q.scopeToMessage.delete(_)}class UK8{workerEpoch=0;heartbeatIntervalMs;heartbeatJitterFraction;heartbeatTimer=null;heartbeatInFlight=!1;closed=!1;consecutiveAuthFailures=0;currentState=null;sessionBaseUrl;sessionId;http=v4q({keepAlive:!0});streamEventBuffer=[];streamEventTimer=null;streamTextAccumulator=OgY();workerState;eventUploader;internalEventUploader;deliveryUploader;onEpochMismatch;getAuthHeaders;constructor(q,K,_){if(this.onEpochMismatch=_?.onEpochMismatch??(()=>{process.exit(1)}),this.heartbeatIntervalMs=_?.heartbeatIntervalMs??zgY,this.heartbeatJitterFraction=_?.heartbeatJitterFraction??0,this.getAuthHeaders=_?.getAuthHeaders??Vy6,K.protocol!=="http:"&&K.protocol!=="https:")throw Error(`CCRClient: Expected http(s) URL, got ${K.protocol}`);let z=K.pathname.replace(/\/$/,"");this.sessionBaseUrl=`${K.protocol}//${K.host}${z}`,this.sessionId=z.split("/").pop()||"",this.workerState=new d$7({send:(Y)=>this.request("put","/worker",{worker_epoch:this.workerEpoch,...Y},"PUT worker").then(($)=>$.ok),baseDelayMs:500,maxDelayMs:30000,jitterMs:500}),this.eventUploader=new MM6({maxBatchSize:100,maxBatchBytes:10485760,maxQueueSize:1e5,send:async(Y)=>{let $=await this.request("post","/worker/events",{worker_epoch:this.workerEpoch,events:Y},"client events")
|
||||
|
||||
this.currentState=q,this.workerState.enqueue({worker_status:q,requires_action_details:K?{tool_name:K.tool_name,action_description:K.action_description,request_id:K.request_id}:null})}reportMetadata(q){this.workerState.enqueue({external_metadata:q})}handleEpochMismatch(){N("CCRClient: Epoch mismatch (409), shutting down",{level:"error"}),a8("error","cli_worker_epoch_mismatch"),this.onEpochMismatch()}startHeartbeat(){this.stopHeartbeat();let q=()=>{let _=this.heartbeatIntervalMs*this.heartbeatJitterFraction*(2*Math.random()-1);this.heartbeatTimer=setTimeout(K,this.heartbeatIntervalMs+_)},K=()=>{if(this.sendHeartbeat(),this.heartbeatTimer===null)return;q()};q()}stopHeartbeat(){if(this.heartbeatTimer)clearTimeout(this.heartbeatTimer),this.heartbeatTimer=null}async sendHeartbeat(){if(this.heartbeatInFlight)return;this.heartbeatInFlight=!0;try{if((await this.request("post","/worker/heartbeat",{session_id:this.sessionId,worker_epoch:this.workerEpoch},"Heartbeat",{timeout:5000})).ok)N("CCRClient: Heartbeat sent")}finally{this.heartbeatInFlight=!1}}async writeEvent(q){if(q.type==="stream_event"){if(this.streamEventBuffer.push(q),!this.streamEventTimer)this.streamEventTimer=setTimeout(()=>void this.flushStreamEventBuffer(),YgY);return}if(await this.flushStreamEventBuffer(),q.type==="assistant")wgY(this.streamTextAccumulator,q);await this.eventUploader.enqueue(this.toClientEvent(q))}toClientEvent(q){let K=q;return{payload:{...K,uuid:typeof K.uuid==="string"?K.uuid:XnK()}}}async flushStreamEventBuffer(){if(this.streamEventTimer)clearTimeout(this.streamEventTimer),this.streamEventTimer=null;if(this.streamEventBuffer.length===0)return;let q=this.streamEventBuffer;this.streamEventBuffer=[];let K=AgY(q,this.streamTextAccumulator);await this.eventUploader.enqueue(K.map((_)=>({payload:_,ephemeral:!0})))}async writeInternalEvent(q,K,{isCompaction:_=!1,agentId:z}={}){let Y={payload:{type:q,...K,uuid:typeof K.uuid==="string"?K.uuid:XnK()},..._&&{is_compaction:!0},...z&&{agent_id:z}}
|
||||
|
||||
return{type:"system",subtype:"informational",content:K?q.errors?.join(", ")||"Unknown error":"Session completed successfully",level:K?"warning":"info",uuid:q.uuid,timestamp:new Date().toISOString()}}function NnY(q){return{type:"system",subtype:"informational",content:`Remote session initialized (model: ${q.model})`,level:"info",uuid:q.uuid,timestamp:new Date().toISOString()}}function ynY(q){if(!q.status)return null;return{type:"system",subtype:"informational",content:q.status==="compacting"?"Compacting conversation…":`Status: ${q.status}`,level:"info",uuid:q.uuid,timestamp:new Date().toISOString()}}function EnY(q){return{type:"system",subtype:"informational",content:`Tool ${q.tool_name} running for ${q.elapsed_time_seconds}s…`,level:"info",uuid:q.uuid,timestamp:new Date().toISOString(),toolUseID:q.tool_use_id}}function LnY(q){return{type:"system",subtype:"compact_boundary",content:"Conversation compacted",level:"info",uuid:q.uuid,timestamp:new Date().toISOString(),compactMetadata:M_7(q.compact_metadata)}}function uM6(q,K){switch(q.type){case"assistant":return{type:"message",message:TnY(q)};case"user":{let _=q.message?.content,z=Array.isArray(_)&&_.some((Y)=>Y.type==="tool_result");if(K?.convertToolResults&&z)return{type:"message",message:n8({content:_,toolUseResult:q.tool_use_result,uuid:q.uuid,timestamp:q.timestamp})};if(K?.convertUserTextMessages&&!z){if(typeof _==="string"||Array.isArray(_))return{type:"message",message:n8({content:_,toolUseResult:q.tool_use_result,uuid:q.uuid,timestamp:q.timestamp})}}return{type:"ignored"}}case"stream_event":return{type:"stream_event",event:knY(q)};case"result":if(q.subtype!=="success")return{type:"message",message:VnY(q)};return{type:"ignored"};case"system":if(q.subtype==="init")return{type:"message",message:NnY(q)};if(q.subtype==="status"){let _=ynY(q);return _?{type:"message",message:_}:{type:"ignored"}}if(q.subtype==="compact_boundary")return{type:"message",message:LnY(q)};return N(`[sdkMessageAdapter] Ignoring system message subtype: ${q.subtype}`),{type:"ignored"}
|
||||
|
||||
filter to type=="text")
|
||||
echo "$response" | jq -r '.content[] | select(.type == "text") | .text'
|
||||
\`\`\`
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Streaming (SSE)
|
||||
|
||||
\`\`\`bash
|
||||
curl https://api.anthropic.com/v1/messages \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \\
|
||||
-H "anthropic-version: 2023-06-01" \\
|
||||
-d '{
|
||||
"model": "{{OPUS_ID}}",
|
||||
"max_tokens": 64000,
|
||||
"stream": true,
|
||||
"messages": [{"role": "user", "content": "Write a haiku"}]
|
||||
}'
|
||||
\`\`\`
|
||||
|
||||
The response is a stream of Server-Sent Events:
|
||||
|
||||
\`\`\`
|
||||
event: message_start
|
||||
data: {"type":"message_start","message":{"id":"msg_...","type":"message",...}}
|
||||
|
||||
event: content_block_start
|
||||
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
|
||||
|
||||
event: content_block_delta
|
||||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
|
||||
|
||||
event: content_block_stop
|
||||
data: {"type":"content_block_stop","index":0}
|
||||
|
||||
event: message_delta
|
||||
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":12}}
|
||||
|
||||
event: message_stop
|
||||
data: {"type":"message_stop"}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Tool Use
|
||||
|
||||
\`\`\`bash
|
||||
curl https://api.anthropic.com/v1/messages \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \\
|
||||
-H "anthropic-version: 2023-06-01" \\
|
||||
-d '{
|
||||
"model": "{{OPUS_ID}}",
|
||||
"max_tokens": 16000,
|
||||
"tools": [{
|
||||
"name": "get_weather",
|
||||
"description": "Get current weather for a location",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {"type": "string", "description": "City name"}
|
||||
},
|
||||
"required": ["location"]
|
||||
}
|
||||
}],
|
||||
"messages": [{"role": "user", "content": "What is the weather in Paris?"}]
|
||||
}'
|
||||
\`\`\`
|
||||
|
||||
When Claude responds with a \`tool_use\` block, send the result back:
|
||||
|
||||
\`\`\`bash
|
||||
curl https://api.anthropic.com/v1/messages \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \\
|
||||
-H "anthropic-version: 2023-06-01" \\
|
||||
-d '{
|
||||
"model": "{{OPUS_ID}}",
|
||||
"max_tokens": 16000,
|
||||
"tools": [{
|
||||
"name": "get_weather",
|
||||
"description": "Get current weather for a location",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {"type": "string", "description": "City name"}
|
||||
},
|
||||
"required": ["location"]
|
||||
}
|
||||
}],
|
||||
"messages": [
|
||||
{"role": "user", "content": "What is the weather in Paris?"},
|
||||
{"role": "assistant", "content": [
|
||||
{"type": "text", "text": "Let me check the weather."},
|
||||
{"type": "tool_use", "id": "toolu_abc123", "name": "get_weather", "input": {"location": "Paris"}}
|
||||
]},
|
||||
{"role": "user", "content": [
|
||||
{"type": "tool_result", "tool_use_id": "toolu_abc123", "content": "72°F and sunny"}
|
||||
]}
|
||||
]
|
||||
}'
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Prompt Caching
|
||||
|
||||
Put \`cache_control\` on the last block of the stable prefix. See \`shared/prompt-caching.md\` for placement patterns and the silent-invalidator audit checklist.
|
||||
|
||||
\`\`\`bash
|
||||
curl https://api.anthropic.com/v1/messages \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \\
|
||||
-H "anthropic-version: 2023-06-01" \\
|
||||
-d '{
|
||||
"model": "{{OPUS_ID}}",
|
||||
"max_tokens": 16000,
|
||||
"system": [
|
||||
{"type": "text", "text": "<large shared prompt...>", "cache_control": {"type": "ephemeral"}}
|
||||
],
|
||||
"messages": [{"role": "user", "content": "Summarize the key points"}]
|
||||
}'
|
||||
\`\`\`
|
||||
|
||||
For 1-hour TTL: \`"cache_control": {"type": "ephemeral", "ttl": "1h"}\`. Top-level \`"cache_control"\` on the request body auto-places on the last cacheable block. Verify hits via the response \`usage.cache_creation_input_tokens\` / \`usage.cache_read_input_tokens\` fields.
|
||||
|
||||
---
|
||||
|
||||
## Extended Thinking
|
||||
|
||||
> **Opus 4.6 and Sonnet 4.6:** Use adaptive thinking. \`budget_tokens\` is deprecated on both Opus 4.6 and Sonnet 4.6.
|
||||
> **Older models:** Use \`"type": "enabled"\` with \`"budget_tokens": N\` (must be < \`max_tokens\`, min 1024).
|
||||
|
||||
\`\`\`bash
|
||||
# Opus 4.6: adaptive thinking (recommended)
|
||||
curl https://api.anthropic.com/v1/messages \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \\
|
||||
-H "anthropic-version: 2023-06-01" \\
|
||||
-d '{
|
||||
"model": "{{OPUS_ID}}",
|
||||
"max_tokens": 16000,
|
||||
"thinking": {
|
||||
"type": "adaptive"
|
||||
},
|
||||
"output_config": {
|
||||
"effort": "high"
|
||||
},
|
||||
"messages": [{"role": "user", "content": "Solve this step by step..."}]
|
||||
}'
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Required Headers
|
||||
|
||||
| Header | Value | Description |
|
||||
| ------------------- | ------------------ | -------------------------- |
|
||||
| \`Content-Type\` | \`application/json\` | Required |
|
||||
| \`x-api-key\` | Your API key | Authentication |
|
||||
| \`anthropic-version\` | \`2023-06-01\` | API version |
|
||||
| \`anthropic-beta\` | Beta feature IDs | Required for beta features |
|
||||
`
|
||||
|
||||
var U45=`# Streaming — Python
|
||||
|
||||
## Quick Start
|
||||
|
||||
\`\`\`python
|
||||
with client.messages.stream(
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=64000,
|
||||
messages=[{"role": "user", "content": "Write a story"}]
|
||||
) as stream:
|
||||
for text in stream.text_stream:
|
||||
print(text, end="", flush=True)
|
||||
\`\`\`
|
||||
|
||||
### Async
|
||||
|
||||
\`\`\`python
|
||||
async with async_client.messages.stream(
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=64000,
|
||||
messages=[{"role": "user", "content": "Write a story"}]
|
||||
) as stream:
|
||||
async for text in stream.text_stream:
|
||||
print(text, end="", flush=True)
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Handling Different Content Types
|
||||
|
||||
Claude may return text, thinking blocks, or tool use. Handle each appropriately:
|
||||
|
||||
> **Opus 4.6:** Use \`thinking: {type: "adaptive"}\`. On older models, use \`thinking: {type: "enabled", budget_tokens: N}\` instead.
|
||||
|
||||
\`\`\`python
|
||||
with client.messages.stream(
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=64000,
|
||||
thinking={"type": "adaptive"},
|
||||
messages=[{"role": "user", "content": "Analyze this problem"}]
|
||||
) as stream:
|
||||
for event in stream:
|
||||
if event.type == "content_block_start":
|
||||
if event.content_block.type == "thinking":
|
||||
print("\\n[Thinking...]")
|
||||
elif event.content_block.type == "text":
|
||||
print("\\n[Response:]")
|
||||
|
||||
elif event.type == "content_block_delta":
|
||||
if event.delta.type == "thinking_delta":
|
||||
print(event.delta.thinking, end="", flush=True)
|
||||
elif event.delta.type == "text_delta":
|
||||
print(event.delta.text, end="", flush=True)
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Streaming with Tool Use
|
||||
|
||||
The Python tool runner currently returns complete messages. Use streaming for individual API calls within a manual loop if you need per-token streaming with tools:
|
||||
|
||||
\`\`\`python
|
||||
with client.messages.stream(
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=64000,
|
||||
tools=tools,
|
||||
messages=messages
|
||||
) as stream:
|
||||
for text in stream.text_stream:
|
||||
print(text, end="", flush=True)
|
||||
|
||||
response = stream.get_final_message()
|
||||
# Continue with tool execution if response.stop_reason == "tool_use"
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Getting the Final Message
|
||||
|
||||
\`\`\`python
|
||||
with client.messages.stream(
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=64000,
|
||||
messages=[{"role": "user", "content": "Hello"}]
|
||||
) as stream:
|
||||
for text in stream.text_stream:
|
||||
print(text, end="", flush=True)
|
||||
|
||||
# Get full message after streaming
|
||||
final_message = stream.get_final_message()
|
||||
print(f"\\n\\nTokens used: {final_message.usage.output_tokens}")
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Streaming with Progress Updates
|
||||
|
||||
\`\`\`python
|
||||
def stream_with_progress(client, **kwargs):
|
||||
"""Stream a response with progress updates."""
|
||||
total_tokens = 0
|
||||
content_parts = []
|
||||
|
||||
with client.messages.stream(**kwargs) as stream:
|
||||
for event in stream:
|
||||
if event.type == "content_block_delta":
|
||||
if event.delta.type == "text_delta":
|
||||
text = event.delta.text
|
||||
content_parts.append(text)
|
||||
print(text, end="", flush=True)
|
||||
|
||||
elif event.type == "message_delta":
|
||||
if event.usage and event.usage.output_tokens is not None:
|
||||
total_tokens = event.usage.output_tokens
|
||||
|
||||
final_message = stream.get_final_message()
|
||||
|
||||
print(f"\\n\\n[Tokens used: {total_tokens}]")
|
||||
return "".join(content_parts)
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Error Handling in Streams
|
||||
|
||||
\`\`\`python
|
||||
try:
|
||||
with client.messages.stream(
|
||||
model="{{OPUS_ID}}",
|
||||
max_tokens=64000,
|
||||
messages=[{"role": "user", "content": "Write a story"}]
|
||||
) as stream:
|
||||
for text in stream.text_stream:
|
||||
print(text, end="", flush=True)
|
||||
except anthropic.APIConnectionError:
|
||||
print("\\nConnection lost. Please retry.")
|
||||
except anthropic.RateLimitError:
|
||||
print("\\nRate limited. Please wait and retry.")
|
||||
except anthropic.APIStatusError as e:
|
||||
print(f"\\nAPI error: {e.status_code}")
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Stream Event Types
|
||||
|
||||
| Event Type | Description | When it fires |
|
||||
| --------------------- | --------------------------- | --------------------------------- |
|
||||
| \`message_start\` | Contains message metadata | Once at the beginning |
|
||||
| \`content_block_start\` | New content block beginning | When a text/tool_use block starts |
|
||||
| \`content_block_delta\` | Incremental content update | For each token/chunk |
|
||||
| \`content_block_stop\` | Content block complete | When a block finishes |
|
||||
| \`message_delta\` | Message-level updates | Contains \`stop_reason\`, usage |
|
||||
| \`message_stop\` | Message complete | Once at the end |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always flush output** — Use \`flush=True\` to show tokens immediately
|
||||
2. **Handle partial responses** — If the stream is interrupted, you may have incomplete content
|
||||
3. **Track token usage** — The \`message_delta\` event contains usage information
|
||||
4. **Use timeouts** — Set appropriate timeouts for your application
|
||||
5. **Default to streaming** — Use \`.get_final_message()\` to get the complete response even when streaming, giving you timeout protection without needing to handle individual events
|
||||
`
|
||||
|
||||
for await (const event of stream) {
|
||||
if (
|
||||
event.type === "content_block_delta" &&
|
||||
event.delta.type === "text_delta"
|
||||
) {
|
||||
process.stdout.write(event.delta.text);
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Handling Different Content Types
|
||||
|
||||
> **Opus 4.6:** Use \`thinking: {type: "adaptive"}\`. On older models, use \`thinking: {type: "enabled", budget_tokens: N}\` instead.
|
||||
|
||||
\`\`\`typescript
|
||||
const stream = client.messages.stream({
|
||||
model: "{{OPUS_ID}}",
|
||||
max_tokens: 64000,
|
||||
thinking: { type: "adaptive" },
|
||||
messages: [{ role: "user", content: "Analyze this problem" }],
|
||||
});
|
||||
|
||||
for await (const event of stream) {
|
||||
switch (event.type) {
|
||||
case "content_block_start":
|
||||
switch (event.content_block.type) {
|
||||
case "thinking":
|
||||
console.log("\\n[Thinking...]");
|
||||
break;
|
||||
case "text":
|
||||
console.log("\\n[Response:]");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "content_block_delta":
|
||||
switch (event.delta.type) {
|
||||
case "thinking_delta":
|
||||
process.stdout.write(event.delta.thinking);
|
||||
break;
|
||||
case "text_delta":
|
||||
process.stdout.write(event.delta.text);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Streaming with Tool Use (Tool Runner)
|
||||
|
||||
Use the tool runner with \`stream: true\`. The outer loop iterates over tool runner iterations (messages), the inner loop processes stream events:
|
||||
|
||||
\`\`\`typescript
|
||||
import Anthropic from "@anthropic-ai/sdk";
|
||||
import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
const client = new Anthropic();
|
||||
|
||||
const getWeather = betaZodTool({
|
||||
name: "get_weather",
|
||||
description: "Get current weather for a location",
|
||||
inputSchema: z.object({
|
||||
location: z.string().describe("City and state, e.g., San Francisco, CA"),
|
||||
}),
|
||||
run: async ({ location }) => \`72°F and sunny in \${location}\`,
|
||||
})
|
||||
|
||||
const runner = client.beta.messages.toolRunner({
|
||||
model: "{{OPUS_ID}}",
|
||||
max_tokens: 64000,
|
||||
tools: [getWeather],
|
||||
messages: [
|
||||
{ role: "user", content: "What's the weather in Paris and London?" },
|
||||
],
|
||||
stream: true,
|
||||
});
|
||||
|
||||
// Outer loop: each tool runner iteration
|
||||
for await (const messageStream of runner) {
|
||||
// Inner loop: stream events for this iteration
|
||||
for await (const event of messageStream) {
|
||||
switch (event.type) {
|
||||
case "content_block_delta":
|
||||
switch (event.delta.type) {
|
||||
case "text_delta":
|
||||
process.stdout.write(event.delta.text);
|
||||
break;
|
||||
case "input_json_delta":
|
||||
// Tool input being streamed
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Getting the Final Message
|
||||
|
||||
\`\`\`typescript
|
||||
const stream = client.messages.stream({
|
||||
model: "{{OPUS_ID}}",
|
||||
max_tokens: 64000,
|
||||
messages: [{ role: "user", content: "Hello" }],
|
||||
});
|
||||
|
||||
for await (const event of stream) {
|
||||
// Process events...
|
||||
}
|
||||
|
||||
const finalMessage = await stream.finalMessage();
|
||||
console.log(\`Tokens used: \${finalMessage.usage.output_tokens}\`)
|
||||
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
## Stream Event Types
|
||||
|
||||
| Event Type | Description | When it fires |
|
||||
| --------------------- | --------------------------- | --------------------------------- |
|
||||
| \`message_start\` | Contains message metadata | Once at the beginning |
|
||||
| \`content_block_start\` | New content block beginning | When a text/tool_use block starts |
|
||||
| \`content_block_delta\` | Incremental content update | For each token/chunk |
|
||||
| \`content_block_stop\` | Content block complete | When a block finishes |
|
||||
| \`message_delta\` | Message-level updates | Contains \`stop_reason\`, usage |
|
||||
| \`message_stop\` | Message complete | Once at the end |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always flush output** — Use \`process.stdout.write()\` for immediate display
|
||||
2. **Handle partial responses** — If the stream is interrupted, you may have incomplete content
|
||||
3. **Track token usage** — The \`message_delta\` event contains usage information
|
||||
4. **Use \`finalMessage()\`** — Get the complete \`Anthropic.Message\` object even when streaming. Don't wrap \`.on()\` events in \`new Promise()\` — \`finalMessage()\` handles all completion/error/abort states internally
|
||||
5. **Buffer for web UIs** — Consider buffering a few tokens before rendering to avoid excessive DOM updates
|
||||
6. **Use \`stream.on("text", ...)\` for deltas** — The \`text\` event provides just the delta string, simpler than manually filtering \`content_block_delta\` events
|
||||
7. **For agentic loops with streaming** — See the [Streaming Manual Loop](./tool-use.md#streaming-manual-loop) section in tool-use.md for combining \`stream()\` + \`finalMessage()\` with a tool-use loop
|
||||
|
||||
## Raw SSE Format
|
||||
|
||||
If using raw HTTP (not SDKs), the stream returns Server-Sent Events:
|
||||
|
||||
\`\`\`
|
||||
event: message_start
|
||||
data: {"type":"message_start","message":{"id":"msg_...","type":"message",...}}
|
||||
|
||||
event: content_block_start
|
||||
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
|
||||
|
||||
event: content_block_delta
|
||||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
|
||||
|
||||
event: content_block_stop
|
||||
data: {"type":"content_block_stop","index":0}
|
||||
|
||||
event: message_delta
|
||||
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":12}}
|
||||
|
||||
event: message_stop
|
||||
data: {"type":"message_stop"}
|
||||
\`\`\`
|
||||
`
|
||||
|
||||
break;case"stream_event":if(b6.event.type==="message_start")x6=wf,x6=x56(x6,b6.event.message.usage);if(b6.event.type==="message_delta"){if(x6=x56(x6,b6.event.usage),b6.event.delta.stop_reason!=null)I6=b6.event.delta.stop_reason}if(b6.event.type==="message_stop")this.totalUsage=Ug8(this.totalUsage,x6);if(v)yield{type:"stream_event",event:b6.event,session_id:N8(),parent_tool_use_id:null,uuid:pc()};break;case"attachment":if(this.mutableMessages.push(b6),R)e.push(b6),l();if(b6.attachment.type==="structured_output")N6=b6.attachment.data;else if(b6.attachment.type==="hook_deferred_tool")Z6={id:b6.attachment.toolUseID,name:b6.attachment.toolName,input:b6.attachment.toolInput};else if(b6.attachment.type==="max_turns_reached"){X8={turnCount:b6.attachment.turnCount,maxTurns:b6.attachment.maxTurns};continue}else if(Z&&b6.attachment.type==="queued_command"){let T6=b6.attachment;yield{type:"user",message:{role:"user",content:T6.prompt},session_id:N8(),parent_tool_use_id:null,uuid:T6.source_uuid||b6.uuid,timestamp:b6.timestamp,isReplay:!0,...T6.fileAttachments?.length&&{file_attachments:T6.fileAttachments}}}break;case"stream_request_start":break;case"system":{let T6=this.config.snipReplay?.(b6,this.mutableMessages);if(T6!==void 0){if(T6.executed)this.mutableMessages.length=0,this.mutableMessages.push(...T6.messages);break}if(this.mutableMessages.push(b6),b6.subtype==="compact_boundary"&&b6.compactMetadata){let s=this.mutableMessages.length-1;if(s>0)this.mutableMessages.splice(0,s);let $6=e.length-1;if($6>0)e.splice(0,$6),a=e.length;yield{type:"system",subtype:"compact_boundary",session_id:N8(),uuid:b6.uuid,compact_metadata:bd8(b6.compactMetadata)}}if(b6.subtype==="api_error")yield{type:"system",subtype:"api_retry",attempt:b6.retryAttempt,max_retries:b6.maxRetries,retry_delay_ms:b6.retryInMs,error_status:b6.error.status??null,error:PTK(b6.error),session_id:N8(),uuid:b6.uuid};break}case"tool_use_summary":yield{type:"tool_use_summary",summary:b6.summary,preceding_tool_use_ids:b6.precedingToolUseIds,session_id:N8(),uuid:b6.uuid}
|
||||
|
|
@ -0,0 +1,861 @@
|
|||
"tengu_startup_perf"
|
||||
"tengu_compact_line_prefix_killswitch"
|
||||
"tengu_atomic_write_error"
|
||||
"tengu_oauth_token_exchange_success"
|
||||
"tengu_oauth_token_refresh_success"
|
||||
"tengu_oauth_token_refresh_failure"
|
||||
"tengu_oauth_roles_stored"
|
||||
"tengu_oauth_api_key"
|
||||
"tengu_oauth_profile_fetch_success"
|
||||
"tengu_penguins_off"
|
||||
"tengu_marble_sandcastle"
|
||||
"tengu_fast_mode_fallback_triggered"
|
||||
"tengu_fast_mode_overage_rejected"
|
||||
"tengu_org_penguin_mode_fetch_failed"
|
||||
"tengu_unknown_model_cost"
|
||||
"tengu_auto_mode_config"
|
||||
"tengu_tool_pear"
|
||||
"tengu_amber_json_tools"
|
||||
"tengu_apiKeyHelper_missing_trust11"
|
||||
"tengu_awsAuthRefresh_missing_trust"
|
||||
"tengu_awsCredentialExport_missing_trust"
|
||||
"tengu_gcpAuthRefresh_missing_trust"
|
||||
"tengu_api_key_saved_to_keychain"
|
||||
"tengu_api_key_keychain_error"
|
||||
"tengu_api_key_saved_to_config"
|
||||
"tengu_oauth_tokens_not_claude_ai"
|
||||
"tengu_oauth_tokens_inference_only"
|
||||
"tengu_oauth_tokens_saved"
|
||||
"tengu_oauth_tokens_save_failed"
|
||||
"tengu_oauth_tokens_save_exception"
|
||||
"tengu_oauth_401_recovered_from_keychain"
|
||||
"tengu_oauth_token_refresh_lock_acquiring"
|
||||
"tengu_oauth_token_refresh_lock_acquired"
|
||||
"tengu_oauth_token_refresh_lock_retry"
|
||||
"tengu_oauth_token_refresh_lock_retry_limit_reached"
|
||||
"tengu_oauth_token_refresh_lock_error"
|
||||
"tengu_oauth_token_refresh_race_resolved"
|
||||
"tengu_oauth_token_refresh_starting"
|
||||
"tengu_oauth_token_refresh_race_recovered"
|
||||
"tengu_oauth_token_refresh_lock_releasing"
|
||||
"tengu_oauth_token_refresh_lock_released"
|
||||
"tengu_amber_flint"
|
||||
"tengu_frond_boric"
|
||||
"tengu_event_sampling_config"
|
||||
"tengu_1p_event_batch_config"
|
||||
"tengu_passport_quail"
|
||||
"tengu_slate_thimble"
|
||||
"tengu_herring_clock"
|
||||
"tengu_config_auth_loss_prevented"
|
||||
"tengu_config_cache_stats"
|
||||
"tengu_config_lock_contention"
|
||||
"tengu_config_stale_write"
|
||||
"tengu_config_parse_error"
|
||||
"tengu_api_error"
|
||||
"tengu_api_success"
|
||||
"tengu_brief_mode_enabled"
|
||||
"tengu_brief_mode_toggled"
|
||||
"tengu_brief_send"
|
||||
"tengu_cancel"
|
||||
"tengu_compact_failed"
|
||||
"tengu_exit"
|
||||
"tengu_flicker"
|
||||
"tengu_init"
|
||||
"tengu_model_fallback_triggered"
|
||||
"tengu_oauth_error"
|
||||
"tengu_oauth_success"
|
||||
"tengu_oauth_token_refresh_completed"
|
||||
"tengu_query_error"
|
||||
"tengu_session_file_read"
|
||||
"tengu_started"
|
||||
"tengu_tool_use_error"
|
||||
"tengu_tool_use_granted_in_prompt_permanent"
|
||||
"tengu_tool_use_granted_in_prompt_temporary"
|
||||
"tengu_tool_use_rejected_in_prompt"
|
||||
"tengu_tool_use_success"
|
||||
"tengu_uncaught_exception"
|
||||
"tengu_unhandled_rejection"
|
||||
"tengu_voice_recording_started"
|
||||
"tengu_voice_toggled"
|
||||
"tengu_team_mem_sync_pull"
|
||||
"tengu_team_mem_sync_push"
|
||||
"tengu_team_mem_sync_started"
|
||||
"tengu_team_mem_entries_capped"
|
||||
"tengu_log_datadog_events"
|
||||
"tengu_attribution_header"
|
||||
"tengu_relpath_gh7k"
|
||||
"tengu_noreread_q7m_velvet"
|
||||
"tengu_maple_forge_w8k"
|
||||
"tengu_ripgrep_eagain_retry"
|
||||
"tengu_ripgrep_availability"
|
||||
"tengu_dir_search"
|
||||
"tengu_plugin_remote_fetch"
|
||||
"tengu_turtle_carbon"
|
||||
"tengu_slate_finch"
|
||||
"tengu_grey_step2"
|
||||
"tengu_amber_stoat"
|
||||
"tengu_agent_parse_error"
|
||||
"tengu_glacier_2xr"
|
||||
"tengu_slate_heron"
|
||||
"tengu_time_based_microcompact"
|
||||
"tengu_claude_md_permission_error"
|
||||
"tengu_claude_rules_md_permission_error"
|
||||
"tengu_moth_copse"
|
||||
"tengu_paper_halyard"
|
||||
"tengu_claudemd__initial_load"
|
||||
"tengu_session_memory_loaded"
|
||||
"tengu_tool_search_outcome"
|
||||
"tengu_disable_keepalive_on_econnreset"
|
||||
"tengu_api_529_background_dropped"
|
||||
"tengu_api_opus_fallback_triggered"
|
||||
"tengu_api_custom_529_overloaded_error"
|
||||
"tengu_max_tokens_context_overflow_adjustment"
|
||||
"tengu_api_retry"
|
||||
"tengu_api_persistent_retry_wait"
|
||||
"tengu_image_api_validation_failed"
|
||||
"tengu_image_resize_failed"
|
||||
"tengu_image_resize_fallback"
|
||||
"tengu_image_compress_failed"
|
||||
"tengu_headless_latency"
|
||||
"tengu_tool_use_granted_in_config"
|
||||
"tengu_tool_use_granted_by_classifier"
|
||||
"tengu_tool_use_granted_by_permission_hook"
|
||||
"tengu_tool_use_denied_in_config"
|
||||
"tengu_tree_sitter_parse_abort"
|
||||
"tengu_vscode_review_upsell"
|
||||
"tengu_vscode_onboarding"
|
||||
"tengu_quiet_fern"
|
||||
"tengu_vscode_cc_auth"
|
||||
"tengu_garnet_plover"
|
||||
"tengu_claudeai_limits_status_changed"
|
||||
"tengu_prompt_suggestion_init"
|
||||
"tengu_chomp_inflection"
|
||||
"tengu_prompt_suggestion"
|
||||
"tengu_speculation"
|
||||
"tengu_kairos_cron"
|
||||
"tengu_kairos_cron_durable"
|
||||
"tengu_keybinding_customization_release"
|
||||
"tengu_custom_keybindings_loaded"
|
||||
"tengu_keybinding_fallback_used"
|
||||
"tengu_message_actions_enter"
|
||||
"tengu_satin_quoll"
|
||||
"tengu_claudeai_mcp_eligibility"
|
||||
"tengu_builtin_mcp_toggle"
|
||||
"tengu_mcp_oauth_flow_success"
|
||||
"tengu_mcp_oauth_flow_failure"
|
||||
"tengu_mcp_oauth_flow_start"
|
||||
"tengu_mcp_oauth_flow_error"
|
||||
"tengu_mcp_oauth_refresh_success"
|
||||
"tengu_mcp_oauth_refresh_failure"
|
||||
"tengu_tool_empty_result"
|
||||
"tengu_tool_result_persisted"
|
||||
"tengu_hawthorn_window"
|
||||
"tengu_hawthorn_steeple"
|
||||
"tengu_tool_result_persisted_message_budget"
|
||||
"tengu_message_level_tool_result_budget_enforced"
|
||||
"tengu_mcp_subagent_prompt"
|
||||
"tengu_binary_content_persisted"
|
||||
"tengu_ext_installed"
|
||||
"tengu_ext_install_error"
|
||||
"tengu_mcp_elicitation_shown"
|
||||
"tengu_mcp_elicitation_response"
|
||||
"tengu_mcp_headersHelper_missing_trust"
|
||||
"tengu_collage_kaleidoscope"
|
||||
"tengu_malort_pedway"
|
||||
"tengu_mcp_server_needs_auth"
|
||||
"tengu_mcp_claudeai_proxy_401"
|
||||
"tengu_mcp_tools_commands_loaded"
|
||||
"tengu_mcp_large_result_handled"
|
||||
"tengu_code_indexing_tool_used"
|
||||
"tengu_mcp_tool_call_auth_error"
|
||||
"tengu_mcp_session_expired"
|
||||
"tengu_mcp_ide_server_connection_failed"
|
||||
"tengu_mcp_ide_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_succeeded"
|
||||
"tengu_mcp_server_connection_failed"
|
||||
"tengu_auto_mode_malformed_tool_input"
|
||||
"tengu_auto_mode_outcome"
|
||||
"tengu_agent_tool_completed"
|
||||
"tengu_cache_eviction_hint"
|
||||
"tengu_auto_mode_decision"
|
||||
"tengu_agent_tool_terminated"
|
||||
"tengu_sage_compass"
|
||||
"tengu_message_rated"
|
||||
"tengu_sessions_elevated_auth_enforcement"
|
||||
"tengu_grove_print_viewed"
|
||||
"tengu_managed_settings_security_dialog_shown"
|
||||
"tengu_managed_settings_security_dialog_accepted"
|
||||
"tengu_managed_settings_security_dialog_rejected"
|
||||
"tengu_trace_lantern"
|
||||
"tengu_oauth_automatic_redirect"
|
||||
"tengu_oauth_automatic_redirect_error"
|
||||
"tengu_oauth_auth_code_received"
|
||||
"tengu_version_config"
|
||||
"tengu_max_version_config"
|
||||
"tengu_auto_updater_lock_contention"
|
||||
"tengu_auto_updater_windows_npm_in_wsl"
|
||||
"tengu_version_check_success"
|
||||
"tengu_version_check_failure"
|
||||
"tengu_binary_download_attempt"
|
||||
"tengu_binary_manifest_fetch_failure"
|
||||
"tengu_binary_platform_not_found"
|
||||
"tengu_binary_download_success"
|
||||
"tengu_binary_download_failure"
|
||||
"tengu_pid_based_version_locking"
|
||||
"tengu_version_lock_acquired"
|
||||
"tengu_version_lock_failed"
|
||||
"tengu_native_install_package_failure"
|
||||
"tengu_native_install_package_success"
|
||||
"tengu_native_install_binary_failure"
|
||||
"tengu_native_install_binary_success"
|
||||
"tengu_native_update_skipped_max_version"
|
||||
"tengu_native_update_complete"
|
||||
"tengu_native_update_skipped_minimum_version"
|
||||
"tengu_native_update_lock_failed"
|
||||
"tengu_native_staging_cleanup"
|
||||
"tengu_native_stale_locks_cleanup"
|
||||
"tengu_native_temp_files_cleanup"
|
||||
"tengu_native_version_cleanup"
|
||||
"tengu_oauth_storage_warning"
|
||||
"tengu_login_from_refresh_token"
|
||||
"tengu_oauth_flow_start"
|
||||
"tengu_notification_method_used"
|
||||
"tengu_agent_memory_loaded"
|
||||
"tengu_kairos_brief"
|
||||
"tengu_oauth_claudeai_forced"
|
||||
"tengu_oauth_console_forced"
|
||||
"tengu_oauth_manual_entry"
|
||||
"tengu_oauth_token_exchange_error"
|
||||
"tengu_oauth_platform_selected"
|
||||
"tengu_oauth_claudeai_selected"
|
||||
"tengu_oauth_console_selected"
|
||||
"tengu_plugin_enabled_for_session"
|
||||
"tengu_plugin_load_failed"
|
||||
"tengu_slash_command_forked"
|
||||
"tengu_input_slash_missing"
|
||||
"tengu_input_slash_invalid"
|
||||
"tengu_input_prompt"
|
||||
"tengu_input_command"
|
||||
"tengu_slim_subagent_claudemd"
|
||||
"tengu_cobalt_lantern"
|
||||
"tengu_ccr_bundle_seed_enabled"
|
||||
"tengu_file_history_track_edit_failed"
|
||||
"tengu_file_history_track_edit_success"
|
||||
"tengu_file_history_backup_deleted_file"
|
||||
"tengu_file_history_backup_file_failed"
|
||||
"tengu_file_history_snapshot_success"
|
||||
"tengu_file_history_snapshot_failed"
|
||||
"tengu_file_history_rewind_failed"
|
||||
"tengu_file_history_rewind_success"
|
||||
"tengu_file_history_rewind_restore_file_failed"
|
||||
"tengu_file_history_backup_file_created"
|
||||
"tengu_file_history_resume_copy_failed"
|
||||
"tengu_file_upload_failed"
|
||||
"tengu_ccr_bundle_upload"
|
||||
"tengu_ccr_bundle_max_bytes"
|
||||
"tengu_teleport_error_git_not_clean"
|
||||
"tengu_teleport_error_branch_checkout_failed"
|
||||
"tengu_teleport_resume_error"
|
||||
"tengu_teleport_error_repo_not_in_git_dir_sessions_api"
|
||||
"tengu_teleport_error_repo_mismatch_sessions_api"
|
||||
"tengu_teleport_errors_detected"
|
||||
"tengu_teleport_errors_resolved"
|
||||
"tengu_teleport_error_session_not_found_404"
|
||||
"tengu_teleport_bundle_mode"
|
||||
"tengu_teleport_source_decision"
|
||||
"tengu_skill_tool_invocation"
|
||||
"tengu_skill_tool_slash_prefix"
|
||||
"tengu_lapis_finch"
|
||||
"tengu_plugin_hint_detected"
|
||||
"tengu_shell_snapshot_failed"
|
||||
"tengu_shell_unknown_error"
|
||||
"tengu_shell_snapshot_error"
|
||||
"tengu_shell_set_cwd"
|
||||
"tengu_bash_tool_reset_to_original_dir"
|
||||
"tengu_git_operation"
|
||||
"tengu_powershell_command_timeout_backgrounded"
|
||||
"tengu_powershell_command_explicitly_backgrounded"
|
||||
"tengu_powershell_command_interrupt_backgrounded"
|
||||
"tengu_powershell_tool_command_executed"
|
||||
"tengu_dynamic_skills_changed"
|
||||
"tengu_advisor_tool_token_usage"
|
||||
"tengu_file_changed"
|
||||
"tengu_file_operation"
|
||||
"tengu_editafterwrite_qpl"
|
||||
"tengu_edit_minimalanchor_jrn"
|
||||
"tengu_write_claudemd"
|
||||
"tengu_edit_string_lengths"
|
||||
"tengu_quartz_lantern"
|
||||
"tengu_tool_use_diff_computed"
|
||||
"tengu_sub_nomdrep_q7k"
|
||||
"tengu_subagent_md_report_blocked"
|
||||
"tengu_write_append_used"
|
||||
"tengu_plum_vx3"
|
||||
"tengu_exit_plan_mode_called_outside_plan"
|
||||
"tengu_plan_mode_interview_phase"
|
||||
"tengu_pewter_ledger"
|
||||
"tengu_worktree_created"
|
||||
"tengu_worktree_kept"
|
||||
"tengu_worktree_removed"
|
||||
"tengu_gypsum_kite"
|
||||
"tengu_amber_quartz_disabled"
|
||||
"tengu_cobalt_frost"
|
||||
"tengu_config_tool_changed"
|
||||
"tengu_surreal_dali"
|
||||
"tengu_team_created"
|
||||
"tengu_team_deleted"
|
||||
"tengu_agent_list_attach"
|
||||
"tengu_willow_prism"
|
||||
"tengu_auto_background_agents"
|
||||
"tengu_agent_tool_selected"
|
||||
"tengu_team_mem_secret_skipped"
|
||||
"tengu_team_mem_push_suppressed"
|
||||
"tengu_session_memory_accessed"
|
||||
"tengu_transcript_accessed"
|
||||
"tengu_memdir_accessed"
|
||||
"tengu_memdir_file_read"
|
||||
"tengu_memdir_file_edit"
|
||||
"tengu_memdir_file_write"
|
||||
"tengu_team_mem_accessed"
|
||||
"tengu_team_mem_file_read"
|
||||
"tengu_team_mem_file_edit"
|
||||
"tengu_team_mem_file_write"
|
||||
"tengu_bash_command_timeout_backgrounded"
|
||||
"tengu_bash_command_explicitly_backgrounded"
|
||||
"tengu_git_index_lock_error"
|
||||
"tengu_bash_tool_command_executed"
|
||||
"tengu_bash_ast_too_complex"
|
||||
"tengu_post_tool_hooks_cancelled"
|
||||
"tengu_post_tool_hook_error"
|
||||
"tengu_post_tool_failure_hooks_cancelled"
|
||||
"tengu_post_tool_failure_hook_error"
|
||||
"tengu_pre_tool_hooks_cancelled"
|
||||
"tengu_pre_tool_hook_error"
|
||||
"tengu_tool_use_cancelled"
|
||||
"tengu_tool_use_progress"
|
||||
"tengu_deferred_tool_schema_not_sent"
|
||||
"tengu_pre_tool_hook_deferred"
|
||||
"tengu_tool_use_can_use_tool_rejected"
|
||||
"tengu_tool_use_can_use_tool_allowed"
|
||||
"tengu_onyx_plover"
|
||||
"tengu_auto_mem_tool_denied"
|
||||
"tengu_extract_memories_skipped_direct_write"
|
||||
"tengu_extract_memories_skipped_no_prose"
|
||||
"tengu_bramble_lintel"
|
||||
"tengu_extract_memories_extraction"
|
||||
"tengu_extract_memories_error"
|
||||
"tengu_extract_memories_coalesced"
|
||||
"tengu_auto_dream_fired"
|
||||
"tengu_auto_dream_completed"
|
||||
"tengu_auto_dream_failed"
|
||||
"tengu_pre_stop_hooks_cancelled"
|
||||
"tengu_stop_hook_error"
|
||||
"tengu_streaming_tool_execution2"
|
||||
"tengu_auto_compact_rapid_refill_breaker"
|
||||
"tengu_auto_compact_succeeded"
|
||||
"tengu_orphaned_messages_tombstoned"
|
||||
"tengu_otk_slot_v1"
|
||||
"tengu_max_tokens_escalate"
|
||||
"tengu_streaming_tool_execution_used"
|
||||
"tengu_streaming_tool_execution_not_used"
|
||||
"tengu_post_autocompact_turn"
|
||||
"tengu_query_before_attachments"
|
||||
"tengu_query_after_attachments"
|
||||
"tengu_api_query"
|
||||
"tengu_teleport_first_message_error"
|
||||
"tengu_teleport_first_message_success"
|
||||
"tengu_forked_agent_default_turns_exceeded"
|
||||
"tengu_fork_agent_query"
|
||||
"tengu_compact_cache_prefix"
|
||||
"tengu_compact_ptl_retry"
|
||||
"tengu_compact"
|
||||
"tengu_partial_compact_failed"
|
||||
"tengu_partial_compact"
|
||||
"tengu_compact_cache_sharing_success"
|
||||
"tengu_compact_cache_sharing_fallback"
|
||||
"tengu_compact_streaming_retry"
|
||||
"tengu_post_compact_file_restore_success"
|
||||
"tengu_post_compact_file_restore_error"
|
||||
"tengu_sm_compact_config"
|
||||
"tengu_session_memory"
|
||||
"tengu_sm_compact"
|
||||
"tengu_sm_compact_no_session_memory"
|
||||
"tengu_sm_compact_empty_template"
|
||||
"tengu_sm_compact_summarized_id_not_found"
|
||||
"tengu_sm_compact_resumed_session"
|
||||
"tengu_sm_compact_threshold_exceeded"
|
||||
"tengu_sm_compact_error"
|
||||
"tengu_cold_compact"
|
||||
"tengu_tool_search_unsupported_models"
|
||||
"tengu_tool_search_mode_decision"
|
||||
"tengu_deferred_tools_pool_change"
|
||||
"tengu_amber_wren"
|
||||
"tengu_pdf_page_extraction"
|
||||
"tengu_slate_reef"
|
||||
"tengu_file_read_limits_override"
|
||||
"tengu_file_read_reread"
|
||||
"tengu_read_dedup_killswitch"
|
||||
"tengu_file_read_dedup"
|
||||
"tengu_mcp_instructions_pool_change"
|
||||
"tengu_attachment_compute_duration"
|
||||
"tengu_ultrathink"
|
||||
"tengu_at_mention_extracting_directory_success"
|
||||
"tengu_at_mention_extracting_filename_success"
|
||||
"tengu_at_mention_extracting_filename_error"
|
||||
"tengu_at_mention_agent_not_found"
|
||||
"tengu_at_mention_agent_success"
|
||||
"tengu_at_mention_mcp_resource_error"
|
||||
"tengu_at_mention_mcp_resource_success"
|
||||
"tengu_watched_file_compression_failed"
|
||||
"tengu_memdir_prefetch_collected"
|
||||
"tengu_attachments"
|
||||
"tengu_pdf_reference_attachment"
|
||||
"tengu_attachment_file_too_large"
|
||||
"tengu_plugin_official_mkt_git_fallback"
|
||||
"tengu_plugin_installed"
|
||||
"tengu_amber_prism"
|
||||
"tengu_toolref_defer_j8m"
|
||||
"tengu_chair_sermon"
|
||||
"tengu_tool_input_json_parse_fail"
|
||||
"tengu_model_whitespace_response"
|
||||
"tengu_filtered_trailing_thinking_block"
|
||||
"tengu_filtered_whitespace_only_assistant"
|
||||
"tengu_fixed_empty_assistant_content"
|
||||
"tengu_filtered_orphaned_thinking_message"
|
||||
"tengu_tool_result_pairing_repaired"
|
||||
"tengu_tool_use_tool_result_mismatch_error"
|
||||
"tengu_unexpected_tool_result"
|
||||
"tengu_duplicate_tool_use_id"
|
||||
"tengu_refusal_api_response"
|
||||
"tengu_cork_m4q"
|
||||
"tengu_bash_prefix"
|
||||
"tengu_auto_mode_denial_limit_exceeded"
|
||||
"tengu_iron_gate_closed"
|
||||
"tengu_disable_bypass_permissions_mode"
|
||||
"tengu_ccr_unsupported_default_mode_ignored"
|
||||
"tengu_bug_report_submitted"
|
||||
"tengu_bug_report_description"
|
||||
"tengu_file_suggestions_git_ls_files"
|
||||
"tengu_file_suggestions_ripgrep"
|
||||
"tengu_file_suggestions_query"
|
||||
"tengu_copy"
|
||||
"tengu_autocompact_command"
|
||||
"tengu_autocompact_dialog_opened"
|
||||
"tengu_ccr_bridge"
|
||||
"tengu_bridge_repl_v2"
|
||||
"tengu_bridge_repl_v2_cse_shim_enabled"
|
||||
"tengu_bridge_min_version"
|
||||
"tengu_model_command_menu_effort"
|
||||
"tengu_claude_md_external_includes_dialog_declined"
|
||||
"tengu_claude_md_external_includes_dialog_accepted"
|
||||
"tengu_claude_md_includes_dialog_shown"
|
||||
"tengu_config_model_changed"
|
||||
"tengu_auto_compact_setting_changed"
|
||||
"tengu_tips_setting_changed"
|
||||
"tengu_reduce_motion_setting_changed"
|
||||
"tengu_thinking_toggled"
|
||||
"tengu_file_history_snapshots_setting_changed"
|
||||
"tengu_terminal_progress_bar_setting_changed"
|
||||
"tengu_terminal_sidebar"
|
||||
"tengu_terminal_tab_status_setting_changed"
|
||||
"tengu_show_turn_duration_setting_changed"
|
||||
"tengu_config_changed"
|
||||
"tengu_respect_gitignore_setting_changed"
|
||||
"tengu_default_view_setting_changed"
|
||||
"tengu_editor_mode_changed"
|
||||
"tengu_pr_status_footer_setting_changed"
|
||||
"tengu_diff_tool_changed"
|
||||
"tengu_auto_connect_ide_changed"
|
||||
"tengu_auto_install_ide_extension_changed"
|
||||
"tengu_claude_in_chrome_setting_changed"
|
||||
"tengu_teammate_mode_changed"
|
||||
"tengu_autoupdate_channel_changed"
|
||||
"tengu_teammate_default_model_changed"
|
||||
"tengu_output_style_changed"
|
||||
"tengu_language_changed"
|
||||
"tengu_autoupdate_enabled"
|
||||
"tengu_overage_credit_upsell_shown"
|
||||
"tengu_auto_memory_toggled"
|
||||
"tengu_auto_dream_toggled"
|
||||
"tengu_memory_toggled"
|
||||
"tengu_ext_ide_command"
|
||||
"tengu_setup_github_actions_failed"
|
||||
"tengu_setup_github_actions_started"
|
||||
"tengu_setup_github_actions_completed"
|
||||
"tengu_install_github_app_started"
|
||||
"tengu_install_github_app_step_completed"
|
||||
"tengu_install_github_app_error"
|
||||
"tengu_install_github_app_completed"
|
||||
"tengu_install_slack_app_clicked"
|
||||
"tengu_harbor_ledger"
|
||||
"tengu_harbor"
|
||||
"tengu_harbor_permissions"
|
||||
"tengu_mcp_channel_gate"
|
||||
"tengu_mcp_channel_message"
|
||||
"tengu_mcp_list_changed"
|
||||
"tengu_mcp_servers"
|
||||
"tengu_claudeai_mcp_auth_completed"
|
||||
"tengu_claudeai_mcp_clear_auth_completed"
|
||||
"tengu_claudeai_mcp_auth_started"
|
||||
"tengu_claudeai_mcp_clear_auth_started"
|
||||
"tengu_claudeai_mcp_toggle"
|
||||
"tengu_mcp_auth_config_authenticate"
|
||||
"tengu_mcp_auth_config_clear"
|
||||
"tengu_claudeai_mcp_reconnect"
|
||||
"tengu_marketplace_added"
|
||||
"tengu_marketplace_removed"
|
||||
"tengu_marketplace_updated"
|
||||
"tengu_powerup_lesson_opened"
|
||||
"tengu_powerup_lesson_completed"
|
||||
"tengu_session_title_generated"
|
||||
"tengu_bridge_repl_skipped"
|
||||
"tengu_worktree_detection"
|
||||
"tengu_guest_passes_upsell_shown"
|
||||
"tengu_session_search_toggled"
|
||||
"tengu_agentic_search_cancelled"
|
||||
"tengu_session_tag_filter_changed"
|
||||
"tengu_session_all_projects_toggled"
|
||||
"tengu_session_branch_filter_toggled"
|
||||
"tengu_session_worktree_filter_toggled"
|
||||
"tengu_session_rename_started"
|
||||
"tengu_session_preview_opened"
|
||||
"tengu_session_group_expanded"
|
||||
"tengu_review_bughunter_config"
|
||||
"tengu_review_overage_not_enabled"
|
||||
"tengu_review_overage_low_balance"
|
||||
"tengu_review_overage_dialog_shown"
|
||||
"tengu_review_remote_precondition_failed"
|
||||
"tengu_review_remote_teleport_failed"
|
||||
"tengu_review_remote_launched"
|
||||
"tengu_transcript_view_enter"
|
||||
"tengu_transcript_view_exit"
|
||||
"tengu_ultraplan_config"
|
||||
"tengu_ultraplan_timeout_seconds"
|
||||
"tengu_ultraplan_model"
|
||||
"tengu_ultraplan_prompt_identifier"
|
||||
"tengu_ultraplan_awaiting_input"
|
||||
"tengu_ultraplan_approved"
|
||||
"tengu_ultraplan_failed"
|
||||
"tengu_ultraplan_stopped"
|
||||
"tengu_ultraplan_create_failed"
|
||||
"tengu_ultraplan_launched"
|
||||
"tengu_thinkback"
|
||||
"tengu_immediate_model_command"
|
||||
"tengu_fast_mode_toggled"
|
||||
"tengu_fast_mode_picker_shown"
|
||||
"tengu_guest_passes_link_copied"
|
||||
"tengu_guest_passes_visited"
|
||||
"tengu_grove_policy_viewed"
|
||||
"tengu_grove_policy_submitted"
|
||||
"tengu_grove_policy_dismissed"
|
||||
"tengu_grove_policy_escaped"
|
||||
"tengu_grove_privacy_settings_viewed"
|
||||
"tengu_grove_policy_toggled"
|
||||
"tengu_hooks_command"
|
||||
"tengu_conversation_forked"
|
||||
"tengu_agent_created"
|
||||
"tengu_agent_definition_generated"
|
||||
"tengu_heap_dump"
|
||||
"tengu_chrome_auto_enable"
|
||||
"tengu_model_command_menu"
|
||||
"tengu_model_command_inline_help"
|
||||
"tengu_model_command_inline"
|
||||
"tengu_tag_command_remove_prompt"
|
||||
"tengu_tag_command_add"
|
||||
"tengu_tag_command_remove_confirmed"
|
||||
"tengu_tag_command_remove_cancelled"
|
||||
"tengu_jade_anvil_4"
|
||||
"tengu_rate_limit_options_menu_cancel"
|
||||
"tengu_rate_limit_options_menu_select_upgrade"
|
||||
"tengu_rate_limit_options_menu_select_extra_usage"
|
||||
"tengu_effort_command"
|
||||
"tengu_kairos_brief_config"
|
||||
"tengu_bridge_repl_v2_config"
|
||||
"tengu_bridge_command"
|
||||
"tengu_voice_silent_drop_replay"
|
||||
"tengu_voice_recording_completed"
|
||||
"tengu_voice_stream_early_retry"
|
||||
"tengu_remote_setup_started"
|
||||
"tengu_remote_setup_result"
|
||||
"tengu_session_persistence_failed"
|
||||
"tengu_relink_walk_broken"
|
||||
"tengu_snip_resume_filtered"
|
||||
"tengu_chain_parent_cycle"
|
||||
"tengu_chain_timestamp_fallback"
|
||||
"tengu_chain_parallel_tr_recovered"
|
||||
"tengu_resume_consistency_delta"
|
||||
"tengu_session_forked_branches_fetched"
|
||||
"tengu_session_renamed"
|
||||
"tengu_session_tagged"
|
||||
"tengu_session_linked_to_pr"
|
||||
"tengu_agent_name_set"
|
||||
"tengu_agent_color_set"
|
||||
"tengu_pebble_leaf_prune"
|
||||
"tengu_transcript_parent_cycle"
|
||||
"tengu_memdir_loaded"
|
||||
"tengu_coral_fern"
|
||||
"tengu_memdir_disabled"
|
||||
"tengu_team_memdir_disabled"
|
||||
"tengu_scratch"
|
||||
"tengu_agent_stop_hook_max_turns"
|
||||
"tengu_agent_stop_hook_error"
|
||||
"tengu_agent_stop_hook_success"
|
||||
"tengu_hook_output_persisted"
|
||||
"tengu_run_hook"
|
||||
"tengu_repl_hook_finished"
|
||||
"tengu_lean_sub_pf7q"
|
||||
"tengu_subagent_lean_schema_applied"
|
||||
"tengu_fgts"
|
||||
"tengu_sysprompt_block"
|
||||
"tengu_sysprompt_using_tool_based_cache"
|
||||
"tengu_sysprompt_boundary_found"
|
||||
"tengu_sysprompt_missing_boundary_marker"
|
||||
"tengu_context_size"
|
||||
"tengu_bash_tool_simple_echo"
|
||||
"tengu_prompt_cache_1h_config"
|
||||
"tengu_nonstreaming_fallback_error"
|
||||
"tengu_off_switch_query"
|
||||
"tengu_api_before_normalize"
|
||||
"tengu_api_after_normalize"
|
||||
"tengu_streaming_idle_timeout"
|
||||
"tengu_streaming_stall"
|
||||
"tengu_advisor_tool_call"
|
||||
"tengu_streaming_error"
|
||||
"tengu_max_tokens_reached"
|
||||
"tengu_context_window_exceeded"
|
||||
"tengu_stream_loop_exited_after_watchdog"
|
||||
"tengu_stream_no_events"
|
||||
"tengu_streaming_stall_summary"
|
||||
"tengu_advisor_tool_interrupted"
|
||||
"tengu_disable_streaming_to_non_streaming_fallback"
|
||||
"tengu_streaming_fallback_to_non_streaming"
|
||||
"tengu_nonstreaming_fallback_started"
|
||||
"tengu_api_cache_breakpoints"
|
||||
"tengu_copper_bridge"
|
||||
"tengu_bridge_token_refreshed"
|
||||
"tengu_bridge_poll_interval_config"
|
||||
"tengu_ccr_bridge_multi_session"
|
||||
"tengu_bridge_heartbeat_error"
|
||||
"tengu_bridge_session_done"
|
||||
"tengu_bridge_reconnected"
|
||||
"tengu_bridge_heartbeat_mode_entered"
|
||||
"tengu_bridge_heartbeat_mode_exited"
|
||||
"tengu_bridge_work_secret_failed"
|
||||
"tengu_bridge_session_started"
|
||||
"tengu_bridge_fatal_error"
|
||||
"tengu_bridge_poll_give_up"
|
||||
"tengu_bridge_shutdown"
|
||||
"tengu_bridge_session_timeout"
|
||||
"tengu_bridge_multi_session_denied"
|
||||
"tengu_bridge_spawn_mode_chosen"
|
||||
"tengu_bridge_registration_failed"
|
||||
"tengu_bridge_started"
|
||||
"tengu_bridge_spawn_mode_toggled"
|
||||
"tengu_bridge_client_presence_enabled"
|
||||
"tengu_bridge_message_received"
|
||||
"tengu_ws_transport_reconnected"
|
||||
"tengu_ws_transport_closed"
|
||||
"tengu_ws_transport_reconnecting"
|
||||
"tengu_bridge_repl_env_registered"
|
||||
"tengu_bridge_repl_session_failed"
|
||||
"tengu_bridge_repl_started"
|
||||
"tengu_bridge_repl_reconnected_in_place"
|
||||
"tengu_bridge_repl_env_expired_fresh_session"
|
||||
"tengu_bridge_repl_ws_closed"
|
||||
"tengu_bridge_repl_reconnect_failed"
|
||||
"tengu_bridge_repl_work_received"
|
||||
"tengu_bridge_repl_ws_connected"
|
||||
"tengu_bridge_repl_history_capped"
|
||||
"tengu_bridge_repl_ccr_v2_init_failed"
|
||||
"tengu_bridge_repl_teardown"
|
||||
"tengu_bridge_repl_suspension_detected"
|
||||
"tengu_bridge_repl_work_secret_failed"
|
||||
"tengu_bridge_repl_env_lost"
|
||||
"tengu_bridge_repl_fatal_error"
|
||||
"tengu_bridge_repl_poll_error"
|
||||
"tengu_bridge_repl_poll_give_up"
|
||||
"tengu_bridge_repl_connect_timeout"
|
||||
"tengu_bridge_initial_history_cap"
|
||||
"tengu_bridge_system_init"
|
||||
"tengu_message_selector_opened"
|
||||
"tengu_message_selector_selected"
|
||||
"tengu_message_selector_restore_option_selected"
|
||||
"tengu_message_selector_cancelled"
|
||||
"tengu_ask_user_question_rejected"
|
||||
"tengu_ask_user_question_respond_to_claude"
|
||||
"tengu_ask_user_question_finish_plan_interview"
|
||||
"tengu_ask_user_question_accepted"
|
||||
"tengu_unary_event"
|
||||
"tengu_tool_use_show_permission_request"
|
||||
"tengu_permission_explainer_generated"
|
||||
"tengu_permission_explainer_error"
|
||||
"tengu_permission_explainer_shortcut_used"
|
||||
"tengu_ext_will_show_diff"
|
||||
"tengu_ext_diff_accepted"
|
||||
"tengu_ext_diff_rejected"
|
||||
"tengu_accept_submitted"
|
||||
"tengu_reject_submitted"
|
||||
"tengu_accept_feedback_mode_collapsed"
|
||||
"tengu_accept_feedback_mode_entered"
|
||||
"tengu_reject_feedback_mode_collapsed"
|
||||
"tengu_reject_feedback_mode_entered"
|
||||
"tengu_permission_request_escape"
|
||||
"tengu_destructive_command_warning"
|
||||
"tengu_permission_request_option_selected"
|
||||
"tengu_plan_enter"
|
||||
"tengu_plan_external_editor_used"
|
||||
"tengu_plan_exit"
|
||||
"tengu_auto_updater_success"
|
||||
"tengu_auto_updater_fail"
|
||||
"tengu_native_auto_updater_start"
|
||||
"tengu_native_auto_updater_lock_contention"
|
||||
"tengu_native_auto_updater_success"
|
||||
"tengu_native_auto_updater_up_to_date"
|
||||
"tengu_native_auto_updater_fail"
|
||||
"tengu_external_editor_hint_shown"
|
||||
"tengu_shell_completion_failed"
|
||||
"tengu_auto_mode_opt_in_dialog_accept"
|
||||
"tengu_auto_mode_opt_in_dialog_accept_default"
|
||||
"tengu_auto_mode_opt_in_dialog_decline"
|
||||
"tengu_auto_mode_opt_in_dialog_shown"
|
||||
"tengu_status_line_mount"
|
||||
"tengu_help_toggled"
|
||||
"tengu_transcript_input_to_teammate"
|
||||
"tengu_paste_image"
|
||||
"tengu_ext_at_mentioned"
|
||||
"tengu_external_editor_used"
|
||||
"tengu_mode_cycle"
|
||||
"tengu_model_picker_hotkey"
|
||||
"tengu_thinking_toggled_hotkey"
|
||||
"tengu_skill_improvement_survey"
|
||||
"tengu_worktree_cleanup"
|
||||
"tengu_lodestone_enabled"
|
||||
"tengu_deep_link_registered"
|
||||
"tengu_toggle_todos"
|
||||
"tengu_toggle_transcript"
|
||||
"tengu_transcript_toggle_show_all"
|
||||
"tengu_transcript_exit"
|
||||
"tengu_input_bash"
|
||||
"tengu_pasted_image_resize_attempt"
|
||||
"tengu_ultraplan_keyword"
|
||||
"tengu_subagent_at_mention"
|
||||
"tengu_paste_text"
|
||||
"tengu_immediate_command_executed"
|
||||
"tengu_skill_file_changed"
|
||||
"tengu_plugins_loaded"
|
||||
"tengu_feedback_survey_config"
|
||||
"tengu_bad_survey_transcript_ask_config"
|
||||
"tengu_good_survey_transcript_ask_config"
|
||||
"tengu_feedback_survey_event"
|
||||
"tengu_dunwich_bell"
|
||||
"tengu_memory_survey_event"
|
||||
"tengu_post_compact_survey_event"
|
||||
"tengu_post_compact_survey"
|
||||
"tengu_official_marketplace_auto_install"
|
||||
"tengu_desktop_upsell"
|
||||
"tengu_desktop_upsell_shown"
|
||||
"tengu_tide_elm"
|
||||
"tengu_tern_alloy"
|
||||
"tengu_timber_lark"
|
||||
"tengu_tip_shown"
|
||||
"tengu_plugin_hint_response"
|
||||
"tengu_marketplace_background_install"
|
||||
"tengu_rate_limit_lever_hint"
|
||||
"tengu_switch_to_subscription_notice_shown"
|
||||
"tengu_kairos_cron_config"
|
||||
"tengu_scheduled_task_missed"
|
||||
"tengu_scheduled_task_fire"
|
||||
"tengu_scheduled_task_expired"
|
||||
"tengu_session_resumed"
|
||||
"tengu_gleaming_fair"
|
||||
"tengu_cost_threshold_reached"
|
||||
"tengu_concurrent_onquery_detected"
|
||||
"tengu_concurrent_onquery_enqueued"
|
||||
"tengu_idle_return_action"
|
||||
"tengu_willow_mode"
|
||||
"tengu_conversation_rewind"
|
||||
"tengu_cost_threshold_acknowledged"
|
||||
"tengu_resume_return_action"
|
||||
"tengu_node_warning"
|
||||
"tengu_mcp_dialog_choice"
|
||||
"tengu_mcp_multidialog_choice"
|
||||
"tengu_preflight_check_failed"
|
||||
"tengu_began_setup"
|
||||
"tengu_onboarding_step"
|
||||
"tengu_trust_dialog_shown"
|
||||
"tengu_trust_dialog_accept"
|
||||
"tengu_bypass_permissions_mode_dialog_accept"
|
||||
"tengu_bypass_permissions_mode_dialog_shown"
|
||||
"tengu_claude_in_chrome_onboarding_shown"
|
||||
"tengu_grove_policy_exited"
|
||||
"tengu_stdin_interactive"
|
||||
"tengu_teleport_resume_session"
|
||||
"tengu_teleport_started"
|
||||
"tengu_teleport_cancelled"
|
||||
"tengu_plugin_command_failed"
|
||||
"tengu_plugin_installed_cli"
|
||||
"tengu_plugin_uninstalled_cli"
|
||||
"tengu_plugin_enabled_cli"
|
||||
"tengu_plugin_disabled_cli"
|
||||
"tengu_plugin_disabled_all_cli"
|
||||
"tengu_plugin_updated_cli"
|
||||
"tengu_skill_loaded"
|
||||
"tengu_mcp_add"
|
||||
"tengu_migrate_autoupdates_to_settings"
|
||||
"tengu_migrate_autoupdates_error"
|
||||
"tengu_migrate_bypass_permissions_accepted"
|
||||
"tengu_migrate_mcp_approval_fields_success"
|
||||
"tengu_migrate_mcp_approval_fields_error"
|
||||
"tengu_legacy_opus_migration"
|
||||
"tengu_opus_to_opus1m_migration"
|
||||
"tengu_sonnet45_to_46_migration"
|
||||
"tengu_migrate_reset_auto_opt_in_for_default_offer"
|
||||
"tengu_reset_pro_to_opus_default"
|
||||
"tengu_sm_config"
|
||||
"tengu_session_memory_file_read"
|
||||
"tengu_session_memory_extraction"
|
||||
"tengu_headless_plugin_install"
|
||||
"tengu_sync_plugin_install_timeout"
|
||||
"tengu_slate_prism"
|
||||
"tengu_mcp_channel_enable"
|
||||
"tengu_continue_print"
|
||||
"tengu_teleport_print"
|
||||
"tengu_resume_print"
|
||||
"tengu_mcp_start"
|
||||
"tengu_mcp_delete"
|
||||
"tengu_mcp_list"
|
||||
"tengu_mcp_get"
|
||||
"tengu_mcp_reset_mcpjson_choices"
|
||||
"tengu_plugin_list_command"
|
||||
"tengu_marketplace_updated_all"
|
||||
"tengu_plugin_install_command"
|
||||
"tengu_plugin_uninstall_command"
|
||||
"tengu_plugin_enable_command"
|
||||
"tengu_plugin_disable_command"
|
||||
"tengu_plugin_update_command"
|
||||
"tengu_claude_install_command"
|
||||
"tengu_setup_token_command"
|
||||
"tengu_doctor_command"
|
||||
"tengu_update_check"
|
||||
"tengu_managed_settings_loaded"
|
||||
"tengu_startup_telemetry"
|
||||
"tengu_code_prompt_ignored"
|
||||
"tengu_single_word_prompt"
|
||||
"tengu_claude_in_chrome_setup"
|
||||
"tengu_claude_in_chrome_setup_failed"
|
||||
"tengu_mcp_channel_flags"
|
||||
"tengu_structured_output_enabled"
|
||||
"tengu_structured_output_failure"
|
||||
"tengu_agent_flag"
|
||||
"tengu_timer"
|
||||
"tengu_cicada_nap_ms"
|
||||
"tengu_miraculo_the_bard"
|
||||
"tengu_concurrent_sessions"
|
||||
"tengu_startup_manual_model_config"
|
||||
"tengu_continue"
|
||||
"tengu_remote_backend"
|
||||
"tengu_remote_create_session"
|
||||
"tengu_remote_create_session_error"
|
||||
"tengu_remote_create_session_success"
|
||||
"tengu_teleport_interactive_mode"
|
||||
"tengu_deep_link_opened"
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -39,7 +39,7 @@ spec:
|
|||
name: OPENROUTER_API_KEY
|
||||
key: latest
|
||||
- name: MCP_SERVERS
|
||||
value: '[{"name":"pi-brain","url":"https://pi.ruv.io/sse"}]'
|
||||
value: '[{"name":"pi-brain","url":"https://mcp.pi.ruv.io"}]'
|
||||
- name: DRAGNES_ENABLED
|
||||
value: "true"
|
||||
- name: DRAGNES_BRAIN_URL
|
||||
|
|
|
|||
|
|
@ -273,10 +273,10 @@ export async function startMcpServer(
|
|||
} else {
|
||||
// SSE mode - point to hosted SSE on pi.ruv.io
|
||||
console.error(
|
||||
`π Brain MCP Server — use hosted SSE at https://pi.ruv.io/sse`,
|
||||
`π Brain MCP Server — use hosted SSE at https://mcp.pi.ruv.io`,
|
||||
);
|
||||
console.error(
|
||||
`Or connect via: claude mcp add π --url https://pi.ruv.io/sse`,
|
||||
`Or connect via: claude mcp add π --url https://mcp.pi.ruv.io`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
267
scripts/claude-code-decompile.sh
Executable file
267
scripts/claude-code-decompile.sh
Executable file
|
|
@ -0,0 +1,267 @@
|
|||
#!/usr/bin/env bash
|
||||
# claude-code-decompile.sh - Extract and analyze Claude Code CLI source
|
||||
#
|
||||
# Extracts the bundled JavaScript from the Claude Code binary or npm package,
|
||||
# applies basic beautification, and splits into logical modules.
|
||||
#
|
||||
# Usage: ./scripts/claude-code-decompile.sh [output-dir]
|
||||
#
|
||||
# Output directory defaults to ./claude-code-extracted/
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
OUTPUT_DIR="${1:-./claude-code-extracted}"
|
||||
BINARY=""
|
||||
CLI_JS=""
|
||||
|
||||
# Color output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() { echo -e "${GREEN}[+]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
|
||||
err() { echo -e "${RED}[-]${NC} $*" >&2; }
|
||||
|
||||
# Find the Claude Code source
|
||||
find_source() {
|
||||
# Method 1: NPM package (preferred - cleaner JS)
|
||||
local npm_paths=(
|
||||
"$(npm root -g 2>/dev/null)/claude-flow/node_modules/@anthropic-ai/claude-code/cli.js"
|
||||
"$(npm root -g 2>/dev/null)/@anthropic-ai/claude-code/cli.js"
|
||||
"./node_modules/@anthropic-ai/claude-code/cli.js"
|
||||
)
|
||||
for p in "${npm_paths[@]}"; do
|
||||
if [[ -f "$p" ]]; then
|
||||
CLI_JS="$p"
|
||||
log "Found NPM package: $CLI_JS"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Method 2: Bun SEA binary
|
||||
local bin_paths=(
|
||||
"$HOME/.local/bin/claude"
|
||||
"$HOME/.local/share/claude/versions/"
|
||||
"/usr/local/bin/claude"
|
||||
)
|
||||
for p in "${bin_paths[@]}"; do
|
||||
if [[ -f "$p" ]]; then
|
||||
BINARY="$(readlink -f "$p" 2>/dev/null || echo "$p")"
|
||||
log "Found binary: $BINARY"
|
||||
return 0
|
||||
elif [[ -d "$p" ]]; then
|
||||
BINARY="$(ls -t "$p"* 2>/dev/null | head -1)"
|
||||
if [[ -n "$BINARY" ]]; then
|
||||
log "Found binary: $BINARY"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
err "Could not find Claude Code binary or npm package"
|
||||
echo "Install via: npm install -g @anthropic-ai/claude-code"
|
||||
echo "Or ensure claude is installed: claude --version"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Extract JS from Bun SEA binary using strings
|
||||
extract_from_binary() {
|
||||
local binary="$1"
|
||||
local output="$2"
|
||||
|
||||
log "Extracting strings from binary ($(du -h "$binary" | cut -f1))..."
|
||||
strings "$binary" > "${output}/raw-strings.txt"
|
||||
|
||||
local total_lines
|
||||
total_lines=$(wc -l < "${output}/raw-strings.txt")
|
||||
log "Extracted $total_lines string fragments"
|
||||
|
||||
# Extract JS-like patterns
|
||||
log "Filtering JavaScript patterns..."
|
||||
grep -E '(function\s|class\s|=>\s*\{|export\s|import\s|require\(|async\s|await\s|const\s|let\s|var\s)' \
|
||||
"${output}/raw-strings.txt" > "${output}/js-fragments.txt" 2>/dev/null || true
|
||||
|
||||
local js_lines
|
||||
js_lines=$(wc -l < "${output}/js-fragments.txt")
|
||||
log "Found $js_lines JS-like fragments"
|
||||
}
|
||||
|
||||
# Process the cli.js bundle
|
||||
process_bundle() {
|
||||
local source="$1"
|
||||
local output="$2"
|
||||
|
||||
log "Processing bundle: $(du -h "$source" | cut -f1)"
|
||||
|
||||
# Copy original
|
||||
cp "$source" "${output}/cli.js.original"
|
||||
|
||||
# Basic beautification: add newlines at statement boundaries
|
||||
log "Beautifying (adding newlines at statement boundaries)..."
|
||||
sed 's/;/;\n/g' "$source" | \
|
||||
sed 's/{/{\n/g' | \
|
||||
sed 's/}/}\n/g' > "${output}/cli.beautified.js"
|
||||
|
||||
local beautified_lines
|
||||
beautified_lines=$(wc -l < "${output}/cli.beautified.js")
|
||||
log "Beautified: $beautified_lines lines"
|
||||
|
||||
# Extract metrics
|
||||
log "Computing code metrics..."
|
||||
{
|
||||
echo "=== Claude Code Source Metrics ==="
|
||||
echo "Date: $(date -Iseconds)"
|
||||
echo "Source: $source"
|
||||
echo "Original size: $(wc -c < "$source") bytes"
|
||||
echo "Original lines: $(wc -l < "$source")"
|
||||
echo "Beautified lines: $beautified_lines"
|
||||
echo ""
|
||||
echo "--- Counts ---"
|
||||
echo "Functions: $(grep -oP 'function\s*\w*\s*\(' "$source" | wc -l)"
|
||||
echo "Async functions: $(grep -oP 'async\s+function' "$source" | wc -l)"
|
||||
echo "Arrow functions: $(grep -oP '=>' "$source" | wc -l)"
|
||||
echo "Classes: $(grep -oP 'class \w+' "$source" | wc -l)"
|
||||
echo "Extends: $(grep -oP 'extends \w+' "$source" | wc -l)"
|
||||
echo "For-await loops: $(grep -c 'for await' "$source")"
|
||||
echo "Yield statements: $(grep -c 'yield' "$source")"
|
||||
echo ""
|
||||
echo "--- Node.js Imports ---"
|
||||
grep -oP 'from"[^"]*"' "$source" | sort -u | grep -P 'from"(node:|assert|child_process|crypto|events|fs|http|https|module|net|os|path|process|stream|tty|url|util|zlib)'
|
||||
echo ""
|
||||
echo "--- Class Definitions ---"
|
||||
grep -oP 'class \w+( extends \w+)?' "$source" | sort -u
|
||||
} > "${output}/metrics.txt"
|
||||
|
||||
log "Metrics saved to ${output}/metrics.txt"
|
||||
}
|
||||
|
||||
# Split into logical modules based on patterns
|
||||
split_modules() {
|
||||
local source="$1"
|
||||
local output="$2"
|
||||
local modules_dir="${output}/modules"
|
||||
mkdir -p "$modules_dir"
|
||||
|
||||
log "Splitting into logical modules..."
|
||||
|
||||
# Extract tool-related code
|
||||
grep -oP '.{0,200}(BashTool|FileReadTool|FileEditTool|FileWriteTool|AgentOutputTool|WebFetch|WebSearch|TodoWrite|NotebookEdit|GlobTool|GrepTool).{0,200}' \
|
||||
"$source" > "${modules_dir}/tools.txt" 2>/dev/null || true
|
||||
|
||||
# Extract permission-related code
|
||||
grep -oP '.{0,200}(permission|Permission|canUseTool|alwaysAllowRules|denyWrite|sandbox|Sandbox).{0,200}' \
|
||||
"$source" > "${modules_dir}/permissions.txt" 2>/dev/null || true
|
||||
|
||||
# Extract MCP-related code
|
||||
grep -oP '.{0,200}(mcp__|McpClient|McpServer|McpError|callTool|listTools|initialize).{0,200}' \
|
||||
"$source" > "${modules_dir}/mcp.txt" 2>/dev/null || true
|
||||
|
||||
# Extract streaming-related code
|
||||
grep -oP '.{0,200}(content_block_delta|message_start|message_stop|message_delta|content_block_start|content_block_stop|stream_event|text_delta|input_json_delta).{0,200}' \
|
||||
"$source" > "${modules_dir}/streaming.txt" 2>/dev/null || true
|
||||
|
||||
# Extract context/compaction code
|
||||
grep -oP '.{0,200}(compact|compaction|tengu_compact|microcompact|auto_compact|compact_boundary|preCompactTokenCount|postCompactTokenCount).{0,200}' \
|
||||
"$source" > "${modules_dir}/compaction.txt" 2>/dev/null || true
|
||||
|
||||
# Extract agent loop code
|
||||
grep -oP '.{0,200}(agentLoop|mainLoop|s\$\(|querySource|toolUseContext|systemPrompt).{0,200}' \
|
||||
"$source" > "${modules_dir}/agent-loop.txt" 2>/dev/null || true
|
||||
|
||||
# Extract telemetry events
|
||||
grep -oP '"tengu_[^"]*"' "$source" | sort -u > "${modules_dir}/telemetry-events.txt" 2>/dev/null || true
|
||||
|
||||
# Extract string constants (tool names, commands, etc.)
|
||||
grep -oP 'name:"[a-z][-a-z]*",description:"[^"]*"' "$source" | sort -u > "${modules_dir}/commands.txt" 2>/dev/null || true
|
||||
|
||||
# Extract class hierarchy
|
||||
grep -oP 'class \w+ extends \w+' "$source" | sort -u > "${modules_dir}/class-hierarchy.txt" 2>/dev/null || true
|
||||
|
||||
# Count extracted lines per module
|
||||
for f in "${modules_dir}"/*.txt; do
|
||||
local name
|
||||
name=$(basename "$f" .txt)
|
||||
local lines
|
||||
lines=$(wc -l < "$f")
|
||||
log " Module '$name': $lines fragments"
|
||||
done
|
||||
}
|
||||
|
||||
# Generate RVF files from extracted modules
|
||||
generate_rvf() {
|
||||
local modules_dir="$1/modules"
|
||||
local rvf_dir="$1/rvf"
|
||||
mkdir -p "$rvf_dir"
|
||||
|
||||
log "Generating RVF files..."
|
||||
|
||||
local version
|
||||
version=$(grep -oP 'VERSION:"[^"]*"' "$modules_dir/../cli.js.original" 2>/dev/null | head -1 | grep -oP '\d+\.\d+\.\d+' || echo "unknown")
|
||||
|
||||
for f in "${modules_dir}"/*.txt; do
|
||||
local name
|
||||
name=$(basename "$f" .txt)
|
||||
local rvf_file="${rvf_dir}/${name}.rvf"
|
||||
{
|
||||
echo "---"
|
||||
echo "type: source-extraction"
|
||||
echo "module: ${name}"
|
||||
echo "binary: claude-code"
|
||||
echo "version: ${version}"
|
||||
echo "extraction-method: strings+pattern-match"
|
||||
echo "confidence: medium"
|
||||
echo "fragments: $(wc -l < "$f")"
|
||||
echo "---"
|
||||
echo ""
|
||||
echo "# ${name} - Extracted Fragments"
|
||||
echo ""
|
||||
echo '```javascript'
|
||||
cat "$f"
|
||||
echo '```'
|
||||
} > "$rvf_file"
|
||||
log " Created ${rvf_file}"
|
||||
done
|
||||
}
|
||||
|
||||
# Main
|
||||
main() {
|
||||
log "Claude Code Decompiler"
|
||||
log "======================"
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
find_source
|
||||
|
||||
if [[ -n "$CLI_JS" ]]; then
|
||||
process_bundle "$CLI_JS" "$OUTPUT_DIR"
|
||||
split_modules "$CLI_JS" "$OUTPUT_DIR"
|
||||
generate_rvf "$OUTPUT_DIR"
|
||||
elif [[ -n "$BINARY" ]]; then
|
||||
extract_from_binary "$BINARY" "$OUTPUT_DIR"
|
||||
# If we got enough JS, process it
|
||||
if [[ -f "${OUTPUT_DIR}/js-fragments.txt" ]]; then
|
||||
split_modules "${OUTPUT_DIR}/js-fragments.txt" "$OUTPUT_DIR"
|
||||
generate_rvf "$OUTPUT_DIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
log ""
|
||||
log "Extraction complete!"
|
||||
log "Output directory: $OUTPUT_DIR"
|
||||
log ""
|
||||
log "Key files:"
|
||||
log " metrics.txt - Code metrics and counts"
|
||||
log " cli.beautified.js - Beautified bundle (if from NPM)"
|
||||
log " modules/ - Split by logical module"
|
||||
log " rvf/ - RVF files with metadata headers"
|
||||
|
||||
# Summary
|
||||
if [[ -f "${OUTPUT_DIR}/metrics.txt" ]]; then
|
||||
echo ""
|
||||
head -15 "${OUTPUT_DIR}/metrics.txt"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
455
scripts/claude-code-rvf-corpus.sh
Executable file
455
scripts/claude-code-rvf-corpus.sh
Executable file
|
|
@ -0,0 +1,455 @@
|
|||
#!/usr/bin/env bash
|
||||
# claude-code-rvf-corpus.sh - Build binary RVF containers for every major
|
||||
# Claude Code CLI release.
|
||||
#
|
||||
# Downloads the latest patch of each major.minor series from npm, extracts
|
||||
# the CLI bundle, splits into modules, and creates a binary RVF container
|
||||
# with vector embeddings and witness chains.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/claude-code-rvf-corpus.sh [--dry-run] [--series 0.2,1.0,2.0,2.1]
|
||||
#
|
||||
# Output: docs/research/claude-code-rvsource/versions/<vX.Y.z>/
|
||||
# - claude-code-vX.Y.rvf Binary RVF container
|
||||
# - claude-code-vX.Y.rvf.manifest.json Container manifest
|
||||
# - source/ Extracted JS modules
|
||||
# - README.md Version metadata
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
OUTPUT_BASE="${ROOT_DIR}/docs/research/claude-code-rvsource/versions"
|
||||
TMP_DIR="/tmp/cc-rvf-corpus-$$"
|
||||
DRY_RUN=false
|
||||
FILTER_SERIES=""
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() { echo -e "${GREEN}[+]${NC} $*"; }
|
||||
info() { echo -e "${CYAN}[*]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
|
||||
err() { echo -e "${RED}[-]${NC} $*" >&2; }
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$TMP_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
--series) FILTER_SERIES="$2"; shift 2 ;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--dry-run] [--series 0.2,1.0,2.0,2.1]"
|
||||
exit 0
|
||||
;;
|
||||
*) err "Unknown argument: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Fetch all versions from npm and group by major.minor
|
||||
get_version_groups() {
|
||||
log "Fetching Claude Code versions from npm..." >&2
|
||||
local versions_json
|
||||
versions_json=$(npm view @anthropic-ai/claude-code versions --json 2>/dev/null)
|
||||
|
||||
# Use node to group versions and pick latest patch per major.minor
|
||||
node -e "
|
||||
const versions = $versions_json;
|
||||
const groups = {};
|
||||
|
||||
for (const v of versions) {
|
||||
const parts = v.split('.');
|
||||
const key = parts[0] + '.' + parts[1];
|
||||
const patch = parseInt(parts[2], 10);
|
||||
|
||||
if (!groups[key] || patch > groups[key].patch) {
|
||||
groups[key] = { version: v, patch, key };
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by semver
|
||||
const sorted = Object.values(groups).sort((a, b) => {
|
||||
const [aMaj, aMin] = a.key.split('.').map(Number);
|
||||
const [bMaj, bMin] = b.key.split('.').map(Number);
|
||||
return aMaj !== bMaj ? aMaj - bMaj : aMin - bMin;
|
||||
});
|
||||
|
||||
for (const g of sorted) {
|
||||
console.log(g.key + ' ' + g.version);
|
||||
}
|
||||
"
|
||||
}
|
||||
|
||||
# Download and extract a specific version
|
||||
download_version() {
|
||||
local version="$1"
|
||||
local dest_dir="$2"
|
||||
|
||||
mkdir -p "$dest_dir"
|
||||
info " Downloading @anthropic-ai/claude-code@${version}..."
|
||||
|
||||
local tgz_dir="${TMP_DIR}/tarballs"
|
||||
mkdir -p "$tgz_dir"
|
||||
|
||||
npm pack "@anthropic-ai/claude-code@${version}" --pack-destination "$tgz_dir" \
|
||||
>/dev/null 2>&1
|
||||
|
||||
# Find the tarball (naming varies between npm versions)
|
||||
local tgz
|
||||
tgz=$(ls "$tgz_dir"/anthropic-ai-claude-code-*.tgz 2>/dev/null | head -1)
|
||||
if [[ -z "$tgz" ]]; then
|
||||
err " Failed to download version ${version}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Try to extract cli.js, then cli.mjs (don't list the tarball, just try)
|
||||
tar xf "$tgz" -C "$dest_dir" --strip-components=1 package/cli.js 2>/dev/null || true
|
||||
tar xf "$tgz" -C "$dest_dir" --strip-components=1 package/cli.mjs 2>/dev/null || true
|
||||
tar xf "$tgz" -C "$dest_dir" --strip-components=1 package/package.json 2>/dev/null || true
|
||||
|
||||
# Rename cli.mjs -> cli.js for consistency
|
||||
if [[ -f "${dest_dir}/cli.mjs" ]] && [[ ! -f "${dest_dir}/cli.js" ]]; then
|
||||
mv "${dest_dir}/cli.mjs" "${dest_dir}/cli.js"
|
||||
fi
|
||||
|
||||
if [[ ! -f "${dest_dir}/cli.js" ]]; then
|
||||
warn " No cli.js or cli.mjs found in ${version}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -f "$tgz"
|
||||
local size
|
||||
size=$(du -sh "${dest_dir}/cli.js" 2>/dev/null | cut -f1)
|
||||
info " Extracted cli.js (${size})"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Split a CLI bundle into modules
|
||||
split_modules() {
|
||||
local cli_path="$1"
|
||||
local source_dir="$2"
|
||||
|
||||
info " Splitting into modules..."
|
||||
node "${SCRIPT_DIR}/lib/module-splitter.mjs" "$cli_path" "$source_dir" 2>/dev/null
|
||||
}
|
||||
|
||||
# Build a binary RVF container
|
||||
build_rvf() {
|
||||
local source_dir="$1"
|
||||
local rvf_path="$2"
|
||||
local version="$3"
|
||||
local series="$4"
|
||||
|
||||
info " Building binary RVF container..."
|
||||
node "${SCRIPT_DIR}/lib/rvf-builder.mjs" \
|
||||
"$source_dir" "$rvf_path" \
|
||||
--meta "version=${version}" \
|
||||
--meta "series=${series}" \
|
||||
--meta "package=@anthropic-ai/claude-code" \
|
||||
--meta "corpus=claude-code-rvsource" \
|
||||
2>/dev/null
|
||||
}
|
||||
|
||||
# Generate a README for a version directory
|
||||
generate_readme() {
|
||||
local ver_dir="$1"
|
||||
local series="$2"
|
||||
local version="$3"
|
||||
local rvf_file="$4"
|
||||
|
||||
local metrics_file="${ver_dir}/source/metrics.json"
|
||||
local manifest_file="${rvf_file}.manifest.json"
|
||||
|
||||
# Read metrics
|
||||
local bundle_size="unknown"
|
||||
local classes="?"
|
||||
local functions="?"
|
||||
local modules_count="?"
|
||||
|
||||
if [[ -f "$metrics_file" ]]; then
|
||||
bundle_size=$(node -e "const m=JSON.parse(require('fs').readFileSync('$metrics_file','utf-8')); console.log((m.sizeBytes/1024/1024).toFixed(1)+'MB')")
|
||||
classes=$(node -e "const m=JSON.parse(require('fs').readFileSync('$metrics_file','utf-8')); console.log(m.classes)")
|
||||
functions=$(node -e "const m=JSON.parse(require('fs').readFileSync('$metrics_file','utf-8')); console.log(m.functions)")
|
||||
modules_count=$(node -e "const m=JSON.parse(require('fs').readFileSync('$metrics_file','utf-8')); console.log(Object.keys(m.modules||{}).length)")
|
||||
fi
|
||||
|
||||
local rvf_size="N/A"
|
||||
local rvf_vectors="N/A"
|
||||
local rvf_id="N/A"
|
||||
if [[ -f "$manifest_file" ]]; then
|
||||
rvf_size=$(node -e "const m=JSON.parse(require('fs').readFileSync('$manifest_file','utf-8')); console.log((m.fileSizeBytes/1024).toFixed(1)+'KB')")
|
||||
rvf_vectors=$(node -e "const m=JSON.parse(require('fs').readFileSync('$manifest_file','utf-8')); console.log(m.totalVectors)")
|
||||
rvf_id=$(node -e "const m=JSON.parse(require('fs').readFileSync('$manifest_file','utf-8')); console.log(m.fileId)")
|
||||
fi
|
||||
|
||||
cat > "${ver_dir}/README.md" <<READMEEOF
|
||||
# Claude Code v${version} (${series} series)
|
||||
|
||||
## Binary RVF Container
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Version | ${version} |
|
||||
| Series | ${series} |
|
||||
| Bundle size | ${bundle_size} |
|
||||
| RVF size | ${rvf_size} |
|
||||
| Vectors | ${rvf_vectors} |
|
||||
| RVF File ID | \`${rvf_id}\` |
|
||||
| Classes | ${classes} |
|
||||
| Functions | ${functions} |
|
||||
| Modules | ${modules_count} |
|
||||
| Extracted | $(date -Iseconds) |
|
||||
|
||||
## Files
|
||||
|
||||
- \`claude-code-v${series}.rvf\` - Binary RVF container with HNSW index + witness chain
|
||||
- \`claude-code-v${series}.rvf.manifest.json\` - Container manifest (vector ID map, metadata)
|
||||
- \`source/\` - Extracted JavaScript module fragments
|
||||
|
||||
## RVF Container Details
|
||||
|
||||
The \`.rvf\` file is a real binary container created with the \`@ruvector/rvf-node\`
|
||||
native backend. It contains:
|
||||
|
||||
- **128-dimensional fingerprint vectors** for each code fragment
|
||||
- **HNSW index** (M=16, ef_construction=200) for fast similarity search
|
||||
- **Cosine distance** metric
|
||||
- **Witness chain** for provenance verification
|
||||
|
||||
To query this container:
|
||||
|
||||
\`\`\`typescript
|
||||
import { RvfDatabase } from '@ruvector/rvf';
|
||||
|
||||
const db = await RvfDatabase.openReadonly('./claude-code-v${series}.rvf');
|
||||
const results = await db.query(queryVector, 10);
|
||||
await db.close();
|
||||
\`\`\`
|
||||
READMEEOF
|
||||
}
|
||||
|
||||
# Generate the top-level index README
|
||||
generate_index() {
|
||||
local base_dir="$1"
|
||||
shift
|
||||
local entries=("$@")
|
||||
|
||||
cat > "${base_dir}/README.md" <<'INDEXHEADER'
|
||||
# Claude Code RVF Corpus
|
||||
|
||||
Binary RVF containers for every major Claude Code CLI release, with
|
||||
HNSW-indexed vector embeddings and witness chains for provenance.
|
||||
|
||||
## Versions
|
||||
|
||||
| Series | Version | Bundle | RVF Size | Vectors | File ID |
|
||||
|--------|---------|--------|----------|---------|---------|
|
||||
INDEXHEADER
|
||||
|
||||
for entry in "${entries[@]}"; do
|
||||
echo "$entry" >> "${base_dir}/README.md"
|
||||
done
|
||||
|
||||
cat >> "${base_dir}/README.md" <<'INDEXFOOTER'
|
||||
|
||||
## How to Use
|
||||
|
||||
```bash
|
||||
# Build the corpus
|
||||
./scripts/claude-code-rvf-corpus.sh
|
||||
|
||||
# Build only specific series
|
||||
./scripts/claude-code-rvf-corpus.sh --series 2.0,2.1
|
||||
```
|
||||
|
||||
## Format
|
||||
|
||||
Each version directory contains:
|
||||
- A binary `.rvf` container (128-dim cosine-distance HNSW index)
|
||||
- A `.manifest.json` sidecar with vector-to-fragment mapping
|
||||
- Extracted JavaScript modules in `source/`
|
||||
|
||||
Generated by `scripts/claude-code-rvf-corpus.sh` using `@ruvector/rvf-node`.
|
||||
INDEXFOOTER
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Main
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
main() {
|
||||
echo -e "${BOLD}Claude Code RVF Corpus Builder${NC}"
|
||||
echo -e "${BOLD}==============================${NC}"
|
||||
echo ""
|
||||
|
||||
mkdir -p "$TMP_DIR" "$OUTPUT_BASE"
|
||||
|
||||
# Get version groups
|
||||
local groups
|
||||
groups=$(get_version_groups)
|
||||
|
||||
if [[ -z "$groups" ]]; then
|
||||
err "No versions found on npm"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local total_groups
|
||||
total_groups=$(echo "$groups" | wc -l)
|
||||
log "Found ${total_groups} major.minor series"
|
||||
|
||||
# Apply filter if specified
|
||||
if [[ -n "$FILTER_SERIES" ]]; then
|
||||
local filtered=""
|
||||
IFS=',' read -ra FILTER_ARRAY <<< "$FILTER_SERIES"
|
||||
while IFS= read -r line; do
|
||||
local series
|
||||
series=$(echo "$line" | awk '{print $1}')
|
||||
for f in "${FILTER_ARRAY[@]}"; do
|
||||
if [[ "$series" == "$f" ]]; then
|
||||
filtered+="${line}"$'\n'
|
||||
fi
|
||||
done
|
||||
done <<< "$groups"
|
||||
groups="$filtered"
|
||||
total_groups=$(echo -n "$groups" | grep -c '^' || echo 0)
|
||||
log "Filtered to ${total_groups} series: ${FILTER_SERIES}"
|
||||
fi
|
||||
|
||||
if $DRY_RUN; then
|
||||
warn "DRY RUN - would process these versions:"
|
||||
echo "$groups" | while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
local series version
|
||||
series=$(echo "$line" | awk '{print $1}')
|
||||
version=$(echo "$line" | awk '{print $2}')
|
||||
echo " v${series}.x -> ${version}"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
local processed=0
|
||||
local failed=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
[[ -z "$line" ]] && continue
|
||||
|
||||
local series version
|
||||
series=$(echo "$line" | awk '{print $1}')
|
||||
version=$(echo "$line" | awk '{print $2}')
|
||||
|
||||
echo ""
|
||||
log "Processing v${series}.x (latest: ${version})"
|
||||
|
||||
local ver_dir="${OUTPUT_BASE}/v${series}.x"
|
||||
local source_dir="${ver_dir}/source"
|
||||
local rvf_file="${ver_dir}/claude-code-v${series}.rvf"
|
||||
local extract_dir="${TMP_DIR}/extract-${version}"
|
||||
|
||||
mkdir -p "$ver_dir" "$source_dir"
|
||||
|
||||
# Step 1: Download
|
||||
if ! download_version "$version" "$extract_dir"; then
|
||||
warn " Skipping ${version} (download failed)"
|
||||
((failed++)) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
local cli_path="${extract_dir}/cli.js"
|
||||
if [[ ! -f "$cli_path" ]]; then
|
||||
warn " No CLI bundle found for ${version}"
|
||||
((failed++)) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
# Step 2: Split into modules
|
||||
if ! split_modules "$cli_path" "$source_dir"; then
|
||||
warn " Module splitting failed for ${version}"
|
||||
fi
|
||||
|
||||
# Step 3: Build binary RVF container
|
||||
if build_rvf "$source_dir" "$rvf_file" "$version" "$series"; then
|
||||
log " RVF container created: $(basename "$rvf_file")"
|
||||
else
|
||||
warn " RVF creation failed for ${version}"
|
||||
# Create a fallback TODO note
|
||||
cat > "${ver_dir}/TODO-rvf.md" <<EOF
|
||||
# TODO: Create RVF Container
|
||||
|
||||
Version: ${version}
|
||||
Series: v${series}.x
|
||||
Error: RVF binary creation failed
|
||||
|
||||
The source modules have been extracted to \`source/\` but the binary
|
||||
RVF container could not be created. This typically means the
|
||||
\`@ruvector/rvf-node\` native backend is not available.
|
||||
|
||||
To create the container manually:
|
||||
|
||||
\`\`\`bash
|
||||
node scripts/lib/rvf-builder.mjs source/ claude-code-v${series}.rvf \\
|
||||
--meta version=${version} --meta series=${series}
|
||||
\`\`\`
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Step 4: Generate README
|
||||
generate_readme "$ver_dir" "$series" "$version" "$rvf_file"
|
||||
|
||||
# Clean up extracted tarball content
|
||||
rm -rf "$extract_dir"
|
||||
|
||||
((processed++)) || true
|
||||
log " Done (${processed}/${total_groups})"
|
||||
done <<< "$groups"
|
||||
|
||||
# Generate index
|
||||
echo ""
|
||||
log "Generating corpus index..."
|
||||
|
||||
# Rebuild index entries by scanning output dirs
|
||||
local final_entries=()
|
||||
for d in "${OUTPUT_BASE}"/v*.x; do
|
||||
[[ -d "$d" ]] || continue
|
||||
local dir_name
|
||||
dir_name=$(basename "$d")
|
||||
local series_name="${dir_name#v}"
|
||||
series_name="${series_name%.x}"
|
||||
|
||||
local manifest="${d}/claude-code-v${series_name}.rvf.manifest.json"
|
||||
if [[ -f "$manifest" ]]; then
|
||||
local row
|
||||
row=$(node -e "
|
||||
const m=JSON.parse(require('fs').readFileSync('$manifest','utf-8'));
|
||||
const s=m.source||{};
|
||||
const met=s.metrics||{};
|
||||
const bundle=(met.bundleSizeBytes/1024/1024).toFixed(1)+'MB';
|
||||
const rvfSize=(m.fileSizeBytes/1024).toFixed(1)+'KB';
|
||||
console.log('| ${series_name} | '+s.version+' | '+bundle+' | '+rvfSize+' | '+m.totalVectors+' | \`'+m.fileId.slice(0,12)+'...\` |');
|
||||
" 2>/dev/null || echo "| ${series_name} | ? | ? | ? | ? | ? |")
|
||||
final_entries+=("$row")
|
||||
else
|
||||
final_entries+=("| ${series_name} | ? | ? | N/A | N/A | N/A |")
|
||||
fi
|
||||
done
|
||||
|
||||
generate_index "$OUTPUT_BASE" "${final_entries[@]}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}Corpus build complete.${NC}"
|
||||
log "Output: ${OUTPUT_BASE}/"
|
||||
log "Versions processed: ${processed:-0}"
|
||||
if [[ ${failed:-0} -gt 0 ]]; then
|
||||
warn "Versions failed: ${failed}"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
@ -96,7 +96,7 @@ gcloud run deploy "${SERVICE_NAME}" \
|
|||
--set-env-vars="DRAGNES_BRAIN_URL=https://pi.ruv.io" \
|
||||
--set-env-vars="DRAGNES_MODEL_VERSION=0.1.0" \
|
||||
--update-secrets="OPENAI_API_KEY=OPENROUTER_API_KEY:latest" \
|
||||
--set-env-vars='MCP_SERVERS=[{"name":"pi-brain","url":"https://pi.ruv.io/sse"}]'
|
||||
--set-env-vars='MCP_SERVERS=[{"name":"pi-brain","url":"https://mcp.pi.ruv.io"}]'
|
||||
|
||||
# ---------- CDN for WASM assets -----------------------------------------------
|
||||
|
||||
|
|
|
|||
211
scripts/lib/module-splitter.mjs
Executable file
211
scripts/lib/module-splitter.mjs
Executable file
|
|
@ -0,0 +1,211 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* module-splitter.mjs - Split a Claude Code CLI bundle into logical modules.
|
||||
*
|
||||
* Given a path to cli.js / cli.mjs, extracts recognizable subsystems
|
||||
* (tools, MCP, permissions, streaming, agent-loop, compaction, telemetry)
|
||||
* and writes individual .js files plus a metrics.json manifest.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/lib/module-splitter.mjs <cli-bundle> <output-dir>
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync, mkdirSync, statSync } from 'fs';
|
||||
import { join, basename } from 'path';
|
||||
|
||||
// Module extraction: keyword -> module name.
|
||||
// A line containing the keyword is assigned to that module.
|
||||
// Order matters: first match wins for each line.
|
||||
const MODULE_KEYWORDS = {
|
||||
'tool-dispatch': [
|
||||
'BashTool', 'FileReadTool', 'FileEditTool', 'FileWriteTool',
|
||||
'AgentOutputTool', 'WebFetch', 'WebSearch', 'TodoWrite',
|
||||
'NotebookEdit', 'GlobTool', 'GrepTool',
|
||||
],
|
||||
'permission-system': [
|
||||
'canUseTool', 'alwaysAllowRules', 'denyWrite',
|
||||
'Permission', 'permission',
|
||||
],
|
||||
'mcp-client': [
|
||||
'mcp__', 'McpClient', 'McpServer', 'McpError',
|
||||
'callTool', 'listTools',
|
||||
],
|
||||
'streaming-handler': [
|
||||
'content_block_delta', 'message_start', 'message_stop',
|
||||
'message_delta', 'content_block_start', 'content_block_stop',
|
||||
'stream_event', 'text_delta', 'input_json_delta',
|
||||
],
|
||||
'context-manager': [
|
||||
'tengu_compact', 'microcompact', 'auto_compact',
|
||||
'compact_boundary', 'preCompactTokenCount',
|
||||
'postCompactTokenCount', 'compaction',
|
||||
],
|
||||
'agent-loop': [
|
||||
'agentLoop', 'mainLoop', 'querySource',
|
||||
'toolUseContext', 'systemPrompt',
|
||||
],
|
||||
};
|
||||
|
||||
// Simple global regex patterns for small, fast extractions.
|
||||
const SIMPLE_PATTERNS = {
|
||||
telemetry: /"tengu_[^"]*"/g,
|
||||
commands: /name:"[a-z][-a-z]*",description:"[^"]*"/g,
|
||||
'class-hierarchy': /class \w+( extends \w+)?/g,
|
||||
};
|
||||
|
||||
/**
|
||||
* Split source into statements (semicolon-delimited chunks).
|
||||
* For minified bundles, this gives us logical units.
|
||||
*/
|
||||
function splitStatements(source) {
|
||||
// Split on semicolons that are not inside strings.
|
||||
// For minified JS, simple semicolon split works well enough.
|
||||
// Limit chunk size to ~2KB for vector embedding granularity.
|
||||
const MAX_CHUNK = 2048;
|
||||
const raw = source.split(';');
|
||||
const chunks = [];
|
||||
let buffer = '';
|
||||
|
||||
for (const part of raw) {
|
||||
if (buffer.length + part.length > MAX_CHUNK && buffer.length > 0) {
|
||||
chunks.push(buffer);
|
||||
buffer = part;
|
||||
} else {
|
||||
buffer += (buffer ? ';' : '') + part;
|
||||
}
|
||||
}
|
||||
if (buffer.length > 0) chunks.push(buffer);
|
||||
return chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign statements to modules based on keyword matching.
|
||||
*/
|
||||
function classifyStatements(statements) {
|
||||
const modules = {};
|
||||
|
||||
for (const stmt of statements) {
|
||||
if (stmt.length < 10) continue;
|
||||
|
||||
for (const [modName, keywords] of Object.entries(MODULE_KEYWORDS)) {
|
||||
const matched = keywords.some((kw) => stmt.includes(kw));
|
||||
if (matched) {
|
||||
if (!modules[modName]) modules[modName] = [];
|
||||
modules[modName].push(stmt.trim());
|
||||
break; // first-match wins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract simple pattern matches (telemetry events, commands, classes).
|
||||
*/
|
||||
function extractSimplePatterns(source) {
|
||||
const results = {};
|
||||
|
||||
for (const [modName, pattern] of Object.entries(SIMPLE_PATTERNS)) {
|
||||
pattern.lastIndex = 0;
|
||||
const matches = new Set();
|
||||
let m;
|
||||
while ((m = pattern.exec(source)) !== null) {
|
||||
const frag = m[0].trim();
|
||||
if (frag.length > 3) matches.add(frag);
|
||||
}
|
||||
if (matches.size > 0) {
|
||||
results[modName] = [...matches];
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute basic metrics about the CLI bundle.
|
||||
*/
|
||||
function computeMetrics(source, filePath) {
|
||||
const sizeBytes = statSync(filePath).size;
|
||||
const versionMatch = source.match(/VERSION[=:]"?(\d+\.\d+\.\d+)/);
|
||||
const version = versionMatch ? versionMatch[1] : 'unknown';
|
||||
|
||||
return {
|
||||
version,
|
||||
sizeBytes,
|
||||
lines: source.split('\n').length,
|
||||
functions: (source.match(/function\s*\w*\s*\(/g) || []).length,
|
||||
asyncFunctions: (source.match(/async\s+function/g) || []).length,
|
||||
arrowFunctions: (source.match(/=>/g) || []).length,
|
||||
classes: (source.match(/class \w+/g) || []).length,
|
||||
extends: (source.match(/extends \w+/g) || []).length,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
*/
|
||||
function main() {
|
||||
const [bundlePath, outputDir] = process.argv.slice(2);
|
||||
if (!bundlePath || !outputDir) {
|
||||
console.error('Usage: node module-splitter.mjs <cli-bundle> <output-dir>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
mkdirSync(outputDir, { recursive: true });
|
||||
|
||||
console.log(`Reading bundle: ${bundlePath}`);
|
||||
const source = readFileSync(bundlePath, 'utf-8');
|
||||
const metrics = computeMetrics(source, bundlePath);
|
||||
console.log(` Size: ${(metrics.sizeBytes / 1024 / 1024).toFixed(1)} MB, ` +
|
||||
`${metrics.classes} classes, ${metrics.functions} functions`);
|
||||
|
||||
// Phase 1: statement-based classification (fast, O(n) per keyword set)
|
||||
console.log(' Splitting into statements...');
|
||||
const statements = splitStatements(source);
|
||||
console.log(` ${statements.length} statements`);
|
||||
|
||||
const classified = classifyStatements(statements);
|
||||
const moduleResults = {};
|
||||
|
||||
for (const [modName, fragments] of Object.entries(classified)) {
|
||||
const outFile = join(outputDir, `${modName}.js`);
|
||||
writeFileSync(outFile, fragments.join('\n\n'), 'utf-8');
|
||||
moduleResults[modName] = {
|
||||
fragments: fragments.length,
|
||||
sizeBytes: Buffer.byteLength(fragments.join('\n\n')),
|
||||
};
|
||||
console.log(` Module "${modName}": ${fragments.length} fragments`);
|
||||
}
|
||||
|
||||
// Phase 2: simple pattern extractions (telemetry, commands, classes)
|
||||
console.log(' Extracting simple patterns...');
|
||||
const simple = extractSimplePatterns(source);
|
||||
|
||||
for (const [modName, fragments] of Object.entries(simple)) {
|
||||
const outFile = join(outputDir, `${modName}.js`);
|
||||
writeFileSync(outFile, fragments.join('\n'), 'utf-8');
|
||||
moduleResults[modName] = {
|
||||
fragments: fragments.length,
|
||||
sizeBytes: Buffer.byteLength(fragments.join('\n')),
|
||||
};
|
||||
console.log(` Module "${modName}": ${fragments.length} fragments`);
|
||||
}
|
||||
|
||||
// Write metrics manifest
|
||||
const manifest = {
|
||||
...metrics,
|
||||
sourceFile: basename(bundlePath),
|
||||
extractedAt: new Date().toISOString(),
|
||||
modules: moduleResults,
|
||||
};
|
||||
writeFileSync(
|
||||
join(outputDir, 'metrics.json'),
|
||||
JSON.stringify(manifest, null, 2)
|
||||
);
|
||||
|
||||
// Output JSON summary to stdout for the caller script
|
||||
console.log(JSON.stringify(manifest));
|
||||
}
|
||||
|
||||
main();
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue