PackagesPlugin Packages
@bunli/plugin-ai-detect
AI agent detection plugin for Bunli
Installation
bun add @bunli/plugin-ai-detectFeatures
- 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
CLAUDECODEorCLAUDE_CODEvariable
Cursor
- Environment variable:
CURSOR_AGENT - Detection: Checks for the presence of
CURSOR_AGENTvariable
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_IDor whenAGENT=amp
Gemini (Google)
- Environment variable:
GEMINI_CLI - Detection: Checks for the presence of
GEMINI_CLIvariable
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: CLAUDECODECustom 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"]);