devlyn-cli 2.5.7 → 2.6.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 +2 -2
- package/bin/devlyn.js +198 -103
- package/package.json +1 -1
- package/scripts/lint-skills.sh +4 -3
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ If devlyn-cli saved you time, [give it a star](https://github.com/fysoul17/devly
|
|
|
27
27
|
npx devlyn-cli
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
That's it. The
|
|
30
|
+
That's it. The installer opens with a single **agent selector** — pick any combination of **Claude Code**, **Codex CLI**, **oh-my-pi (omp)**, **Pi**, Gemini, Cursor, Copilot, or Windsurf, and devlyn installs into every one you choose in a single pass. Claude Code and any agent already present on your machine are pre-checked, so the common case is just Enter. Skill-capable agents receive the `devlyn:resolve`, `devlyn:ideate`, and `devlyn:design-ui` skills in the directory each one loads from: Codex → `~/.codex/skills/`, while **omp and Pi share `~/.agents/skills/`** — the cross-agent standard both read — so the bundle is written there once, not duplicated per agent. In Codex / omp / Pi, invoke them as skills (`$devlyn:resolve`, `$devlyn:ideate`, `$devlyn:design-ui`); in Claude Code they're slash commands (`/devlyn:resolve`). Run it again anytime to update. (`npx devlyn-cli -y` installs the Claude core non-interactively; `npx devlyn-cli agents <cli>` adds one agent later.)
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
@@ -39,7 +39,7 @@ devlyn-cli turns Claude Code into a hands-free development pipeline. The pipelin
|
|
|
39
39
|
ideate (optional) → resolve → ship
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
Codex
|
|
42
|
+
Non-Claude agents (Codex / omp / Pi): when one of these is selected, the workflows install as that agent's skills. Use `$devlyn:ideate`, `$devlyn:resolve`, or `$devlyn:design-ui`; the `/devlyn:*` slash-command form is for Claude Code.
|
|
43
43
|
|
|
44
44
|
### Step 1 (optional) — Plan with `/devlyn:ideate`
|
|
45
45
|
|
package/bin/devlyn.js
CHANGED
|
@@ -11,6 +11,19 @@ const AGENTS_SOURCE = path.join(__dirname, '..', 'agents-config');
|
|
|
11
11
|
const OPTIONAL_SKILLS_SOURCE = path.join(__dirname, '..', 'optional-skills');
|
|
12
12
|
const PKG = require('../package.json');
|
|
13
13
|
|
|
14
|
+
// The devlyn skill bundle installed into every skill-capable agent's loader
|
|
15
|
+
// directory. Single source of truth so codex/omp/pi stay in lockstep — adding a
|
|
16
|
+
// skill here installs it everywhere. Standards skills (code-*, root-cause-*,
|
|
17
|
+
// ui-*) stay Claude-core-only, matching the pre-existing Codex bundle.
|
|
18
|
+
const DEVLYN_CORE_SKILLS = ['devlyn:resolve', 'devlyn:ideate', 'devlyn:design-ui', '_shared'];
|
|
19
|
+
|
|
20
|
+
// Cross-agent shared skills directory read by BOTH oh-my-pi and Pi. Verified
|
|
21
|
+
// from the omp binary's skill-provider strings ("skills from .agents/skills —
|
|
22
|
+
// project walk-up + user home") and Pi's docs ("~/.agents/skills/"). Installing
|
|
23
|
+
// the bundle here once covers both agents — the de-dup driver writes it a single
|
|
24
|
+
// time even when both are selected.
|
|
25
|
+
const SHARED_AGENTS_SKILLS_DIR = path.join(os.homedir(), '.agents', 'skills');
|
|
26
|
+
|
|
14
27
|
// Cross-CLI agent installation targets
|
|
15
28
|
// Each entry maps a CLI tool to where its agent instructions should be placed
|
|
16
29
|
const CLI_TARGETS = {
|
|
@@ -22,9 +35,32 @@ const CLI_TARGETS = {
|
|
|
22
35
|
// Codex auto-loads skills from ~/.codex/skills/ (user-global). Same
|
|
23
36
|
// SKILL.md format as Claude Code; descriptions must stay ≤1024 chars.
|
|
24
37
|
skillsDir: path.join(os.homedir(), '.codex', 'skills'),
|
|
25
|
-
skillsToInstall:
|
|
38
|
+
skillsToInstall: DEVLYN_CORE_SKILLS,
|
|
26
39
|
detect: () => fs.existsSync(path.join(process.cwd(), 'AGENTS.md')) || fs.existsSync(path.join(process.cwd(), '.codex')),
|
|
27
40
|
},
|
|
41
|
+
omp: {
|
|
42
|
+
name: 'oh-my-pi (omp)',
|
|
43
|
+
instructionsFile: 'AGENTS.md',
|
|
44
|
+
baseInstructionsFile: 'AGENTS.md',
|
|
45
|
+
configDir: null, // omp discovers AGENTS.md at project root + user home
|
|
46
|
+
// omp loads skills from ~/.agents/skills (user home) — shared with Pi.
|
|
47
|
+
skillsDir: SHARED_AGENTS_SKILLS_DIR,
|
|
48
|
+
skillsToInstall: DEVLYN_CORE_SKILLS,
|
|
49
|
+
// Project-scoped only: machine-level ~/.omp must not auto-trigger a project
|
|
50
|
+
// AGENTS.md write via `npx devlyn-cli agents` in an unrelated repo.
|
|
51
|
+
detect: () => fs.existsSync(path.join(process.cwd(), '.omp')) || fs.existsSync(path.join(process.cwd(), '.agents')),
|
|
52
|
+
},
|
|
53
|
+
pi: {
|
|
54
|
+
name: 'Pi (earendil-works)',
|
|
55
|
+
instructionsFile: 'AGENTS.md',
|
|
56
|
+
baseInstructionsFile: 'AGENTS.md',
|
|
57
|
+
configDir: null, // Pi reads AGENTS.md / CLAUDE.md walking up from cwd
|
|
58
|
+
// Pi loads skills from ~/.agents/skills — shared with oh-my-pi.
|
|
59
|
+
skillsDir: SHARED_AGENTS_SKILLS_DIR,
|
|
60
|
+
skillsToInstall: DEVLYN_CORE_SKILLS,
|
|
61
|
+
// Project-scoped only (see omp): machine-level ~/.pi must not auto-trigger.
|
|
62
|
+
detect: () => fs.existsSync(path.join(process.cwd(), '.pi')) || fs.existsSync(path.join(process.cwd(), '.agents')),
|
|
63
|
+
},
|
|
28
64
|
gemini: {
|
|
29
65
|
name: 'Gemini CLI (Google)',
|
|
30
66
|
instructionsFile: 'GEMINI.md',
|
|
@@ -363,9 +399,9 @@ function cleanManagedSkillDirs(sourceSkillsDir, targetSkillsDir) {
|
|
|
363
399
|
return cleaned;
|
|
364
400
|
}
|
|
365
401
|
|
|
366
|
-
function multiSelect(items) {
|
|
402
|
+
function multiSelect(items, preselectedIndices = []) {
|
|
367
403
|
return new Promise((resolve) => {
|
|
368
|
-
const selected = new Set();
|
|
404
|
+
const selected = new Set(preselectedIndices.filter((i) => i >= 0 && i < items.length));
|
|
369
405
|
let cursor = 0;
|
|
370
406
|
let firstRender = true;
|
|
371
407
|
|
|
@@ -470,11 +506,15 @@ function installLocalSkill(skillName) {
|
|
|
470
506
|
copyRecursive(src, dest, targetDir);
|
|
471
507
|
|
|
472
508
|
// Mirror to every CLI skill-loader directory that already exists so optional
|
|
473
|
-
// skills are picked up by Codex (and any future CLI with a skillsDir)
|
|
474
|
-
// same way required skills are. Existing dir, not new dir — we don't
|
|
475
|
-
//
|
|
509
|
+
// skills are picked up by Codex/omp/Pi (and any future CLI with a skillsDir)
|
|
510
|
+
// the same way required skills are. Existing dir, not new dir — we don't
|
|
511
|
+
// create an agent install just because someone opted into a Claude-side skill.
|
|
512
|
+
// De-dup by directory: omp and Pi share ~/.agents/skills, so the mirror runs
|
|
513
|
+
// once per unique destination.
|
|
514
|
+
const mirrored = new Set();
|
|
476
515
|
for (const cli of Object.values(CLI_TARGETS)) {
|
|
477
|
-
if (!cli.skillsDir || !fs.existsSync(cli.skillsDir)) continue;
|
|
516
|
+
if (!cli.skillsDir || mirrored.has(cli.skillsDir) || !fs.existsSync(cli.skillsDir)) continue;
|
|
517
|
+
mirrored.add(cli.skillsDir);
|
|
478
518
|
const cliDest = path.join(cli.skillsDir, skillName);
|
|
479
519
|
if (fs.existsSync(cliDest)) fs.rmSync(cliDest, { recursive: true, force: true });
|
|
480
520
|
copyRecursive(src, cliDest, cli.skillsDir);
|
|
@@ -556,94 +596,136 @@ function installSkillsForCLI(cliKey) {
|
|
|
556
596
|
return copied;
|
|
557
597
|
}
|
|
558
598
|
|
|
559
|
-
|
|
599
|
+
// Strip devlyn's previously-appended "# Devlyn Agent Instructions" block from an
|
|
600
|
+
// instruction file (or the packaged base) before re-appending, so installs stay
|
|
601
|
+
// idempotent and never duplicate the block. Anchors on the LAST marker, not the
|
|
602
|
+
// first: the packaged AGENTS.md ships its own "# Devlyn Agent Instructions"
|
|
603
|
+
// section, so indexOf would truncate that real content — lastIndexOf targets the
|
|
604
|
+
// devlyn-appended block (always last) and preserves everything above it.
|
|
605
|
+
function stripManagedBlock(content) {
|
|
606
|
+
const marker = '# Devlyn Agent Instructions';
|
|
607
|
+
const markerIdx = content.lastIndexOf(marker);
|
|
608
|
+
if (markerIdx > 0) {
|
|
609
|
+
const sepIdx = content.lastIndexOf('\n---', markerIdx);
|
|
610
|
+
return content.slice(0, sepIdx > 0 ? sepIdx : markerIdx).trimEnd();
|
|
611
|
+
}
|
|
612
|
+
return content.trimEnd();
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// One-line description of exactly what selecting a CLI target installs, so the
|
|
616
|
+
// unified selector stays honest — "Gemini" (instructions only) must not look
|
|
617
|
+
// identical to "Codex" (instructions + skills).
|
|
618
|
+
function targetDesc(cli) {
|
|
619
|
+
if (cli.skillsDir) {
|
|
620
|
+
return `${cli.instructionsFile} + devlyn skills → ${cli.skillsDir.replace(os.homedir(), '~')}`;
|
|
621
|
+
}
|
|
622
|
+
if (cli.configDir) return `Agent instructions → ${cli.configDir}/`;
|
|
623
|
+
return `${cli.instructionsFile} instructions only`;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Install only the instruction file(s) for a CLI (no skills). Returns true when
|
|
627
|
+
// instruction content was written. Split from skills so the de-dup driver can
|
|
628
|
+
// write a shared destination (e.g. project AGENTS.md for codex/omp/pi) once.
|
|
629
|
+
function installInstructionsForCLI(cliKey) {
|
|
560
630
|
const cli = CLI_TARGETS[cliKey];
|
|
561
631
|
if (!cli) return false;
|
|
562
632
|
|
|
563
633
|
const agents = fs.existsSync(AGENTS_SOURCE)
|
|
564
634
|
? fs.readdirSync(AGENTS_SOURCE).filter((f) => f.endsWith('.md'))
|
|
565
635
|
: [];
|
|
636
|
+
if (agents.length === 0) return false;
|
|
566
637
|
|
|
567
|
-
|
|
568
|
-
log(`\n🤖 Installing agents for ${cli.name}...`, 'cyan');
|
|
638
|
+
log(`\n🤖 Installing agent instructions for ${cli.name}...`, 'cyan');
|
|
569
639
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
// Find the separator before the marker (---\n\n)
|
|
598
|
-
const sepIdx = existing.lastIndexOf('---', markerIdx);
|
|
599
|
-
existing = existing.slice(0, sepIdx > 0 ? sepIdx : markerIdx).trimEnd();
|
|
600
|
-
}
|
|
601
|
-
} else if (cli.baseInstructionsFile) {
|
|
602
|
-
const baseInstructionsSrc = path.join(__dirname, '..', cli.baseInstructionsFile);
|
|
603
|
-
if (fs.existsSync(baseInstructionsSrc)) {
|
|
604
|
-
existing = fs.readFileSync(baseInstructionsSrc, 'utf8').trimEnd();
|
|
605
|
-
}
|
|
640
|
+
if (cli.configDir) {
|
|
641
|
+
// CLI supports an agents directory — copy agent files there
|
|
642
|
+
const destDir = path.join(process.cwd(), cli.configDir);
|
|
643
|
+
if (!fs.existsSync(destDir)) {
|
|
644
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
645
|
+
}
|
|
646
|
+
for (const file of agents) {
|
|
647
|
+
const src = path.join(AGENTS_SOURCE, file);
|
|
648
|
+
const dest = path.join(destDir, file);
|
|
649
|
+
fs.copyFileSync(src, dest);
|
|
650
|
+
log(` → ${cli.configDir}/${file}`, 'dim');
|
|
651
|
+
}
|
|
652
|
+
} else {
|
|
653
|
+
// CLI uses a single instructions file — append agent content
|
|
654
|
+
const destFile = path.join(process.cwd(), cli.instructionsFile);
|
|
655
|
+
const separator = '\n\n---\n\n# Devlyn Agent Instructions\n\n';
|
|
656
|
+
const agentContent = agents.map((file) => {
|
|
657
|
+
return fs.readFileSync(path.join(AGENTS_SOURCE, file), 'utf8');
|
|
658
|
+
}).join('\n\n---\n\n');
|
|
659
|
+
|
|
660
|
+
let existing = '';
|
|
661
|
+
if (fs.existsSync(destFile)) {
|
|
662
|
+
existing = stripManagedBlock(fs.readFileSync(destFile, 'utf8'));
|
|
663
|
+
} else if (cli.baseInstructionsFile) {
|
|
664
|
+
const baseInstructionsSrc = path.join(__dirname, '..', cli.baseInstructionsFile);
|
|
665
|
+
if (fs.existsSync(baseInstructionsSrc)) {
|
|
666
|
+
existing = stripManagedBlock(fs.readFileSync(baseInstructionsSrc, 'utf8'));
|
|
606
667
|
}
|
|
607
|
-
|
|
608
|
-
fs.writeFileSync(destFile, existing + separator + agentContent + '\n');
|
|
609
|
-
log(` → ${cli.instructionsFile} (agent instructions appended)`, 'dim');
|
|
610
668
|
}
|
|
669
|
+
|
|
670
|
+
fs.writeFileSync(destFile, existing + separator + agentContent + '\n');
|
|
671
|
+
log(` → ${cli.instructionsFile} (agent instructions appended)`, 'dim');
|
|
611
672
|
}
|
|
673
|
+
return true;
|
|
674
|
+
}
|
|
612
675
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
676
|
+
// Install both instructions and skills for a single CLI. Used by the
|
|
677
|
+
// `agents <cli>` command; multi-target paths use installSelectedCLITargets.
|
|
678
|
+
function installAgentsForCLI(cliKey) {
|
|
679
|
+
const instr = installInstructionsForCLI(cliKey);
|
|
616
680
|
const skillsCopied = installSkillsForCLI(cliKey);
|
|
617
681
|
if (skillsCopied > 0) {
|
|
618
682
|
log(` → ${skillsCopied} skill${skillsCopied > 1 ? 's' : ''} installed (devlyn:resolve / devlyn:ideate / devlyn:design-ui / _shared)`, 'dim');
|
|
619
683
|
}
|
|
684
|
+
return instr || skillsCopied > 0;
|
|
685
|
+
}
|
|
620
686
|
|
|
621
|
-
|
|
687
|
+
// Install instructions + skills for a set of selected CLI targets, writing each
|
|
688
|
+
// unique destination exactly once. omp and Pi share project AGENTS.md and the
|
|
689
|
+
// ~/.agents/skills dir, so selecting both does not duplicate writes — this is
|
|
690
|
+
// the researched "group the common" model: targets are the user's selection,
|
|
691
|
+
// destinations are the unit of work.
|
|
692
|
+
function installSelectedCLITargets(cliKeys) {
|
|
693
|
+
const instrDone = new Set();
|
|
694
|
+
const skillsDone = new Set();
|
|
695
|
+
let count = 0;
|
|
696
|
+
for (const cliKey of cliKeys) {
|
|
697
|
+
const cli = CLI_TARGETS[cliKey];
|
|
698
|
+
if (!cli) continue;
|
|
699
|
+
const instrKey = cli.configDir ? `dir:${cli.configDir}` : `file:${cli.instructionsFile}`;
|
|
700
|
+
if (!instrDone.has(instrKey)) {
|
|
701
|
+
installInstructionsForCLI(cliKey);
|
|
702
|
+
instrDone.add(instrKey);
|
|
703
|
+
}
|
|
704
|
+
if (cli.skillsDir && !skillsDone.has(cli.skillsDir)) {
|
|
705
|
+
const copied = installSkillsForCLI(cliKey);
|
|
706
|
+
if (copied > 0) {
|
|
707
|
+
log(` → ${copied} skill${copied > 1 ? 's' : ''} → ${cli.skillsDir.replace(os.homedir(), '~')}`, 'dim');
|
|
708
|
+
}
|
|
709
|
+
skillsDone.add(cli.skillsDir);
|
|
710
|
+
}
|
|
711
|
+
count++;
|
|
712
|
+
}
|
|
713
|
+
return count;
|
|
622
714
|
}
|
|
623
715
|
|
|
624
716
|
function installAgentsForAllDetected() {
|
|
625
717
|
const detected = detectOtherCLIs();
|
|
626
718
|
if (detected.length === 0) return 0;
|
|
627
|
-
|
|
628
|
-
let installed = 0;
|
|
629
|
-
for (const cliKey of detected) {
|
|
630
|
-
if (installAgentsForCLI(cliKey)) installed++;
|
|
631
|
-
}
|
|
632
|
-
return installed;
|
|
719
|
+
return installSelectedCLITargets(detected);
|
|
633
720
|
}
|
|
634
721
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
log('❌ Config source not found', 'yellow');
|
|
641
|
-
process.exit(1);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Install core config
|
|
722
|
+
// Install the Claude Code core config: project .claude/ (skills, templates,
|
|
723
|
+
// settings, CLAUDE.md, .gitignore) plus global ~/.claude/settings.json tweaks.
|
|
724
|
+
// Extracted so the unified target selector installs it only when "Claude Code"
|
|
725
|
+
// is chosen. Behavior is unchanged from the previous unconditional core install.
|
|
726
|
+
function installClaudeCore() {
|
|
645
727
|
const targetDir = getTargetDir();
|
|
646
|
-
log('\n📁 Installing
|
|
728
|
+
log('\n📁 Installing Claude Code config to .claude/', 'green');
|
|
647
729
|
const refreshed = cleanManagedSkillDirs(
|
|
648
730
|
path.join(CONFIG_SOURCE, 'skills'),
|
|
649
731
|
path.join(targetDir, 'skills'),
|
|
@@ -747,40 +829,55 @@ async function init(skipPrompts = false) {
|
|
|
747
829
|
log(' → ~/.claude/settings.json (disabled adaptive thinking, enabled 1h prompt caching)', 'dim');
|
|
748
830
|
}
|
|
749
831
|
|
|
750
|
-
log('\n✅
|
|
832
|
+
log('\n✅ Claude Code config installed!', 'green');
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
async function init(skipPrompts = false) {
|
|
836
|
+
showLogo();
|
|
837
|
+
log('─'.repeat(44), 'dim');
|
|
751
838
|
|
|
752
|
-
|
|
839
|
+
if (!fs.existsSync(CONFIG_SOURCE)) {
|
|
840
|
+
log('❌ Config source not found', 'yellow');
|
|
841
|
+
process.exit(1);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// Non-interactive / -y: preserve historical behavior — install Claude core
|
|
845
|
+
// only. Multi-target selection needs a TTY; scripted runs add other agents
|
|
846
|
+
// via `npx devlyn-cli agents <cli>`.
|
|
753
847
|
if (skipPrompts || !process.stdin.isTTY) {
|
|
848
|
+
installClaudeCore();
|
|
754
849
|
log('\n💡 Add optional addons later: run `npx devlyn-cli` without -y', 'dim');
|
|
755
|
-
log(' Add Codex
|
|
850
|
+
log(' Add another agent (Codex / omp / Pi / …) later: `npx devlyn-cli agents <cli>`', 'dim');
|
|
756
851
|
log(`\n${COLORS.dim} Enjoying devlyn? Star it on GitHub — it helps others find it:${COLORS.reset}`);
|
|
757
852
|
log(` ${COLORS.purple}→ https://github.com/fysoul17/devlyn-cli${COLORS.reset}\n`);
|
|
758
853
|
return;
|
|
759
854
|
}
|
|
760
855
|
|
|
761
|
-
//
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
|
|
856
|
+
// Pick every agent to install devlyn into, up front. Claude Code is
|
|
857
|
+
// pre-checked (the happy path); every other agent is an explicit opt-in so a
|
|
858
|
+
// bare Enter never mutates a project's AGENTS.md or a shared skills dir for an
|
|
859
|
+
// agent the user didn't choose.
|
|
860
|
+
log('\n🎯 Select the agents to install devlyn into:\n', 'blue');
|
|
861
|
+
const targetOptions = [
|
|
862
|
+
{ key: 'claude', name: 'Claude Code', desc: '.claude/ config — skills, templates, settings, CLAUDE.md', type: 'cli' },
|
|
863
|
+
...Object.entries(CLI_TARGETS).map(([key, cli]) => ({ key, name: cli.name, desc: targetDesc(cli), type: 'cli' })),
|
|
864
|
+
];
|
|
865
|
+
const preselected = [targetOptions.findIndex((o) => o.key === 'claude')];
|
|
866
|
+
const selectedKeys = (await multiSelect(targetOptions, preselected)).map((t) => t.key);
|
|
867
|
+
|
|
868
|
+
if (selectedKeys.length === 0) {
|
|
869
|
+
log('\n💡 No agents selected — nothing installed.', 'yellow');
|
|
870
|
+
log(' Run `npx devlyn-cli` again and pick at least one agent.\n', 'dim');
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (selectedKeys.includes('claude')) {
|
|
875
|
+
installClaudeCore();
|
|
876
|
+
}
|
|
877
|
+
const cliKeys = selectedKeys.filter((k) => k !== 'claude');
|
|
878
|
+
if (cliKeys.length > 0) {
|
|
879
|
+
const installed = installSelectedCLITargets(cliKeys);
|
|
880
|
+
log(`\n ✅ Installed devlyn into ${installed} agent${installed !== 1 ? 's' : ''}`, 'green');
|
|
784
881
|
}
|
|
785
882
|
|
|
786
883
|
// Ask about optional addons (local skills + external packs)
|
|
@@ -806,9 +903,9 @@ async function init(skipPrompts = false) {
|
|
|
806
903
|
function showHelp() {
|
|
807
904
|
showLogo();
|
|
808
905
|
log('Usage:', 'green');
|
|
809
|
-
log(' npx devlyn-cli Install/update
|
|
906
|
+
log(' npx devlyn-cli Install/update devlyn (pick agents: Claude / Codex / omp / Pi / …)');
|
|
810
907
|
log(' npx devlyn-cli list List available skills & templates');
|
|
811
|
-
log(' npx devlyn-cli -y Install without prompts');
|
|
908
|
+
log(' npx devlyn-cli -y Install Claude core without prompts');
|
|
812
909
|
log(' npx devlyn-cli agents Install agents for detected CLIs');
|
|
813
910
|
log(' npx devlyn-cli agents all Install agents for all supported CLIs');
|
|
814
911
|
log(' npx devlyn-cli benchmark Run the resolve benchmark suite');
|
|
@@ -1065,12 +1162,10 @@ switch (command) {
|
|
|
1065
1162
|
log('─'.repeat(44), 'dim');
|
|
1066
1163
|
const subArg = args[1];
|
|
1067
1164
|
if (subArg === 'all') {
|
|
1068
|
-
// Install for all supported CLIs regardless of detection
|
|
1165
|
+
// Install for all supported CLIs regardless of detection. De-duped so the
|
|
1166
|
+
// shared ~/.agents/skills dir (omp + Pi) and shared AGENTS.md write once.
|
|
1069
1167
|
log('\n🤖 Installing agents for all supported CLIs...', 'blue');
|
|
1070
|
-
|
|
1071
|
-
for (const cliKey of Object.keys(CLI_TARGETS)) {
|
|
1072
|
-
if (installAgentsForCLI(cliKey)) count++;
|
|
1073
|
-
}
|
|
1168
|
+
const count = installSelectedCLITargets(Object.keys(CLI_TARGETS));
|
|
1074
1169
|
log(`\n✅ Agents installed for ${count} CLI${count !== 1 ? 's' : ''}`, 'green');
|
|
1075
1170
|
} else if (subArg && CLI_TARGETS[subArg]) {
|
|
1076
1171
|
// Install for a specific CLI
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devlyn-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "AI development toolkit for Claude Code — ideate, resolve, and ship with context engineering and agent orchestration",
|
|
5
5
|
"homepage": "https://github.com/fysoul17/devlyn-cli#readme",
|
|
6
6
|
"bin": {
|
package/scripts/lint-skills.sh
CHANGED
|
@@ -242,10 +242,11 @@ if [ ! -e "optional-skills/devlyn:design-ui" ]; then
|
|
|
242
242
|
else
|
|
243
243
|
bad "devlyn:design-ui must not be installed as an optional addon"
|
|
244
244
|
fi
|
|
245
|
-
if grep -Fq "
|
|
246
|
-
|
|
245
|
+
if grep -Fq "const DEVLYN_CORE_SKILLS = ['devlyn:resolve', 'devlyn:ideate', 'devlyn:design-ui', '_shared'];" bin/devlyn.js \
|
|
246
|
+
&& grep -Fq "skillsToInstall: DEVLYN_CORE_SKILLS" bin/devlyn.js; then
|
|
247
|
+
ok "Codex install includes devlyn:design-ui (via shared DEVLYN_CORE_SKILLS bundle)"
|
|
247
248
|
else
|
|
248
|
-
bad "Codex skillsToInstall must include devlyn:design-ui"
|
|
249
|
+
bad "Codex skillsToInstall must include devlyn:design-ui (shared DEVLYN_CORE_SKILLS bundle)"
|
|
249
250
|
fi
|
|
250
251
|
if ! grep -F "name: 'devlyn:design-ui'" bin/devlyn.js >/dev/null 2>&1; then
|
|
251
252
|
ok "devlyn:design-ui is absent from OPTIONAL_ADDONS"
|