/ skills / bundled / debug.ts
debug.ts
  1  import { open, stat } from 'fs/promises'
  2  import { CLAUDE_CODE_GUIDE_AGENT_TYPE } from 'src/tools/AgentTool/built-in/claudeCodeGuideAgent.js'
  3  import { getSettingsFilePathForSource } from 'src/utils/settings/settings.js'
  4  import { enableDebugLogging, getDebugLogPath } from '../../utils/debug.js'
  5  import { errorMessage, isENOENT } from '../../utils/errors.js'
  6  import { formatFileSize } from '../../utils/format.js'
  7  import { registerBundledSkill } from '../bundledSkills.js'
  8  
  9  const DEFAULT_DEBUG_LINES_READ = 20
 10  const TAIL_READ_BYTES = 64 * 1024
 11  
 12  export function registerDebugSkill(): void {
 13    registerBundledSkill({
 14      name: 'debug',
 15      description:
 16        process.env.USER_TYPE === 'ant'
 17          ? 'Debug your current Claude Code session by reading the session debug log. Includes all event logging'
 18          : 'Enable debug logging for this session and help diagnose issues',
 19      allowedTools: ['Read', 'Grep', 'Glob'],
 20      argumentHint: '[issue description]',
 21      // disableModelInvocation so that the user has to explicitly request it in
 22      // interactive mode and so the description does not take up context.
 23      disableModelInvocation: true,
 24      userInvocable: true,
 25      async getPromptForCommand(args) {
 26        // Non-ants don't write debug logs by default — turn logging on now so
 27        // subsequent activity in this session is captured.
 28        const wasAlreadyLogging = enableDebugLogging()
 29        const debugLogPath = getDebugLogPath()
 30  
 31        let logInfo: string
 32        try {
 33          // Tail the log without reading the whole thing - debug logs grow
 34          // unbounded in long sessions and reading them in full spikes RSS.
 35          const stats = await stat(debugLogPath)
 36          const readSize = Math.min(stats.size, TAIL_READ_BYTES)
 37          const startOffset = stats.size - readSize
 38          const fd = await open(debugLogPath, 'r')
 39          try {
 40            const { buffer, bytesRead } = await fd.read({
 41              buffer: Buffer.alloc(readSize),
 42              position: startOffset,
 43            })
 44            const tail = buffer
 45              .toString('utf-8', 0, bytesRead)
 46              .split('\n')
 47              .slice(-DEFAULT_DEBUG_LINES_READ)
 48              .join('\n')
 49            logInfo = `Log size: ${formatFileSize(stats.size)}\n\n### Last ${DEFAULT_DEBUG_LINES_READ} lines\n\n\`\`\`\n${tail}\n\`\`\``
 50          } finally {
 51            await fd.close()
 52          }
 53        } catch (e) {
 54          logInfo = isENOENT(e)
 55            ? 'No debug log exists yet — logging was just enabled.'
 56            : `Failed to read last ${DEFAULT_DEBUG_LINES_READ} lines of debug log: ${errorMessage(e)}`
 57        }
 58  
 59        const justEnabledSection = wasAlreadyLogging
 60          ? ''
 61          : `
 62  ## Debug Logging Just Enabled
 63  
 64  Debug logging was OFF for this session until now. Nothing prior to this /debug invocation was captured.
 65  
 66  Tell the user that debug logging is now active at \`${debugLogPath}\`, ask them to reproduce the issue, then re-read the log. If they can't reproduce, they can also restart with \`claude --debug\` to capture logs from startup.
 67  `
 68  
 69        const prompt = `# Debug Skill
 70  
 71  Help the user debug an issue they're encountering in this current Claude Code session.
 72  ${justEnabledSection}
 73  ## Session Debug Log
 74  
 75  The debug log for the current session is at: \`${debugLogPath}\`
 76  
 77  ${logInfo}
 78  
 79  For additional context, grep for [ERROR] and [WARN] lines across the full file.
 80  
 81  ## Issue Description
 82  
 83  ${args || 'The user did not describe a specific issue. Read the debug log and summarize any errors, warnings, or notable issues.'}
 84  
 85  ## Settings
 86  
 87  Remember that settings are in:
 88  * user - ${getSettingsFilePathForSource('userSettings')}
 89  * project - ${getSettingsFilePathForSource('projectSettings')}
 90  * local - ${getSettingsFilePathForSource('localSettings')}
 91  
 92  ## Instructions
 93  
 94  1. Review the user's issue description
 95  2. The last ${DEFAULT_DEBUG_LINES_READ} lines show the debug file format. Look for [ERROR] and [WARN] entries, stack traces, and failure patterns across the file
 96  3. Consider launching the ${CLAUDE_CODE_GUIDE_AGENT_TYPE} subagent to understand the relevant Claude Code features
 97  4. Explain what you found in plain language
 98  5. Suggest concrete fixes or next steps
 99  `
100        return [{ type: 'text', text: prompt }]
101      },
102    })
103  }