devlyn-cli 0.5.4 → 0.5.7

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/bin/devlyn.js CHANGED
@@ -6,10 +6,46 @@ const readline = require('readline');
6
6
  const { execSync } = require('child_process');
7
7
 
8
8
  const CONFIG_SOURCE = path.join(__dirname, '..', 'config');
9
+ const AGENTS_SOURCE = path.join(__dirname, '..', 'config', 'agents');
9
10
  const OPTIONAL_SKILLS_SOURCE = path.join(__dirname, '..', 'optional-skills');
10
11
  const OPTIONAL_COMMANDS_SOURCE = path.join(__dirname, '..', 'optional-commands');
11
12
  const PKG = require('../package.json');
12
13
 
14
+ // Cross-CLI agent installation targets
15
+ // Each entry maps a CLI tool to where its agent instructions should be placed
16
+ const CLI_TARGETS = {
17
+ codex: {
18
+ name: 'Codex CLI (OpenAI)',
19
+ instructionsFile: 'AGENTS.md',
20
+ configDir: null, // Codex uses AGENTS.md at project root
21
+ detect: () => fs.existsSync(path.join(process.cwd(), 'AGENTS.md')) || fs.existsSync(path.join(process.cwd(), '.codex')),
22
+ },
23
+ gemini: {
24
+ name: 'Gemini CLI (Google)',
25
+ instructionsFile: 'GEMINI.md',
26
+ configDir: null, // Gemini uses GEMINI.md at project root
27
+ detect: () => fs.existsSync(path.join(process.cwd(), 'GEMINI.md')) || fs.existsSync(path.join(process.cwd(), '.gemini')),
28
+ },
29
+ cursor: {
30
+ name: 'Cursor',
31
+ instructionsFile: '.cursorrules',
32
+ configDir: '.cursor/rules',
33
+ detect: () => fs.existsSync(path.join(process.cwd(), '.cursorrules')) || fs.existsSync(path.join(process.cwd(), '.cursor')),
34
+ },
35
+ copilot: {
36
+ name: 'GitHub Copilot',
37
+ instructionsFile: '.github/copilot-instructions.md',
38
+ configDir: '.github/copilot/agents',
39
+ detect: () => fs.existsSync(path.join(process.cwd(), '.github', 'copilot-instructions.md')) || fs.existsSync(path.join(process.cwd(), '.github', 'copilot')),
40
+ },
41
+ windsurf: {
42
+ name: 'Windsurf',
43
+ instructionsFile: '.windsurfrules',
44
+ configDir: '.windsurf/rules',
45
+ detect: () => fs.existsSync(path.join(process.cwd(), '.windsurfrules')) || fs.existsSync(path.join(process.cwd(), '.windsurf')),
46
+ },
47
+ };
48
+
13
49
  // Files removed in previous versions that should be cleaned up on upgrade
