Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"name": "claude-code-best",
"version": "1.0.3",
"version": "2026.4.3-restored",
"private": true,
"description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal",
"license": "SEE LICENSE IN LICENSE.md",
"type": "module",
"author": "claude-code-best <claude-code-best@proton.me>",
"repository": {
Expand Down Expand Up @@ -39,6 +41,7 @@
"scripts": {
"build": "bun run build.ts",
"dev": "bun run scripts/dev.ts",
"dev-debug": "FEATURE_BUDDY=1 bun run scripts/dev.ts --debug",
"dev:inspect": "bun run scripts/dev-debug.ts",
"prepublishOnly": "bun run build",
"lint": "biome lint src/",
Expand Down
28 changes: 28 additions & 0 deletions src/services/api/claude.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,27 @@ async function* queryModel(
const params = paramsFromContext(context)
captureAPIRequest(params, options.querySource) // Capture for bug reports

// Log the full API request to debug log file
logForDebugging(`[API_REQUEST] model=${params.model} max_tokens=${params.max_tokens}`)
// Set CLAUDE_CODE_LOG_FULL_PROMPT=1 to log full system prompt and messages
if (isEnvTruthy(process.env.CLAUDE_CODE_LOG_FULL_PROMPT)) {
logForDebugging(`[API_REQUEST_SYSTEM_FULL] ${jsonStringify(params.system)}`)
logForDebugging(`[API_REQUEST_MESSAGES_FULL] ${jsonStringify(params.messages)}`)
} else {
logForDebugging(`[API_REQUEST_SYSTEM] ${jsonStringify(params.system).slice(0, 5000)}...`)
logForDebugging(`[API_REQUEST_MESSAGES] count=${params.messages.length}`)
}
logForDebugging(`[API_REQUEST_TOOLS] count=${params.tools?.length ?? 0}`)
if (params.tools && params.tools.length > 0) {
for (const tool of params.tools) {
if ('name' in tool) {
logForDebugging(`[API_REQUEST_TOOL] name=${tool.name}`)
} else if ('type' in tool) {
logForDebugging(`[API_REQUEST_TOOL] type=${tool.type}`)
}
}
}

maxOutputTokens = params.max_tokens

// Fire immediately before the fetch is dispatched. .withResponse() below
Expand Down Expand Up @@ -1986,12 +2007,14 @@ async function* queryModel(
...part.content_block,
input: '',
}
logForDebugging(`[TOOL_USE] name=${part.content_block.name} id=${part.content_block.id}`)
break
case 'server_tool_use':
contentBlocks[part.index] = {
...part.content_block,
input: '' as unknown as { [key: string]: unknown },
}
logForDebugging(`[MCP_TOOL_USE] name=${part.content_block.name} id=${part.content_block.id}`)
if ((part.content_block.name as string) === 'advisor') {
isAdvisorInProgress = true
logForDebugging(`[AdvisorTool] Advisor tool called`)
Expand Down Expand Up @@ -2234,6 +2257,11 @@ async function* queryModel(
lastMsg.message.stop_reason = stopReason
}

// Log the API response summary
logForDebugging(`[API_RESPONSE] stop_reason=${stopReason} usage=${jsonStringify(usage)}`)
logForDebugging(`[API_RESPONSE_MESSAGES] count=${newMessages.length}`)
logForDebugging(`[API_RESPONSE_CONTENT] ${jsonStringify(newMessages)}`)
Comment on lines +2260 to +2263
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Consider gating full response content logging with CLAUDE_CODE_LOG_FULL_PROMPT.

Line 2263 logs the entire newMessages array via jsonStringify, which contains assistant message content. This is inconsistent with the request logging (lines 1790-1796) where full content requires CLAUDE_CODE_LOG_FULL_PROMPT to be set.

From the context in src/utils/debug.ts:173-186, ant users always have debug logs written (for /share and bug reports), meaning this full response content would be logged unconditionally for internal users.

🛡️ Suggested fix to align with request logging pattern
             // Log the API response summary
             logForDebugging(`[API_RESPONSE] stop_reason=${stopReason} usage=${jsonStringify(usage)}`)
             logForDebugging(`[API_RESPONSE_MESSAGES] count=${newMessages.length}`)
-            logForDebugging(`[API_RESPONSE_CONTENT] ${jsonStringify(newMessages)}`)
+            if (isEnvTruthy(process.env.CLAUDE_CODE_LOG_FULL_PROMPT)) {
+              logForDebugging(`[API_RESPONSE_CONTENT] ${jsonStringify(newMessages)}`)
+            }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/api/claude.ts` around lines 2260 - 2263, The code
unconditionally logs full assistant response content by calling
logForDebugging(`[API_RESPONSE_CONTENT] ${jsonStringify(newMessages)}`), which
bypasses the CLAUDE_CODE_LOG_FULL_PROMPT gating used for request logging; modify
the block that logs API response content so it only logs the full
jsonStringify(newMessages) when the CLAUDE_CODE_LOG_FULL_PROMPT flag (or
equivalent debug check used in src/utils/debug.ts) is set, otherwise log a
redacted/summary version (e.g., count or truncated text) — update the lines
around logForDebugging, newMessages and jsonStringify usage to mirror the
request-logging pattern.


// Update cost
const costUSDForPart = calculateUSDCost(resolvedModel, usage as unknown as BetaUsage)
costUSD += addToTotalSessionCost(
Expand Down
51 changes: 51 additions & 0 deletions src/tools/AgentTool/AgentTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,19 @@ export const AgentTool = buildTool({
const startTime = Date.now();
const model = isCoordinatorMode() ? undefined : modelParam;

// Log Agent tool invocation details
logForDebugging(`[AGENT_TOOL] Invoking Agent with parameters:`);
logForDebugging(`[AGENT_TOOL] description: ${description}`);
logForDebugging(`[AGENT_TOOL] subagent_type: ${subagent_type ?? '(auto-select)'}`);
logForDebugging(`[AGENT_TOOL] model: ${model ?? '(default)'}`);
logForDebugging(`[AGENT_TOOL] run_in_background: ${run_in_background ?? false}`);
logForDebugging(`[AGENT_TOOL] prompt length: ${prompt.length} chars`);
if (name) logForDebugging(`[AGENT_TOOL] name: ${name}`);
if (team_name) logForDebugging(`[AGENT_TOOL] team_name: ${team_name}`);
if (spawnMode) logForDebugging(`[AGENT_TOOL] mode: ${spawnMode}`);
if (isolation) logForDebugging(`[AGENT_TOOL] isolation: ${isolation}`);
if (cwd) logForDebugging(`[AGENT_TOOL] cwd: ${cwd}`);

// Get app state for permission mode and agent filtering
const appState = toolUseContext.getAppState();
const permissionMode = appState.toolPermissionContext.mode;
Expand Down Expand Up @@ -299,6 +312,12 @@ export const AgentTool = buildTool({
invokingRequestId: assistantMessage?.requestId as string | undefined
}, toolUseContext);

// Log teammate spawn
logForDebugging(`[AGENT_TOOL] Teammate spawned: ${name}`);
logForDebugging(`[AGENT_TOOL] team_name: ${teamName}`);
logForDebugging(`[AGENT_TOOL] agent_type: ${subagent_type ?? '(default)'}`);
logForDebugging(`[AGENT_TOOL] model: ${model ?? agentDef?.model ?? '(default)'}`);

// Type assertion uses TeammateSpawnedOutput (defined above) instead of any.
// This type is excluded from the exported outputSchema for dead code elimination.
// Cast through unknown because TeammateSpawnedOutput is intentionally
Expand Down Expand Up @@ -355,6 +374,16 @@ export const AgentTool = buildTool({
selectedAgent = found;
}

// Log selected agent definition details
logForDebugging(`[AGENT_TOOL] Selected agent: ${selectedAgent.agentType}`);
logForDebugging(`[AGENT_TOOL] source: ${selectedAgent.source}`);
if (selectedAgent.model) logForDebugging(`[AGENT_TOOL] agent model: ${selectedAgent.model}`);
if (selectedAgent.permissionMode) logForDebugging(`[AGENT_TOOL] permissionMode: ${selectedAgent.permissionMode}`);
if (selectedAgent.maxTurns) logForDebugging(`[AGENT_TOOL] maxTurns: ${selectedAgent.maxTurns}`);
if (selectedAgent.background) logForDebugging(`[AGENT_TOOL] background: ${selectedAgent.background}`);
if (selectedAgent.effort !== undefined) logForDebugging(`[AGENT_TOOL] effort: ${selectedAgent.effort}`);
if (selectedAgent.requiredMcpServers?.length) logForDebugging(`[AGENT_TOOL] requiredMcpServers: ${selectedAgent.requiredMcpServers.join(', ')}`);

// Same lifecycle constraint as the run_in_background guard above, but for
// agent definitions that force background via `background: true`. Checked
// here because selectedAgent is only now resolved.
Expand Down Expand Up @@ -466,6 +495,12 @@ export const AgentTool = buildTool({
logEvent('tengu_agent_tool_remote_launched', {
agent_type: selectedAgent.agentType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
});

// Log remote agent launch
logForDebugging(`[AGENT_TOOL] Remote agent launched: ${selectedAgent.agentType}`);
logForDebugging(`[AGENT_TOOL] taskId: ${taskId}`);
logForDebugging(`[AGENT_TOOL] sessionUrl: ${getRemoteTaskSessionUrl(sessionId)}`);

const remoteResult: RemoteLaunchedOutput = {
status: 'remote_launched',
taskId,
Expand Down Expand Up @@ -751,6 +786,12 @@ export const AgentTool = buildTool({
getWorktreeResult: cleanupWorktreeIfNeeded
})));
const canReadOutputFile = toolUseContext.options.tools.some(t => toolMatchesName(t, FILE_READ_TOOL_NAME) || toolMatchesName(t, BASH_TOOL_NAME));

// Log async agent launch
logForDebugging(`[AGENT_TOOL] Async agent launched: ${selectedAgent.agentType}`);
logForDebugging(`[AGENT_TOOL] agentId: ${agentBackgroundTask.agentId}`);
logForDebugging(`[AGENT_TOOL] outputFile: ${getTaskOutputPath(agentBackgroundTask.agentId)}`);

return {
data: {
isAsync: true as const,
Expand Down Expand Up @@ -1233,6 +1274,16 @@ export const AgentTool = buildTool({
logForDebugging(`Sync agent recovering from error with ${agentMessages.length} messages`);
}
const agentResult = finalizeAgentTool(agentMessages, syncAgentId, metadata);

// Log Agent completion with usage statistics
const duration = Date.now() - startTime;
logForDebugging(`[AGENT_TOOL] Agent completed: ${selectedAgent.agentType}`);
logForDebugging(`[AGENT_TOOL] agentId: ${syncAgentId}`);
logForDebugging(`[AGENT_TOOL] totalTokens: ${agentResult.totalTokens}`);
logForDebugging(`[AGENT_TOOL] totalToolUseCount: ${agentResult.totalToolUseCount}`);
logForDebugging(`[AGENT_TOOL] duration_ms: ${duration}`);
logForDebugging(`[AGENT_TOOL] content items: ${agentResult.content.length}`);

if (feature('TRANSCRIPT_CLASSIFIER')) {
const currentAppState = toolUseContext.getAppState();
const handoffWarning = await classifyHandoffIfNeeded({
Expand Down