Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Contributor

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