@orchestra-research/ai-research-skills 1.0.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 +97 -0
- package/bin/cli.js +8 -0
- package/package.json +46 -0
- package/src/agents.js +81 -0
- package/src/ascii.js +126 -0
- package/src/index.js +282 -0
- package/src/installer.js +391 -0
- package/src/prompts.js +436 -0
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @orchestra-research/ai-research-skills
|
|
2
|
+
|
|
3
|
+
Install AI research engineering skills to your coding agents (Claude Code, Cursor, Gemini CLI, and more).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @orchestra-research/ai-research-skills
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **82 skills** across 20 categories for AI research engineering
|
|
12
|
+
- **Auto-detects** installed coding agents
|
|
13
|
+
- **Interactive installer** with guided experience
|
|
14
|
+
- **One canonical copy** with symlinks to all agents
|
|
15
|
+
- **Works with 7 agents**: Claude Code, Cursor, Codex, Windsurf, Gemini CLI, Kilo Code, Qwen Code
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
Run the interactive installer:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @orchestra-research/ai-research-skills
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This will:
|
|
26
|
+
1. Detect your installed coding agents
|
|
27
|
+
2. Let you choose what to install (everything, categories, or quick start bundle)
|
|
28
|
+
3. Download skills from GitHub
|
|
29
|
+
4. Create symlinks to each agent's skills directory
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Interactive mode (recommended)
|
|
35
|
+
npx @orchestra-research/ai-research-skills
|
|
36
|
+
|
|
37
|
+
# Install everything
|
|
38
|
+
npx @orchestra-research/ai-research-skills install --all
|
|
39
|
+
|
|
40
|
+
# Install a specific category
|
|
41
|
+
npx @orchestra-research/ai-research-skills install post-training
|
|
42
|
+
|
|
43
|
+
# List installed skills
|
|
44
|
+
npx @orchestra-research/ai-research-skills list
|
|
45
|
+
|
|
46
|
+
# Update all skills
|
|
47
|
+
npx @orchestra-research/ai-research-skills update
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Categories
|
|
51
|
+
|
|
52
|
+
| Category | Skills | Description |
|
|
53
|
+
|----------|--------|-------------|
|
|
54
|
+
| Model Architecture | 6 | LitGPT, Mamba, TorchTitan, Megatron... |
|
|
55
|
+
| Post-Training | 8 | GRPO, verl, slime, miles, torchforge... |
|
|
56
|
+
| Fine-Tuning | 5 | Axolotl, Unsloth, PEFT, Torchtune... |
|
|
57
|
+
| Distributed Training | 6 | DeepSpeed, FSDP, Megatron... |
|
|
58
|
+
| Inference Serving | 4 | vLLM, TensorRT-LLM, SGLang... |
|
|
59
|
+
| Optimization | 6 | Flash Attention, GPTQ, AWQ... |
|
|
60
|
+
| And 14 more... | | |
|
|
61
|
+
|
|
62
|
+
## How It Works
|
|
63
|
+
|
|
64
|
+
1. **Canonical Storage**: Skills are stored once at `~/.agents/skills/`
|
|
65
|
+
2. **Symlinks**: Each agent gets symlinks pointing to the canonical copy
|
|
66
|
+
3. **Auto-activation**: Skills activate when you discuss relevant topics
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
~/.agents/skills/ # Single source of truth
|
|
70
|
+
├── 06-post-training/
|
|
71
|
+
│ ├── verl/
|
|
72
|
+
│ └── grpo-rl-training/
|
|
73
|
+
└── ...
|
|
74
|
+
|
|
75
|
+
~/.claude/skills/ # Symlinks for Claude Code
|
|
76
|
+
├── verl → ~/.agents/skills/.../verl
|
|
77
|
+
└── grpo-rl-training → ...
|
|
78
|
+
|
|
79
|
+
~/.cursor/skills/ # Symlinks for Cursor
|
|
80
|
+
└── (same links)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Supported Agents
|
|
84
|
+
|
|
85
|
+
| Agent | Config Directory |
|
|
86
|
+
|-------|-----------------|
|
|
87
|
+
| Claude Code | `~/.claude` |
|
|
88
|
+
| Cursor | `~/.cursor` |
|
|
89
|
+
| Codex (OpenAI) | `~/.codex` |
|
|
90
|
+
| Windsurf | `~/.windsurf` |
|
|
91
|
+
| Gemini CLI | `~/.gemini` |
|
|
92
|
+
| Kilo Code | `~/.kilocode` |
|
|
93
|
+
| Qwen Code | `~/.qwen` |
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT - Orchestra Research
|
package/bin/cli.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@orchestra-research/ai-research-skills",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Install AI research engineering skills to your coding agents (Claude Code, Cursor, Gemini CLI, and more)",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ai-research-skills": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node bin/cli.js",
|
|
12
|
+
"test": "node --test"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ai",
|
|
16
|
+
"research",
|
|
17
|
+
"skills",
|
|
18
|
+
"claude",
|
|
19
|
+
"cursor",
|
|
20
|
+
"gemini",
|
|
21
|
+
"codex",
|
|
22
|
+
"windsurf",
|
|
23
|
+
"llm",
|
|
24
|
+
"machine-learning",
|
|
25
|
+
"deep-learning",
|
|
26
|
+
"cli"
|
|
27
|
+
],
|
|
28
|
+
"author": "Orchestra Research",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/orchestra-research/ai-research-skills.git"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/orchestra-research/ai-research-skills",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/orchestra-research/ai-research-skills/issues"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"chalk": "^5.3.0",
|
|
43
|
+
"inquirer": "^9.2.12",
|
|
44
|
+
"ora": "^8.0.1"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/agents.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Supported coding agents with their global config directories and skills paths
|
|
7
|
+
* All agents now support ~/.{agent}/skills/ format
|
|
8
|
+
*/
|
|
9
|
+
export const SUPPORTED_AGENTS = [
|
|
10
|
+
{
|
|
11
|
+
id: 'claude',
|
|
12
|
+
name: 'Claude Code',
|
|
13
|
+
configDir: '.claude',
|
|
14
|
+
skillsDir: 'skills',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'cursor',
|
|
18
|
+
name: 'Cursor',
|
|
19
|
+
configDir: '.cursor',
|
|
20
|
+
skillsDir: 'skills',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'codex',
|
|
24
|
+
name: 'Codex',
|
|
25
|
+
configDir: '.codex',
|
|
26
|
+
skillsDir: 'skills',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'gemini',
|
|
30
|
+
name: 'Gemini CLI',
|
|
31
|
+
configDir: '.gemini',
|
|
32
|
+
skillsDir: 'skills',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'qwen',
|
|
36
|
+
name: 'Qwen Code',
|
|
37
|
+
configDir: '.qwen',
|
|
38
|
+
skillsDir: 'skills',
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Detect which coding agents are installed on the system
|
|
44
|
+
* @returns {Array} List of detected agents with their paths
|
|
45
|
+
*/
|
|
46
|
+
export function detectAgents() {
|
|
47
|
+
const home = homedir();
|
|
48
|
+
const detected = [];
|
|
49
|
+
|
|
50
|
+
for (const agent of SUPPORTED_AGENTS) {
|
|
51
|
+
const configPath = join(home, agent.configDir);
|
|
52
|
+
|
|
53
|
+
if (existsSync(configPath)) {
|
|
54
|
+
detected.push({
|
|
55
|
+
...agent,
|
|
56
|
+
path: `~/${agent.configDir}`,
|
|
57
|
+
fullPath: configPath,
|
|
58
|
+
skillsPath: join(configPath, agent.skillsDir),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return detected;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get agent by ID
|
|
68
|
+
* @param {string} id Agent ID
|
|
69
|
+
* @returns {Object|null} Agent configuration or null
|
|
70
|
+
*/
|
|
71
|
+
export function getAgentById(id) {
|
|
72
|
+
return SUPPORTED_AGENTS.find(agent => agent.id === id) || null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get all supported agent IDs
|
|
77
|
+
* @returns {Array<string>} List of agent IDs
|
|
78
|
+
*/
|
|
79
|
+
export function getSupportedAgentIds() {
|
|
80
|
+
return SUPPORTED_AGENTS.map(agent => agent.id);
|
|
81
|
+
}
|
package/src/ascii.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
// Clean capital ORCHESTRA
|
|
4
|
+
const logo = `
|
|
5
|
+
|
|
6
|
+
██████╗ ██████╗ ██████╗ ██╗ ██╗ ███████╗ ███████╗ ████████╗ ██████╗ █████╗
|
|
7
|
+
██╔═══██╗██╔══██╗██╔════╝ ██║ ██║ ██╔════╝ ██╔════╝ ╚══██╔══╝ ██╔══██╗ ██╔══██╗
|
|
8
|
+
██║ ██║██████╔╝██║ ███████║ █████╗ ███████╗ ██║ ██████╔╝ ███████║
|
|
9
|
+
██║ ██║██╔══██╗██║ ██╔══██║ ██╔══╝ ╚════██║ ██║ ██╔══██╗ ██╔══██║
|
|
10
|
+
╚██████╔╝██║ ██║╚██████╗ ██║ ██║ ███████╗ ███████║ ██║ ██║ ██║ ██║ ██║
|
|
11
|
+
╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
|
12
|
+
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Welcome screen
|
|
17
|
+
*/
|
|
18
|
+
export function showWelcome(skillCount = 82, categoryCount = 20, agentCount = 5) {
|
|
19
|
+
console.clear();
|
|
20
|
+
console.log(chalk.white(logo));
|
|
21
|
+
console.log();
|
|
22
|
+
console.log(chalk.bold.white(' AI Research Skills'));
|
|
23
|
+
console.log();
|
|
24
|
+
console.log();
|
|
25
|
+
console.log(chalk.dim(' Expert-level knowledge for AI research engineering'));
|
|
26
|
+
console.log();
|
|
27
|
+
console.log();
|
|
28
|
+
console.log(` ${skillCount} skills · ${categoryCount} categories · ${agentCount} agents`);
|
|
29
|
+
console.log();
|
|
30
|
+
console.log();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Agents detected screen
|
|
35
|
+
*/
|
|
36
|
+
export function showAgentsDetected(agents) {
|
|
37
|
+
console.clear();
|
|
38
|
+
console.log(chalk.white(logo));
|
|
39
|
+
console.log();
|
|
40
|
+
console.log(chalk.bold.white(' AI Research Skills'));
|
|
41
|
+
console.log();
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(chalk.green(` ✓ Found ${agents.length} coding agent${agents.length !== 1 ? 's' : ''}`));
|
|
44
|
+
console.log();
|
|
45
|
+
|
|
46
|
+
for (const agent of agents) {
|
|
47
|
+
console.log(` ${chalk.green('●')} ${chalk.white(agent.name.padEnd(14))} ${chalk.dim(agent.path)}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log();
|
|
51
|
+
console.log();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Menu header for inner screens
|
|
56
|
+
*/
|
|
57
|
+
export function showMenuHeader() {
|
|
58
|
+
console.clear();
|
|
59
|
+
console.log();
|
|
60
|
+
console.log(chalk.dim(' ────────────────────────────────────────────────────────────'));
|
|
61
|
+
console.log(chalk.white(' ORCHESTRA · AI Research Skills'));
|
|
62
|
+
console.log(chalk.dim(' ────────────────────────────────────────────────────────────'));
|
|
63
|
+
console.log();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Success screen
|
|
68
|
+
*/
|
|
69
|
+
export function showSuccess(skillCount, agents) {
|
|
70
|
+
console.clear();
|
|
71
|
+
console.log();
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(chalk.green.bold(' ✓ Installation Complete'));
|
|
74
|
+
console.log();
|
|
75
|
+
console.log();
|
|
76
|
+
console.log(` Installed ${chalk.white(skillCount)} skills to ${chalk.white(agents.length)} agent${agents.length !== 1 ? 's' : ''}`);
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(chalk.dim(' Your skills are now active and will appear when relevant.'));
|
|
79
|
+
console.log();
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(chalk.dim(' ────────────────────────────────────────────────────────────'));
|
|
82
|
+
console.log();
|
|
83
|
+
console.log(chalk.white(' Examples:'));
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(chalk.dim(' → "Help me set up GRPO training with verl"'));
|
|
86
|
+
console.log(chalk.dim(' → "How do I serve a model with vLLM?"'));
|
|
87
|
+
console.log(chalk.dim(' → "Write a NeurIPS paper introduction"'));
|
|
88
|
+
console.log();
|
|
89
|
+
console.log(chalk.dim(' ────────────────────────────────────────────────────────────'));
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(chalk.white(' Commands:'));
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(` ${chalk.dim('$')} ${chalk.cyan('npx @orchestra-research/ai-research-skills')}`);
|
|
94
|
+
console.log(` ${chalk.dim('$')} ${chalk.cyan('npx @orchestra-research/ai-research-skills list')}`);
|
|
95
|
+
console.log(` ${chalk.dim('$')} ${chalk.cyan('npx @orchestra-research/ai-research-skills update')}`);
|
|
96
|
+
console.log();
|
|
97
|
+
console.log(chalk.dim(' ────────────────────────────────────────────────────────────'));
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(chalk.dim(' github.com/orchestra-research/ai-research-skills'));
|
|
100
|
+
console.log();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* No agents found screen
|
|
105
|
+
*/
|
|
106
|
+
export function showNoAgents() {
|
|
107
|
+
console.clear();
|
|
108
|
+
console.log(chalk.white(logo));
|
|
109
|
+
console.log();
|
|
110
|
+
console.log(chalk.bold.white(' AI Research Skills'));
|
|
111
|
+
console.log();
|
|
112
|
+
console.log();
|
|
113
|
+
console.log(chalk.yellow(' ⚠ No coding agents detected'));
|
|
114
|
+
console.log();
|
|
115
|
+
console.log(chalk.dim(' Install one of these supported agents:'));
|
|
116
|
+
console.log();
|
|
117
|
+
console.log(' ○ Claude Code');
|
|
118
|
+
console.log(' ○ Cursor');
|
|
119
|
+
console.log(' ○ Codex (OpenAI)');
|
|
120
|
+
console.log(' ○ Windsurf');
|
|
121
|
+
console.log(' ○ Gemini CLI');
|
|
122
|
+
console.log(' ○ Kilo Code');
|
|
123
|
+
console.log(' ○ Qwen Code');
|
|
124
|
+
console.log();
|
|
125
|
+
console.log();
|
|
126
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
import { detectAgents } from './agents.js';
|
|
5
|
+
import { showWelcome, showAgentsDetected, showSuccess, showNoAgents, showMenuHeader } from './ascii.js';
|
|
6
|
+
import {
|
|
7
|
+
askInstallChoice,
|
|
8
|
+
askCategories,
|
|
9
|
+
askIndividualSkills,
|
|
10
|
+
askConfirmation,
|
|
11
|
+
askMainMenuAction,
|
|
12
|
+
askSelectAgents,
|
|
13
|
+
askAfterAction,
|
|
14
|
+
parseArgs,
|
|
15
|
+
CATEGORIES,
|
|
16
|
+
INDIVIDUAL_SKILLS,
|
|
17
|
+
QUICK_START_SKILLS,
|
|
18
|
+
getTotalSkillCount,
|
|
19
|
+
} from './prompts.js';
|
|
20
|
+
import { installSkills, installSpecificSkills, listInstalledSkills, getAllCategoryIds } from './installer.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Sleep utility
|
|
24
|
+
*/
|
|
25
|
+
function sleep(ms) {
|
|
26
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Interactive flow - the main guided experience with navigation
|
|
31
|
+
*/
|
|
32
|
+
async function interactiveFlow() {
|
|
33
|
+
let agents = [];
|
|
34
|
+
|
|
35
|
+
// STEP 1: Welcome + Agent Detection
|
|
36
|
+
showWelcome();
|
|
37
|
+
const spinner = ora({
|
|
38
|
+
text: chalk.cyan('Detecting coding agents...'),
|
|
39
|
+
spinner: 'dots',
|
|
40
|
+
prefixText: ' ',
|
|
41
|
+
}).start();
|
|
42
|
+
|
|
43
|
+
await sleep(1200);
|
|
44
|
+
agents = detectAgents();
|
|
45
|
+
spinner.stop();
|
|
46
|
+
|
|
47
|
+
if (agents.length === 0) {
|
|
48
|
+
showNoAgents();
|
|
49
|
+
console.log(chalk.yellow(' Please install a supported coding agent first.'));
|
|
50
|
+
console.log();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// STEP 2: Show detected agents + main menu
|
|
55
|
+
step2_menu:
|
|
56
|
+
while (true) {
|
|
57
|
+
showAgentsDetected(agents);
|
|
58
|
+
const menuAction = await askMainMenuAction();
|
|
59
|
+
|
|
60
|
+
if (menuAction === 'exit') {
|
|
61
|
+
console.log(chalk.dim(' Goodbye!'));
|
|
62
|
+
console.log();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (menuAction === 'view') {
|
|
67
|
+
// View installed skills
|
|
68
|
+
showMenuHeader();
|
|
69
|
+
listInstalledSkills();
|
|
70
|
+
const afterView = await askAfterAction();
|
|
71
|
+
if (afterView === 'exit') {
|
|
72
|
+
console.log(chalk.dim(' Goodbye!'));
|
|
73
|
+
console.log();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
continue step2_menu;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (menuAction === 'update') {
|
|
80
|
+
// Update all skills
|
|
81
|
+
showMenuHeader();
|
|
82
|
+
console.log(chalk.cyan(' Updating all skills...'));
|
|
83
|
+
console.log();
|
|
84
|
+
const categories = getAllCategoryIds();
|
|
85
|
+
await installSkills(categories, agents);
|
|
86
|
+
console.log();
|
|
87
|
+
console.log(chalk.green(' ✓ All skills updated!'));
|
|
88
|
+
const afterUpdate = await askAfterAction();
|
|
89
|
+
if (afterUpdate === 'exit') {
|
|
90
|
+
console.log(chalk.dim(' Goodbye!'));
|
|
91
|
+
console.log();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
continue step2_menu;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// STEP 3: Choose what to install (menuAction === 'install')
|
|
98
|
+
step3_choice:
|
|
99
|
+
while (true) {
|
|
100
|
+
showMenuHeader();
|
|
101
|
+
const choice = await askInstallChoice();
|
|
102
|
+
|
|
103
|
+
if (choice === 'back') {
|
|
104
|
+
continue step2_menu;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let categories = [];
|
|
108
|
+
let selectedSkills = [];
|
|
109
|
+
let skillCount = 0;
|
|
110
|
+
let installType = choice;
|
|
111
|
+
|
|
112
|
+
// Handle different choices
|
|
113
|
+
if (choice === 'everything') {
|
|
114
|
+
categories = getAllCategoryIds();
|
|
115
|
+
skillCount = getTotalSkillCount();
|
|
116
|
+
} else if (choice === 'quickstart') {
|
|
117
|
+
categories = [...new Set(QUICK_START_SKILLS.map(s => s.split('/')[0]))];
|
|
118
|
+
skillCount = QUICK_START_SKILLS.length;
|
|
119
|
+
} else if (choice === 'categories') {
|
|
120
|
+
// Category selection
|
|
121
|
+
step4_categories:
|
|
122
|
+
while (true) {
|
|
123
|
+
showMenuHeader();
|
|
124
|
+
const result = await askCategories();
|
|
125
|
+
|
|
126
|
+
if (result.action === 'back') {
|
|
127
|
+
continue step3_choice;
|
|
128
|
+
}
|
|
129
|
+
if (result.action === 'retry') {
|
|
130
|
+
continue step4_categories;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
categories = result.categories;
|
|
134
|
+
skillCount = CATEGORIES
|
|
135
|
+
.filter(c => categories.includes(c.id))
|
|
136
|
+
.reduce((sum, c) => sum + c.skills, 0);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
} else if (choice === 'individual') {
|
|
140
|
+
// Individual skill selection
|
|
141
|
+
step4_individual:
|
|
142
|
+
while (true) {
|
|
143
|
+
showMenuHeader();
|
|
144
|
+
const result = await askIndividualSkills();
|
|
145
|
+
|
|
146
|
+
if (result.action === 'back') {
|
|
147
|
+
continue step3_choice;
|
|
148
|
+
}
|
|
149
|
+
if (result.action === 'retry') {
|
|
150
|
+
continue step4_individual;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
selectedSkills = result.skills;
|
|
154
|
+
skillCount = selectedSkills.length;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// STEP 5: Select agents + Confirmation
|
|
160
|
+
let targetAgents = agents;
|
|
161
|
+
step5_agents:
|
|
162
|
+
while (true) {
|
|
163
|
+
showMenuHeader();
|
|
164
|
+
const agentResult = await askSelectAgents(agents);
|
|
165
|
+
|
|
166
|
+
if (agentResult.action === 'back') {
|
|
167
|
+
continue step3_choice;
|
|
168
|
+
}
|
|
169
|
+
if (agentResult.action === 'retry') {
|
|
170
|
+
continue step5_agents;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
targetAgents = agentResult.agents;
|
|
174
|
+
|
|
175
|
+
// STEP 6: Confirmation
|
|
176
|
+
showMenuHeader();
|
|
177
|
+
const confirmAction = await askConfirmation(skillCount, targetAgents, categories, selectedSkills, installType);
|
|
178
|
+
|
|
179
|
+
if (confirmAction === 'exit') {
|
|
180
|
+
console.log(chalk.dim(' Goodbye!'));
|
|
181
|
+
console.log();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (confirmAction === 'back') {
|
|
185
|
+
continue step5_agents;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// STEP 7: Installation
|
|
192
|
+
console.log();
|
|
193
|
+
console.log(chalk.cyan(' Installing...'));
|
|
194
|
+
console.log();
|
|
195
|
+
|
|
196
|
+
let installedCount;
|
|
197
|
+
if (selectedSkills.length > 0) {
|
|
198
|
+
// Install specific skills
|
|
199
|
+
installedCount = await installSpecificSkills(selectedSkills, targetAgents);
|
|
200
|
+
} else {
|
|
201
|
+
// Install by categories
|
|
202
|
+
installedCount = await installSkills(categories, targetAgents);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// STEP 8: Success!
|
|
206
|
+
await sleep(500);
|
|
207
|
+
showSuccess(installedCount, targetAgents);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Direct command mode (for power users)
|
|
215
|
+
*/
|
|
216
|
+
async function commandMode(options) {
|
|
217
|
+
if (options.command === 'list') {
|
|
218
|
+
listInstalledSkills();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (options.command === 'update') {
|
|
223
|
+
console.log(chalk.cyan('Updating skills...'));
|
|
224
|
+
const agents = detectAgents();
|
|
225
|
+
if (agents.length === 0) {
|
|
226
|
+
console.log(chalk.yellow('No agents detected.'));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const categories = getAllCategoryIds();
|
|
230
|
+
await installSkills(categories, agents);
|
|
231
|
+
console.log(chalk.green('✓ Skills updated!'));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (options.command === 'install' || options.all || options.category || options.skill) {
|
|
236
|
+
const agents = detectAgents();
|
|
237
|
+
if (agents.length === 0) {
|
|
238
|
+
console.log(chalk.yellow('No agents detected.'));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let categories;
|
|
243
|
+
if (options.all) {
|
|
244
|
+
categories = getAllCategoryIds();
|
|
245
|
+
} else if (options.category) {
|
|
246
|
+
categories = [options.category];
|
|
247
|
+
} else if (options.skill) {
|
|
248
|
+
const matchingCategory = CATEGORIES.find(c =>
|
|
249
|
+
c.id.includes(options.skill) || c.name.toLowerCase().includes(options.skill.toLowerCase())
|
|
250
|
+
);
|
|
251
|
+
if (matchingCategory) {
|
|
252
|
+
categories = [matchingCategory.id];
|
|
253
|
+
} else {
|
|
254
|
+
console.log(chalk.yellow(`Category or skill "${options.skill}" not found.`));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
categories = getAllCategoryIds();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
console.log(chalk.cyan('Installing skills...'));
|
|
262
|
+
await installSkills(categories, agents);
|
|
263
|
+
console.log(chalk.green('✓ Done!'));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Main entry point
|
|
270
|
+
*/
|
|
271
|
+
export async function main() {
|
|
272
|
+
const args = process.argv.slice(2);
|
|
273
|
+
const options = parseArgs(args);
|
|
274
|
+
|
|
275
|
+
// If any command-line options provided, use command mode
|
|
276
|
+
if (options.command || options.all || options.category || options.skill) {
|
|
277
|
+
await commandMode(options);
|
|
278
|
+
} else {
|
|
279
|
+
// Otherwise, use interactive flow
|
|
280
|
+
await interactiveFlow();
|
|
281
|
+
}
|
|
282
|
+
}
|