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 +160 -4
- package/config/agents/evaluator.md +40 -0
- package/config/commands/devlyn.evaluate.md +467 -0
- package/config/commands/devlyn.team-resolve.md +2 -2
- package/optional-skills/dokkit/ANALYSIS.md +32 -1
- package/optional-skills/dokkit/COMMANDS.md +20 -13
- package/optional-skills/dokkit/FILLING.md +19 -0
- package/optional-skills/dokkit/IMAGE-SOURCING.md +2 -2
- package/optional-skills/dokkit/PIPELINE.md +348 -0
- package/optional-skills/dokkit/SKILL.md +169 -111
- package/optional-skills/dokkit/references/docx-section-range-detection.md +147 -0
- package/optional-skills/dokkit/references/image-opportunity-heuristics.md +1 -1
- package/optional-skills/dokkit/scripts/fill_docx.py +819 -0
- package/optional-skills/dokkit/scripts/parse_image_with_gemini.py +3 -3
- package/optional-skills/dokkit/scripts/source_images.py +40 -2
- package/package.json +1 -1
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
|
|
457
|
-
log(' npx devlyn-cli list
|
|
458
|
-
log(' npx devlyn-cli -y
|
|
459
|
-
log(' npx devlyn-cli
|
|
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
|
+
```
|