cairn-work 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,241 @@
1
+ # Cairn 🏔️
2
+
3
+ AI-native project management where markdown files are the source of truth.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npm install -g cairn
9
+ cairn onboard
10
+ ```
11
+
12
+ That's it! Cairn will detect your AI agent (Clawdbot, Claude Code, Cursor, etc.) and configure everything automatically.
13
+
14
+ ## What is Cairn?
15
+
16
+ Cairn is a project management system designed for working with AI agents. Instead of databases and web UIs, Cairn uses simple markdown files that both you and your AI agent can read and edit.
17
+
18
+ **Key features:**
19
+ - **Files are the source of truth** - No database, just markdown
20
+ - **AI-native** - Designed for AI agents to understand and work with
21
+ - **Agent detection** - Auto-configures for Clawdbot, Claude Code, Cursor, Windsurf
22
+ - **Simple hierarchy** - Projects → Tasks
23
+ - **Status tracking** - pending, active, review, blocked, completed
24
+
25
+ ## Installation
26
+
27
+ ### Global Install (Recommended)
28
+
29
+ ```bash
30
+ npm install -g cairn
31
+ # or
32
+ bun install -g cairn
33
+ ```
34
+
35
+ ### Test Locally
36
+
37
+ ```bash
38
+ git clone https://github.com/gregoryehill/cairn-cli.git
39
+ cd cairn-cli
40
+ bun install
41
+ bun link
42
+ ```
43
+
44
+ ## Commands
45
+
46
+ ### `cairn onboard`
47
+
48
+ Set up Cairn and configure your AI agent automatically.
49
+
50
+ ```bash
51
+ cairn onboard # Auto-detect agent
52
+ cairn onboard --agent clawdbot # Specific agent
53
+ cairn onboard --force # Re-run onboarding
54
+ ```
55
+
56
+ ### `cairn init`
57
+
58
+ Initialize workspace without agent configuration.
59
+
60
+ ```bash
61
+ cairn init # Create workspace in current directory
62
+ cairn init --path /custom # Custom location
63
+ ```
64
+
65
+ ### `cairn create`
66
+
67
+ Create projects and tasks.
68
+
69
+ ```bash
70
+ # Create a project
71
+ cairn create project "Launch My App"
72
+
73
+ # Create a task
74
+ cairn create task "Set up database" \\
75
+ --project launch-my-app
76
+ ```
77
+
78
+ ### `cairn doctor`
79
+
80
+ Check workspace health and fix issues.
81
+
82
+ ```bash
83
+ cairn doctor
84
+ ```
85
+
86
+ ### `cairn update-skill`
87
+
88
+ Update agent skill documentation.
89
+
90
+ ```bash
91
+ cairn update-skill # Update all detected agents
92
+ cairn update-skill --agent cursor # Specific agent
93
+ ```
94
+
95
+ ### `cairn update`
96
+
97
+ Check for and install CLI updates.
98
+
99
+ ```bash
100
+ cairn update # Check npm for latest version and prompt to upgrade
101
+ ```
102
+
103
+ ## Supported Agents
104
+
105
+ Cairn auto-detects and configures:
106
+
107
+ - **[Clawdbot](https://clawd.bot)** - Full integration via skills system
108
+ - **Claude Code** - Workspace context integration
109
+ - **Cursor** - .cursorrules integration
110
+ - **Windsurf** - Workspace integration
111
+ - **Generic** - Manual setup instructions for any AI agent
112
+
113
+ ## How It Works
114
+
115
+ ### File Structure
116
+
117
+ ```
118
+ ~/cairn/
119
+ projects/
120
+ launch-my-app/
121
+ charter.md # Project overview
122
+ tasks/
123
+ setup-database.md # Individual task
124
+ deploy-api.md # Another task
125
+ inbox/ # Incoming ideas
126
+ _drafts/ # Work in progress
127
+ ```
128
+
129
+ ### Project → Task
130
+
131
+ **Project** - A goal or initiative (e.g., "Launch My App")
132
+ **Task** - An atomic piece of work (e.g., "Set up database")
133
+
134
+ ### Status Workflow
135
+
136
+ `pending` → `active` → `review` → `completed`
137
+
138
+ Or if blocked: `active` → `blocked` → `active`
139
+
140
+ ### Working with AI Agents
141
+
142
+ After onboarding, your agent understands how to:
143
+ - Create and update projects/tasks
144
+ - Follow status workflows
145
+ - Log work with timestamps
146
+ - Ask for input when blocked
147
+
148
+ **Example conversation:**
149
+ ```
150
+ You: "Help me plan out my app launch"
151
+ Agent: "I'll create a project structure. What's your app called?"
152
+ You: "TaskMaster - a todo app"
153
+ Agent: *creates project with tasks for backend, frontend, deployment*
154
+ ```
155
+
156
+ ## Updates
157
+
158
+ ```bash
159
+ cairn update
160
+ ```
161
+
162
+ Checks npm for the latest version and prompts to upgrade.
163
+
164
+ Or update manually:
165
+ ```bash
166
+ npm update -g cairn
167
+ ```
168
+
169
+ Updates only affect the CLI and agent skills. Your workspace files are never touched.
170
+
171
+ ## Configuration
172
+
173
+ Cairn uses sensible defaults:
174
+ - **Workspace:** Current directory or `~/cairn`
175
+ - **Agent detection:** Automatic
176
+ - **Files:** Plain markdown with YAML frontmatter
177
+
178
+ Override workspace location:
179
+ ```bash
180
+ export CAIRN_WORKSPACE=/custom/path
181
+ ```
182
+
183
+ ## Philosophy
184
+
185
+ 1. **Context is King** - Keep all context in one place
186
+ 2. **Files > Databases** - Text files are portable and future-proof
187
+ 3. **Simple Beats Complete** - Start simple, add complexity when needed
188
+ 4. **AI-First** - Designed for human-AI collaboration
189
+
190
+ ## Troubleshooting
191
+
192
+ ### Agent not detected
193
+
194
+ ```bash
195
+ cairn doctor # Check setup
196
+ cairn onboard --force # Re-run onboarding
197
+ ```
198
+
199
+ ### Workspace issues
200
+
201
+ ```bash
202
+ cairn doctor # Auto-fix common issues
203
+ cairn init --path ~/cairn # Recreate structure
204
+ ```
205
+
206
+ ### Skill not updating
207
+
208
+ ```bash
209
+ cairn update-skill # Refresh agent skill
210
+ ```
211
+
212
+ ## Development
213
+
214
+ ```bash
215
+ git clone https://github.com/gregoryehill/cairn-cli.git
216
+ cd cairn-cli
217
+ bun install
218
+ bun link # Test locally
219
+ ```
220
+
221
+ Run tests:
222
+ ```bash
223
+ bun test
224
+ ```
225
+
226
+ ## Contributing
227
+
228
+ Contributions welcome! Open an issue or PR on GitHub.
229
+
230
+ ## License
231
+
232
+ MIT © Gregory Hill
233
+
234
+ ## Links
235
+
236
+ - **GitHub:** https://github.com/gregoryehill/cairn-cli
237
+ - **npm:** https://www.npmjs.com/package/cairn
238
+
239
+ ---
240
+
241
+ Built with ❤️ for AI-human collaboration
package/bin/cairn.js ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname, join } from 'path';
7
+ import { readFileSync } from 'fs';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
12
+
13
+ const program = new Command();
14
+
15
+ program
16
+ .name('cairn')
17
+ .description('🏔️ AI-native project management')
18
+ .version(packageJson.version);
19
+
20
+ // Import commands
21
+ import onboard from '../lib/commands/onboard.js';
22
+ import init from '../lib/commands/init.js';
23
+ import create from '../lib/commands/create.js';
24
+ import doctor from '../lib/commands/doctor.js';
25
+ import updateSkill from '../lib/commands/update-skill.js';
26
+ import update from '../lib/commands/update.js';
27
+
28
+ // Onboard command - full setup with agent detection
29
+ program
30
+ .command('onboard')
31
+ .description('Set up Cairn and configure your AI agent')
32
+ .option('--force', 'Force re-onboarding even if already set up')
33
+ .option('--agent <type>', 'Specify agent type (clawdbot|claude-code|cursor|generic)')
34
+ .option('--path <path>', 'Custom workspace path')
35
+ .action(onboard);
36
+
37
+ // Init command - workspace only, no agent setup
38
+ program
39
+ .command('init')
40
+ .description('Initialize Cairn workspace (without agent configuration)')
41
+ .option('--path <path>', 'Custom workspace path (default: current directory)')
42
+ .action(init);
43
+
44
+ // Create command - create projects/tasks
45
+ program
46
+ .command('create <type> <name>')
47
+ .description('Create a project or task')
48
+ .option('--project <slug>', 'Parent project (required for tasks)')
49
+ .option('--assignee <name>', 'Assignee name', 'you')
50
+ .option('--status <status>', 'Initial status', 'pending')
51
+ .option('--due <date>', 'Due date (YYYY-MM-DD)')
52
+ .option('--description <text>', 'Short description')
53
+ .option('--objective <text>', 'Detailed objective')
54
+ .action(create);
55
+
56
+ // Doctor command - check workspace health
57
+ program
58
+ .command('doctor')
59
+ .description('Check workspace health and fix issues')
60
+ .action(doctor);
61
+
62
+ // Update-skill command - refresh agent skill
63
+ program
64
+ .command('update-skill')
65
+ .description('Update agent skill documentation')
66
+ .option('--agent <type>', 'Specific agent to update')
67
+ .action(updateSkill);
68
+
69
+ // Update command - check for and install updates
70
+ program
71
+ .command('update')
72
+ .description('Check for and install Cairn CLI updates')
73
+ .action(update);
74
+
75
+ // Parse and handle errors
76
+ program.parseAsync(process.argv).catch((error) => {
77
+ console.error(chalk.red('Error:'), error.message);
78
+ process.exit(1);
79
+ });
@@ -0,0 +1,26 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import { existsSync } from 'fs';
3
+ import { join, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ describe('CLI Executable', () => {
10
+ test('cairn.js exists and is executable', () => {
11
+ const cliPath = join(__dirname, 'cairn.js');
12
+ expect(existsSync(cliPath)).toBe(true);
13
+ });
14
+
15
+ test('cairn.js has shebang', () => {
16
+ const cliPath = join(__dirname, 'cairn.js');
17
+ const content = require('fs').readFileSync(cliPath, 'utf-8');
18
+ expect(content.startsWith('#!/usr/bin/env node')).toBe(true);
19
+ });
20
+
21
+ test('cairn.js imports commander', () => {
22
+ const cliPath = join(__dirname, 'cairn.js');
23
+ const content = require('fs').readFileSync(cliPath, 'utf-8');
24
+ expect(content).toContain('commander');
25
+ });
26
+ });
@@ -0,0 +1,91 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import chalk from 'chalk';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ /**
10
+ * Set up Cairn for Claude Code
11
+ * Adds agent-skill.md to workspace context
12
+ */
13
+ export async function setupClaudeCode(workspacePath) {
14
+ const cwd = process.cwd();
15
+ const contextDir = join(cwd, '.claude-code');
16
+ const skillTemplate = join(__dirname, '../../skills/agent-skill.template.md');
17
+ const skillDest = join(contextDir, 'cairn-skill.md');
18
+
19
+ // Create context directory
20
+ if (!existsSync(contextDir)) {
21
+ mkdirSync(contextDir, { recursive: true });
22
+ }
23
+
24
+ // Read template and replace workspace placeholders
25
+ let skillContent = readFileSync(skillTemplate, 'utf-8');
26
+ const workspaceRoot = dirname(workspacePath);
27
+
28
+ skillContent = skillContent
29
+ .replace(/\{\{WORKSPACE_PATH\}\}/g, workspacePath)
30
+ .replace(/\{\{WORKSPACE_ROOT\}\}/g, workspaceRoot);
31
+
32
+ // Write skill to workspace
33
+ writeFileSync(skillDest, skillContent);
34
+ console.log(chalk.green('✓'), 'Cairn skill added to Claude Code workspace');
35
+
36
+ // Create instructions file
37
+ const instructionsPath = join(contextDir, 'cairn-instructions.md');
38
+ const instructions = `# Cairn Project Management
39
+
40
+ This workspace uses Cairn for project management.
41
+
42
+ **Workspace:** ${workspacePath}
43
+
44
+ **Skill documentation:** Read \`cairn-skill.md\` in this directory for the complete workflow.
45
+
46
+ **Key points:**
47
+ - All project files are in markdown format at ${workspacePath}
48
+ - Files are the source of truth (no database)
49
+ - Follow the project → task hierarchy
50
+ - Always update status before asking blocking questions
51
+ - Log all work in the Work Log section
52
+
53
+ Refer to cairn-skill.md for detailed instructions on working with Cairn files.
54
+ `;
55
+
56
+ writeFileSync(instructionsPath, instructions);
57
+ console.log(chalk.green('✓'), 'Cairn instructions added');
58
+
59
+ return true;
60
+ }
61
+
62
+ /**
63
+ * Get setup instructions for Claude Code
64
+ */
65
+ export function getClaudeCodeInstructions(workspacePath) {
66
+ return `
67
+ ${chalk.bold('Claude Code Setup Complete!')}
68
+
69
+ Your Cairn workspace: ${chalk.cyan(workspacePath)}
70
+ Context added at: ${chalk.cyan('.claude-code/')}
71
+
72
+ ${chalk.bold('Test it:')}
73
+ Ask Claude Code:
74
+ ${chalk.yellow('"Read .claude-code/cairn-skill.md and help me create a project"')}
75
+
76
+ ${chalk.dim('Note: You may need to reload the workspace for changes to take effect.')}
77
+ `;
78
+ }
79
+
80
+ /**
81
+ * Verify Claude Code setup
82
+ */
83
+ export function verifyClaudeCode() {
84
+ const contextPath = join(process.cwd(), '.claude-code', 'cairn-skill.md');
85
+
86
+ if (!existsSync(contextPath)) {
87
+ return { success: false, message: 'Cairn skill not found in workspace' };
88
+ }
89
+
90
+ return { success: true, message: 'Claude Code setup verified' };
91
+ }
@@ -0,0 +1,85 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import chalk from 'chalk';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ /**
11
+ * Set up Cairn for Clawdbot
12
+ * Installs skill file from template (agent detects its own identity)
13
+ */
14
+ export async function setupClawdbot(workspacePath) {
15
+ const clawdbotSkillsDir = join(homedir(), '.clawdbot', 'skills', 'cairn');
16
+ const skillTemplate = join(__dirname, '../../skills/agent-skill.template.md');
17
+ const skillDest = join(clawdbotSkillsDir, 'SKILL.md');
18
+
19
+ // Create skills directory if it doesn't exist
20
+ if (!existsSync(clawdbotSkillsDir)) {
21
+ mkdirSync(clawdbotSkillsDir, { recursive: true });
22
+ }
23
+
24
+ // Read template and replace workspace placeholders only
25
+ let skillContent = readFileSync(skillTemplate, 'utf-8');
26
+
27
+ // Determine workspace root (parent of workspace path, e.g., /home/user from /home/user/cairn)
28
+ const workspaceRoot = dirname(workspacePath);
29
+
30
+ // Replace workspace placeholders (agent will detect its own name)
31
+ skillContent = skillContent
32
+ .replace(/\{\{WORKSPACE_PATH\}\}/g, workspacePath)
33
+ .replace(/\{\{WORKSPACE_ROOT\}\}/g, workspaceRoot);
34
+
35
+ // Write skill file
36
+ writeFileSync(skillDest, skillContent);
37
+ console.log(chalk.green('✓'), 'Cairn skill added to Clawdbot');
38
+
39
+ // Create a config file with workspace path
40
+ const configPath = join(clawdbotSkillsDir, 'config.json');
41
+ const config = {
42
+ workspacePath,
43
+ version: '0.1.0',
44
+ installedAt: new Date().toISOString()
45
+ };
46
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
47
+
48
+ return true;
49
+ }
50
+
51
+ /**
52
+ * Get setup instructions for Clawdbot
53
+ */
54
+ export function getClawdbotInstructions(workspacePath) {
55
+ return `
56
+ ${chalk.bold('Clawdbot Setup Complete!')}
57
+
58
+ Your Cairn workspace: ${chalk.cyan(workspacePath)}
59
+ Skill installed at: ${chalk.cyan('~/.clawdbot/skills/cairn/')}
60
+
61
+ ${chalk.bold('Test it:')}
62
+ In your next Clawdbot session, try:
63
+ ${chalk.yellow('"Help me create a project called Launch My App"')}
64
+
65
+ The skill will be automatically available in new sessions.
66
+ `;
67
+ }
68
+
69
+ /**
70
+ * Verify Clawdbot setup
71
+ */
72
+ export function verifyClawdbot() {
73
+ const clawdbotPath = join(homedir(), '.clawdbot');
74
+ const skillPath = join(clawdbotPath, 'skills', 'cairn', 'SKILL.md');
75
+
76
+ if (!existsSync(clawdbotPath)) {
77
+ return { success: false, message: 'Clawdbot directory not found' };
78
+ }
79
+
80
+ if (!existsSync(skillPath)) {
81
+ return { success: false, message: 'Cairn skill not installed' };
82
+ }
83
+
84
+ return { success: true, message: 'Clawdbot setup verified' };
85
+ }
@@ -0,0 +1,107 @@
1
+ import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import chalk from 'chalk';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ /**
10
+ * Set up Cairn for Cursor
11
+ * Adds to .cursorrules or creates .cursor/ directory with skill
12
+ */
13
+ export async function setupCursor(workspacePath) {
14
+ const cwd = process.cwd();
15
+ const cursorRulesPath = join(cwd, '.cursorrules');
16
+ const skillTemplate = join(__dirname, '../../skills/agent-skill.template.md');
17
+
18
+ // Strategy 1: Add to .cursorrules if it exists
19
+ if (existsSync(cursorRulesPath)) {
20
+ const existing = readFileSync(cursorRulesPath, 'utf8');
21
+ const cairnRule = `
22
+
23
+ # Cairn Project Management
24
+
25
+ This project uses Cairn for project management.
26
+
27
+ **Workspace:** ${workspacePath}
28
+
29
+ When working with project management tasks:
30
+ 1. All files are in markdown format at ${workspacePath}
31
+ 2. Follow project → task hierarchy
32
+ 3. Update status before asking for blocking information
33
+ 4. Log all work with timestamps
34
+
35
+ See .cursor/cairn-skill.md for complete workflow documentation.
36
+ `;
37
+
38
+ if (!existing.includes('Cairn Project Management')) {
39
+ writeFileSync(cursorRulesPath, existing + cairnRule);
40
+ console.log(chalk.green('✓'), 'Cairn rules added to .cursorrules');
41
+ } else {
42
+ console.log(chalk.yellow('⚠'), '.cursorrules already contains Cairn rules');
43
+ }
44
+ }
45
+
46
+ // Strategy 2: Create .cursor/ directory with skill
47
+ const cursorDir = join(cwd, '.cursor');
48
+ if (!existsSync(cursorDir)) {
49
+ mkdirSync(cursorDir, { recursive: true });
50
+ }
51
+
52
+ // Read template and replace workspace placeholders
53
+ let skillContent = readFileSync(skillTemplate, 'utf-8');
54
+ const workspaceRoot = dirname(workspacePath);
55
+
56
+ skillContent = skillContent
57
+ .replace(/\{\{WORKSPACE_PATH\}\}/g, workspacePath)
58
+ .replace(/\{\{WORKSPACE_ROOT\}\}/g, workspaceRoot);
59
+
60
+ const skillDest = join(cursorDir, 'cairn-skill.md');
61
+ writeFileSync(skillDest, skillContent);
62
+ console.log(chalk.green('✓'), 'Cairn skill added to .cursor/');
63
+
64
+ // Create config
65
+ const configPath = join(cursorDir, 'cairn-config.json');
66
+ const config = {
67
+ workspacePath,
68
+ version: '0.1.0',
69
+ installedAt: new Date().toISOString()
70
+ };
71
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
72
+
73
+ return true;
74
+ }
75
+
76
+ /**
77
+ * Get setup instructions for Cursor
78
+ */
79
+ export function getCursorInstructions(workspacePath) {
80
+ return `
81
+ ${chalk.bold('Cursor Setup Complete!')}
82
+
83
+ Your Cairn workspace: ${chalk.cyan(workspacePath)}
84
+ Configuration: ${chalk.cyan('.cursor/')} and ${chalk.cyan('.cursorrules')}
85
+
86
+ ${chalk.bold('Test it:')}
87
+ Ask Cursor:
88
+ ${chalk.yellow('"Read .cursor/cairn-skill.md and help me create a project"')}
89
+
90
+ ${chalk.dim('Note: Cursor should automatically pick up .cursorrules on next prompt.')}
91
+ `;
92
+ }
93
+
94
+ /**
95
+ * Verify Cursor setup
96
+ */
97
+ export function verifyCursor() {
98
+ const cwd = process.cwd();
99
+ const rulesPath = join(cwd, '.cursorrules');
100
+ const skillPath = join(cwd, '.cursor', 'cairn-skill.md');
101
+
102
+ if (!existsSync(rulesPath) && !existsSync(skillPath)) {
103
+ return { success: false, message: 'Cairn not configured for Cursor' };
104
+ }
105
+
106
+ return { success: true, message: 'Cursor setup verified' };
107
+ }
@@ -0,0 +1,60 @@
1
+ import { existsSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join } from 'path';
4
+
5
+ /**
6
+ * Detect which AI agent(s) are available in the environment
7
+ * @returns {Object} { primary: string, detected: string[] }
8
+ */
9
+ export function detectAgents() {
10
+ const detected = [];
11
+
12
+ // Check for Clawdbot
13
+ const clawdbotPath = join(homedir(), '.clawdbot');
14
+ if (existsSync(clawdbotPath)) {
15
+ detected.push('clawdbot');
16
+ }
17
+
18
+ // Check for Claude Code
19
+ // Claude Code typically sets environment variables or has workspace indicators
20
+ if (process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_CODE_WORKSPACE) {
21
+ detected.push('claude-code');
22
+ }
23
+
24
+ // Check for Cursor
25
+ // Cursor uses .cursorrules file or sets env variables
26
+ if (existsSync('.cursorrules') || process.env.CURSOR_WORKSPACE) {
27
+ detected.push('cursor');
28
+ }
29
+
30
+ // Check for Windsurf
31
+ if (process.env.WINDSURF_WORKSPACE) {
32
+ detected.push('windsurf');
33
+ }
34
+
35
+ // Determine primary agent (first detected, or generic)
36
+ const primary = detected[0] || 'generic';
37
+
38
+ return { primary, detected };
39
+ }
40
+
41
+ /**
42
+ * Get agent display name
43
+ */
44
+ export function getAgentName(type) {
45
+ const names = {
46
+ 'clawdbot': 'Clawdbot',
47
+ 'claude-code': 'Claude Code',
48
+ 'cursor': 'Cursor',
49
+ 'windsurf': 'Windsurf',
50
+ 'generic': 'Generic AI Agent'
51
+ };
52
+ return names[type] || type;
53
+ }
54
+
55
+ /**
56
+ * Check if an agent type is supported
57
+ */
58
+ export function isSupportedAgent(type) {
59
+ return ['clawdbot', 'claude-code', 'cursor', 'windsurf', 'generic'].includes(type);
60
+ }