Bunli
PackagesPlugin Packages

@bunli/plugin-ai-detect

AI agent detection plugin for Bunli

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()] as const,
});

// In your commands:
cli.command(
  defineCommand({
    name: "info",
    description: "Show information about the environment",
    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 variables: CLAUDECODE, CLAUDE_CODE
  • Detection: Checks for the presence of either CLAUDECODE or CLAUDE_CODE variable

Cursor

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

Codex (OpenAI)

  • Environment variables: CODEX_CI, CODEX_THREAD_ID, CODEX_SANDBOX
  • Detection: Checks for any of the Codex environment variables

Amp (Anthropic)

  • Environment variables: AMP_CURRENT_THREAD_ID, AGENT
  • Detection: Checks for AMP_CURRENT_THREAD_ID or when AGENT=amp

Gemini (Google)

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

OpenCode

  • Environment variable: OPENCODE
  • Detection: Checks for OPENCODE=1

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

handler: async ({ prompt, context, flags }) => {
  const name = context?.env.isAIAgent
    ? flags.name || "default-name"
    : await prompt("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"]);

On this page