Bunli
Packages/Plugin Packages

@bunli/plugin-ai-detect

AI agent detection plugin for Bunli

@bunli/plugin-ai-detect

The AI detect plugin automatically detects when your CLI is being run by AI coding assistants like Claude, Cursor, and others. This enables you to provide AI-optimized output or adjust behavior based on the execution context.

Installation

bun add @bunli/plugin-ai-detect

Features

  • Detect popular AI coding assistants
  • Type-safe store integration
  • Module augmentation for environment info
  • Support for custom AI agent detection
  • Verbose logging option
  • Zero configuration required

Basic Usage

import { createCLI } from '@bunli/core'
import { aiAgentPlugin } from '@bunli/plugin-ai-detect'

const cli = await createCLI({
  name: 'my-cli',
  plugins: [
    aiAgentPlugin()
  ]
})

// In your commands:
cli.command(defineCommand({
  name: 'info',
  handler: async ({ context }) => {
    if (context?.env.isAIAgent) {
      console.log('Running in AI agent environment!')
      console.log(`Detected: ${context.store.aiAgents.join(', ')}`)
    }
  }
}))

Options

interface AIDetectPluginOptions {
  /**
   * Additional custom AI agents to detect
   */
  customAgents?: AIAgentInfo[]
  
  /**
   * Whether to log detection results
   * Default: false
   */
  verbose?: boolean
}

Store Properties

The plugin provides a type-safe store with the following properties:

interface AIDetectStore {
  /** Whether any AI agent was detected */
  isAIAgent: boolean
  
  /** Array of detected AI agent names */
  aiAgents: string[]
  
  /** Environment variables that triggered detection */
  aiAgentEnvVars: string[]
}

Built-in AI Agents

The plugin detects these AI agents out of the box:

Claude (Anthropic)

  • Environment variable: CLAUDECODE
  • Detection: Checks for the presence of CLAUDECODE variable

Cursor

  • Environment variable: CURSOR_TRACE_ID
  • Detection: Checks for the presence of CURSOR_TRACE_ID variable

Examples

Verbose Output

aiAgentPlugin({ verbose: true })

// Output when AI agent detected:
// 🤖 AI agent detected: claude
//    Environment variables: CLAUDECODE

Custom AI Agents

aiAgentPlugin({
  customAgents: [
    {
      name: 'github-copilot',
      envVars: ['GITHUB_COPILOT_ACTIVE'],
      detect: (env) => !!env.GITHUB_COPILOT_ACTIVE
    },
    {
      name: 'codeium',
      envVars: ['CODEIUM_API_KEY', 'CODEIUM_ENABLED'],
      detect: (env) => !!env.CODEIUM_API_KEY || env.CODEIUM_ENABLED === '1'
    }
  ]
})

AI-Optimized Output

cli.command(defineCommand({
  name: 'generate',
  handler: async ({ context, flags }) => {
    const isAI = context?.env.isAIAgent
    
    if (isAI) {
      // Provide structured output for AI agents
      console.log('```json')
      console.log(JSON.stringify({
        status: 'success',
        files: generatedFiles,
        nextSteps: [
          'Review the generated files',
          'Run tests with `bun test`',
          'Deploy with `bun run deploy`'
        ]
      }, null, 2))
      console.log('```')
    } else {
      // Human-friendly output
      console.log('✅ Generated successfully!')
      console.log(`\nCreated ${generatedFiles.length} files:`)
      generatedFiles.forEach(f => console.log(`  - ${f}`))
    }
  }
}))

Conditional Features

cli.command(defineCommand({
  name: 'debug',
  handler: async ({ context }) => {
    // Enable extra debugging for AI agents
    const debugLevel = context?.env.isAIAgent ? 'verbose' : 'normal'
    
    if (context?.store.isAIAgent) {
      console.log('AI Context Information:')
      console.log(`- Agents: ${context.store.aiAgents.join(', ')}`)
      console.log(`- Env vars: ${context.store.aiAgentEnvVars.join(', ')}`)
      console.log(`- Debug level: ${debugLevel}`)
    }
  }
}))

Module Augmentation

The plugin extends the EnvironmentInfo interface:

declare module '@bunli/core/plugin' {
  interface EnvironmentInfo {
    /** AI agent detected */
    isAIAgent: boolean
    
    /** Detected AI agents */
    aiAgents: string[]
  }
}

This means you can access AI detection info through context.env:

if (context.env.isAIAgent) {
  console.log(`AI agents: ${context.env.aiAgents.join(', ')}`)
}

Use Cases

1. Structured Error Output

try {
  await riskyOperation()
} catch (error) {
  if (context?.env.isAIAgent) {
    // Structured error for AI parsing
    console.error(JSON.stringify({
      error: {
        message: error.message,
        stack: error.stack,
        code: error.code,
        suggestions: getSuggestions(error)
      }
    }))
  } else {
    // Human-friendly error
    console.error(`❌ ${error.message}`)
  }
}

2. Skip Interactive Prompts

import { prompt } from '@bunli/prompts'

const name = context?.env.isAIAgent 
  ? flags.name || 'default-name'  // Use defaults for AI
  : await prompt({                 // Interactive for humans
      type: 'text',
      message: 'Enter project name:'
    })

3. Enhanced Logging

const logger = {
  info: (msg: string) => {
    if (context?.env.isAIAgent) {
      console.log(`[INFO] ${new Date().toISOString()} ${msg}`)
    } else {
      console.log(`ℹ️  ${msg}`)
    }
  }
}

Best Practices

1. Always Check for Context

// ✅ Good - defensive checking
if (context?.env.isAIAgent) {
  // AI-specific logic
}

// ❌ Bad - assumes context exists
if (context.env.isAIAgent) {
  // May throw error
}

2. Provide Structured Data

When AI is detected, prefer structured output:

if (context?.env.isAIAgent) {
  // Structured data
  console.log(JSON.stringify(result, null, 2))
} else {
  // Pretty formatted
  console.table(result)
}

3. Document AI Behavior

Let users know about AI-specific features:

export const command = defineCommand({
  name: 'build',
  description: 'Build the project (AI agents receive JSON output)',
  // ...
})

4. Test Both Modes

// Test with AI agent
process.env.CLAUDECODE = '1'
await cli.run(['build'])

// Test without AI agent
delete process.env.CLAUDECODE
await cli.run(['build'])