14
50
  const DEPRECATED_FILES = [
15
51
  'commands/devlyn.handoff.md', // removed in v0.2.0
@@ -78,6 +114,7 @@ const OPTIONAL_ADDONS = [
78
114
  { name: 'supabase/agent-skills', desc: 'Supabase integration patterns', type: 'external' },
79
115
  { name: 'coreyhaines31/marketingskills', desc: 'Marketing automation and content skills', type: 'external' },
80
116
  { name: 'anthropics/skills', desc: 'Official Anthropic skill-creator with eval framework and description optimizer', type: 'external' },
117
+ { name: 'Leonxlnx/taste-skill', desc: 'Premium frontend design skills — modern layouts, animations, and visual refinement', type: 'external' },
81
118
  ];
82
119
 
83
120
  function log(msg, color = 'reset') {
@@ -371,6 +408,77 @@ function installAddon(addon) {
371
408
  return installSkillPack(addon.name);
372
409
  }
373
410
 
411
+ function detectOtherCLIs() {
412
+ const detected = [];
413
+ for (const [key, cli] of Object.entries(CLI_TARGETS)) {
414
+ if (cli.detect()) {
415
+ detected.push(key);
416
+ }
417
+ }
418
+ return detected;
419
+ }
420
+
421
+ function installAgentsForCLI(cliKey) {
422
+ const cli = CLI_TARGETS[cliKey];
423
+ if (!cli) return false;
424
+ if (!fs.existsSync(AGENTS_SOURCE)) return false;
425
+
426
+ const agents = fs.readdirSync(AGENTS_SOURCE).filter((f) => f.endsWith('.md'));
427
+ if (agents.length === 0) return false;
428
+
429
+ log(`\nšŸ¤– Installing agents for ${cli.name}...`, 'cyan');
430
+
431
+ if (cli.configDir) {
432
+ // CLI supports an agents directory — copy agent files there
433
+ const destDir = path.join(process.cwd(), cli.configDir);
434
+ if (!fs.existsSync(destDir)) {
435
+ fs.mkdirSync(destDir, { recursive: true });
436
+ }
437
+ for (const file of agents) {
438
+ const src = path.join(AGENTS_SOURCE, file);
439
+ const dest = path.join(destDir, file);
440
+ fs.copyFileSync(src, dest);
441
+ log(` → ${cli.configDir}/${file}`, 'dim');
442
+ }
443
+ } else {
444
+ // CLI uses a single instructions file — append agent content
445
+ const destFile = path.join(process.cwd(), cli.instructionsFile);
446
+ const separator = '\n\n---\n\n# Devlyn Agent Instructions\n\n';
447
+ const agentContent = agents.map((file) => {
448
+ return fs.readFileSync(path.join(AGENTS_SOURCE, file), 'utf8');
449
+ }).join('\n\n---\n\n');
450
+
451
+ let existing = '';
452
+ if (fs.existsSync(destFile)) {
453
+ existing = fs.readFileSync(destFile, 'utf8');
454
+ // Remove previous devlyn agent section if present
455
+ const devlynMarker = '# Devlyn Agent Instructions';
456
+ const markerIdx = existing.indexOf(devlynMarker);
457
+ if (markerIdx > 0) {
458
+ // Find the separator before the marker (---\n\n)
459
+ const sepIdx = existing.lastIndexOf('---', markerIdx);
460
+ existing = existing.slice(0, sepIdx > 0 ? sepIdx : markerIdx).trimEnd();
461
+ }
462
+ }
463
+
464
+ fs.writeFileSync(destFile, existing + separator + agentContent + '\n');
465
+ log(` → ${cli.instructionsFile} (agent instructions appended)`, 'dim');
466
+ }
467
+
468
+ return true;
469
+ }
470
+
471
+ function installAgentsForAllDetected() {
472
+ const detected = detectOtherCLIs();
473
+ if (detected.length === 0) return 0;
474
+
475
+ let installed = 0;
476
+ for (const cliKey of detected) {
477
+ if (installAgentsForCLI(cliKey)) installed++;
478
+ }
479
+ return installed;
480
+ }
481
+
374
482
  async function init(skipPrompts = false) {
375
483
  showLogo();
376
484
  log('─'.repeat(44), 'dim');
@@ -416,6 +524,16 @@ async function init(skipPrompts = false) {
416
524
  log(' → settings.json (agent teams enabled)', 'dim');
417
525
  }
418
526
 
527
+ // Install agents for other detected CLIs
528
+ const detected = detectOtherCLIs();
529
+ if (detected.length > 0) {
530
+ log(`\nšŸ” Detected other AI CLIs: ${detected.map((k) => CLI_TARGETS[k].name).join(', ')}`, 'blue');
531
+ const agentsInstalled = installAgentsForAllDetected();
532
+ if (agentsInstalled > 0) {
533
+ log(` āœ… Agent instructions installed for ${agentsInstalled} CLI${agentsInstalled > 1 ? 's' : ''}`, 'green');
534
+ }
535
+ }
536
+
419
537
  log('\nāœ… Core config installed!', 'green');
420
538
 
421
539
  // Skip prompts if -y flag or non-interactive
@@ -453,10 +571,12 @@ async function init(skipPrompts = false) {
453
571
  function showHelp() {
454
572
  showLogo();
455
573
  log('Usage:', 'green');
456
- log(' npx devlyn-cli Install/update .claude config');
457
- log(' npx devlyn-cli list List available commands & templates');
458
- log(' npx devlyn-cli -y Install without prompts');
459
- log(' npx devlyn-cli --help Show this help\n');
574
+ log(' npx devlyn-cli Install/update .claude config');
575
+ log(' npx devlyn-cli list List available commands & templates');
576
+ log(' npx devlyn-cli -y Install without prompts');
577
+ log(' npx devlyn-cli agents Install agents for detected CLIs');
578
+ log(' npx devlyn-cli agents all Install agents for all supported CLIs');
579
+ log(' npx devlyn-cli --help Show this help\n');
460
580
  log('Optional skills (select during install):', 'green');
461
581
  OPTIONAL_ADDONS.filter((a) => a.type === 'local').forEach((skill) => {
462
582
  log(` ${skill.name} ${COLORS.dim}${skill.desc}${COLORS.reset}`);
@@ -465,6 +585,10 @@ function showHelp() {
465
585
  OPTIONAL_ADDONS.filter((a) => a.type === 'external').forEach((pack) => {
466
586
  log(` npx skills add ${pack.name}`);
467
587
  });
588
+ log('\nSupported CLIs for agent installation:', 'green');
589
+ for (const [key, cli] of Object.entries(CLI_TARGETS)) {
590
+ log(` ${key.padEnd(10)} ${cli.name}`);
591
+ }
468
592
  log('');
469
593
  }
470
594
 
@@ -485,6 +609,38 @@ switch (command) {
485
609
  case 'ls':
486
610
  listContents();
487
611
  break;
612
+ case 'agents': {
613
+ showLogo();
614
+ log('─'.repeat(44), 'dim');
615
+ const subArg = args[1];
616
+ if (subArg === 'all') {
617
+ // Install for all supported CLIs regardless of detection
618
+ log('\nšŸ¤– Installing agents for all supported CLIs...', 'blue');
619
+ let count = 0;
620
+ for (const cliKey of Object.keys(CLI_TARGETS)) {
621
+ if (installAgentsForCLI(cliKey)) count++;
622
+ }
623
+ log(`\nāœ… Agents installed for ${count} CLI${count !== 1 ? 's' : ''}`, 'green');
624
+ } else if (subArg && CLI_TARGETS[subArg]) {
625
+ // Install for a specific CLI
626
+ installAgentsForCLI(subArg);
627
+ log('\nāœ… Done!', 'green');
628
+ } else {
629
+ // Auto-detect and install
630
+ const detected = detectOtherCLIs();
631
+ if (detected.length === 0) {
632
+ log('\nšŸ” No other AI CLIs detected in this project.', 'yellow');
633
+ log(' Use `npx devlyn-cli agents all` to install for all supported CLIs', 'dim');
634
+ log(` Supported: ${Object.keys(CLI_TARGETS).join(', ')}`, 'dim');
635
+ } else {
636
+ log(`\nšŸ” Detected: ${detected.map((k) => CLI_TARGETS[k].name).join(', ')}`, 'blue');
637
+ const count = installAgentsForAllDetected();
638
+ log(`\nāœ… Agents installed for ${count} CLI${count !== 1 ? 's' : ''}`, 'green');
639
+ }
640
+ }
641
+ log('');
642
+ break;
643
+ }
488
644
  case 'init':
489
645
  case undefined:
490
646
  init(false);
@@ -0,0 +1,40 @@
1
+ # Evaluator Agent
2
+
3
+ You are a code quality evaluator. Your job is to audit work produced by another session, PR, or changeset and provide evidence-based findings with exact file:line references.
4
+
5
+ ## Evaluation Process
6
+
7
+ 1. **Discover scope**: Read the changeset (git diff, PR diff, or specified files)
8
+ 2. **Assess correctness**: Find bugs, logic errors, silent failures, missing error handling
9
+ 3. **Check architecture**: Verify patterns match existing codebase, no type duplication, proper wiring
10
+ 4. **Verify spec compliance**: If a spec exists (HANDOFF.md, RFC, issue), compare requirements vs implementation
11
+ 5. **Check error handling**: Every async operation needs loading, error, and empty states in UI. No silent catches.
12
+ 6. **Review API contracts**: New endpoints must follow existing conventions for naming, validation, error envelopes
13
+ 7. **Assess test coverage**: New modules need tests. Run the test suite and report results.
14
+
15
+ ## Rules
16
+
17
+ - Every finding must have a file:line reference. No guesswork.
18
+ - Classify by severity: CRITICAL (must fix), HIGH (should fix), MEDIUM (fix or justify), LOW (note)
19
+ - Call out what's done well, not just problems
20
+ - Look for cross-cutting patterns (e.g., same mistake repeated in multiple files)
21
+
22
+ ## Output Format
23
+
24
+ ```
25
+ ### Verdict: [PASS / PASS WITH ISSUES / NEEDS WORK / BLOCKED]
26
+
27
+ **Findings by Severity:**
28
+
29
+ CRITICAL:
30
+ - [domain] `file:line` - description
31
+
32
+ HIGH:
33
+ - [domain] `file:line` - description
34
+
35
+ **What's Good:**
36
+ - [positive observations]
37
+
38
+ **Recommendation:**
39
+ [next action]
40
+ ```