@synsci/cli 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 ADDED
@@ -0,0 +1,39 @@
1
+ # @synsci/cli
2
+
3
+ Synthetic Sciences CLI - AI coding agent for machine learning engineers.
4
+
5
+ > **Note**: This is a private package. Access requires a Synthetic Sciences subscription.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g @synsci/cli
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ synsc
17
+ ```
18
+
19
+ ## Features
20
+
21
+ - **82 expert ML skills** built-in (GRPO, vLLM, DeepSpeed, Axolotl, etc.)
22
+ - **Native cloud integrations** (HuggingFace, W&B, Modal, Lambda Labs)
23
+ - **Tokens included** in your subscription
24
+ - **Model selection** (Claude 4.5, GPT-5.2, Gemini 3)
25
+
26
+ ## Subscription
27
+
28
+ Visit [syntheticsciences.com](https://syntheticsciences.com) to subscribe.
29
+
30
+ | Plan | Price | Rate Limits |
31
+ |------|-------|-------------|
32
+ | Pro | $50/mo | ~1,000 requests/day |
33
+ | Pro+ | $200/mo | ~5,000 requests/day |
34
+ | Scale | $500/mo | ~20,000 requests/day |
35
+ | Enterprise | Custom | Unlimited |
36
+
37
+ ## License
38
+
39
+ UNLICENSED - Synthetic Sciences
package/bin/cli.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from '../src/index.js';
4
+
5
+ main().catch((error) => {
6
+ console.error('Error:', error.message);
7
+ process.exit(1);
8
+ });
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@synsci/cli",
3
+ "version": "1.0.0",
4
+ "description": "Synthetic Sciences CLI - AI coding agent for machine learning engineers",
5
+ "publishConfig": {
6
+ "access": "restricted"
7
+ },
8
+ "main": "src/index.js",
9
+ "bin": {
10
+ "synsc": "./bin/cli.js"
11
+ },
12
+ "type": "module",
13
+ "scripts": {
14
+ "start": "node bin/cli.js",
15
+ "test": "node --test"
16
+ },
17
+ "keywords": [
18
+ "ai",
19
+ "ml",
20
+ "machine-learning",
21
+ "deep-learning",
22
+ "cli",
23
+ "coding-agent",
24
+ "synthetic-sciences"
25
+ ],
26
+ "author": "Synthetic Sciences",
27
+ "license": "UNLICENSED",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/inkvell/synsc-cli.git"
31
+ },
32
+ "homepage": "https://syntheticsciences.com",
33
+ "bugs": {
34
+ "url": "https://github.com/inkvell/synsc-cli/issues"
35
+ },
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "dependencies": {
40
+ "chalk": "^5.3.0",
41
+ "inquirer": "^9.2.12",
42
+ "ora": "^8.0.1"
43
+ }
44
+ }
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 @syntheticsciences/ai-research-skills')}`);
94
+ console.log(` ${chalk.dim('$')} ${chalk.cyan('npx @syntheticsciences/ai-research-skills list')}`);
95
+ console.log(` ${chalk.dim('$')} ${chalk.cyan('npx @syntheticsciences/ai-research-skills update')}`);
96
+ console.log();
97
+ console.log(chalk.dim(' ────────────────────────────────────────────────────────────'));
98
+ console.log();
99
+ console.log(chalk.dim(' github.com/syntheticsciences/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,358 @@
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
+ askUninstallChoice,
15
+ askSelectSkillsToUninstall,
16
+ askConfirmUninstall,
17
+ parseArgs,
18
+ CATEGORIES,
19
+ INDIVIDUAL_SKILLS,
20
+ QUICK_START_SKILLS,
21
+ getTotalSkillCount,
22
+ } from './prompts.js';
23
+ import { installSkills, installSpecificSkills, listInstalledSkills, getAllCategoryIds, updateInstalledSkills, uninstallAllSkills, uninstallSpecificSkills, getInstalledSkillPaths, getInstalledSkillsForSelection } from './installer.js';
24
+
25
+ /**
26
+ * Sleep utility
27
+ */
28
+ function sleep(ms) {
29
+ return new Promise(resolve => setTimeout(resolve, ms));
30
+ }
31
+
32
+ /**
33
+ * Interactive flow - the main guided experience with navigation
34
+ */
35
+ async function interactiveFlow() {
36
+ let agents = [];
37
+
38
+ // STEP 1: Welcome + Agent Detection
39
+ showWelcome();
40
+ const spinner = ora({
41
+ text: chalk.cyan('Detecting coding agents...'),
42
+ spinner: 'dots',
43
+ prefixText: ' ',
44
+ }).start();
45
+
46
+ await sleep(1200);
47
+ agents = detectAgents();
48
+ spinner.stop();
49
+
50
+ if (agents.length === 0) {
51
+ showNoAgents();
52
+ console.log(chalk.yellow(' Please install a supported coding agent first.'));
53
+ console.log();
54
+ return;
55
+ }
56
+
57
+ // STEP 2: Show detected agents + main menu
58
+ step2_menu:
59
+ while (true) {
60
+ showAgentsDetected(agents);
61
+ const menuAction = await askMainMenuAction();
62
+
63
+ if (menuAction === 'exit') {
64
+ console.log(chalk.dim(' Goodbye!'));
65
+ console.log();
66
+ return;
67
+ }
68
+
69
+ if (menuAction === 'view') {
70
+ // View installed skills
71
+ showMenuHeader();
72
+ listInstalledSkills();
73
+ const afterView = await askAfterAction();
74
+ if (afterView === 'exit') {
75
+ console.log(chalk.dim(' Goodbye!'));
76
+ console.log();
77
+ return;
78
+ }
79
+ continue step2_menu;
80
+ }
81
+
82
+ if (menuAction === 'update') {
83
+ // Update only installed skills
84
+ showMenuHeader();
85
+ const installedPaths = getInstalledSkillPaths();
86
+ if (installedPaths.length === 0) {
87
+ console.log(chalk.yellow(' No skills installed to update.'));
88
+ console.log();
89
+ console.log(chalk.dim(' Install some skills first.'));
90
+ } else {
91
+ console.log(chalk.cyan(` Updating ${installedPaths.length} installed skills...`));
92
+ console.log();
93
+ await updateInstalledSkills(agents);
94
+ console.log();
95
+ console.log(chalk.green(' ✓ All installed skills updated!'));
96
+ }
97
+ const afterUpdate = await askAfterAction();
98
+ if (afterUpdate === 'exit') {
99
+ console.log(chalk.dim(' Goodbye!'));
100
+ console.log();
101
+ return;
102
+ }
103
+ continue step2_menu;
104
+ }
105
+
106
+ if (menuAction === 'uninstall') {
107
+ // Uninstall skills
108
+ step_uninstall:
109
+ while (true) {
110
+ showMenuHeader();
111
+ const installedSkills = getInstalledSkillsForSelection();
112
+
113
+ if (installedSkills.length === 0) {
114
+ console.log(chalk.yellow(' No skills installed to uninstall.'));
115
+ break;
116
+ }
117
+
118
+ const uninstallChoice = await askUninstallChoice();
119
+
120
+ if (uninstallChoice === 'back') {
121
+ break;
122
+ }
123
+
124
+ if (uninstallChoice === 'all') {
125
+ // Uninstall everything
126
+ const confirmAction = await askConfirmUninstall(installedSkills.length);
127
+ if (confirmAction === 'confirm') {
128
+ console.log();
129
+ await uninstallAllSkills(agents);
130
+ console.log();
131
+ console.log(chalk.green(' ✓ All skills uninstalled!'));
132
+ }
133
+ break;
134
+ }
135
+
136
+ if (uninstallChoice === 'select') {
137
+ // Select specific skills to uninstall
138
+ showMenuHeader();
139
+ const result = await askSelectSkillsToUninstall(installedSkills);
140
+
141
+ if (result.action === 'back') {
142
+ continue step_uninstall;
143
+ }
144
+ if (result.action === 'retry') {
145
+ continue step_uninstall;
146
+ }
147
+
148
+ // Confirm uninstall
149
+ const confirmAction = await askConfirmUninstall(result.skills.length);
150
+ if (confirmAction === 'confirm') {
151
+ console.log();
152
+ await uninstallSpecificSkills(result.skills, agents);
153
+ console.log();
154
+ console.log(chalk.green(` ✓ ${result.skills.length} skill${result.skills.length !== 1 ? 's' : ''} uninstalled!`));
155
+ }
156
+ break;
157
+ }
158
+ }
159
+
160
+ const afterUninstall = await askAfterAction();
161
+ if (afterUninstall === 'exit') {
162
+ console.log(chalk.dim(' Goodbye!'));
163
+ console.log();
164
+ return;
165
+ }
166
+ continue step2_menu;
167
+ }
168
+
169
+ // STEP 3: Choose what to install (menuAction === 'install')
170
+ step3_choice:
171
+ while (true) {
172
+ showMenuHeader();
173
+ const choice = await askInstallChoice();
174
+
175
+ if (choice === 'back') {
176
+ continue step2_menu;
177
+ }
178
+
179
+ let categories = [];
180
+ let selectedSkills = [];
181
+ let skillCount = 0;
182
+ let installType = choice;
183
+
184
+ // Handle different choices
185
+ if (choice === 'everything') {
186
+ categories = getAllCategoryIds();
187
+ skillCount = getTotalSkillCount();
188
+ } else if (choice === 'quickstart') {
189
+ categories = [...new Set(QUICK_START_SKILLS.map(s => s.split('/')[0]))];
190
+ skillCount = QUICK_START_SKILLS.length;
191
+ } else if (choice === 'categories') {
192
+ // Category selection
193
+ step4_categories:
194
+ while (true) {
195
+ showMenuHeader();
196
+ const result = await askCategories();
197
+
198
+ if (result.action === 'back') {
199
+ continue step3_choice;
200
+ }
201
+ if (result.action === 'retry') {
202
+ continue step4_categories;
203
+ }
204
+
205
+ categories = result.categories;
206
+ skillCount = CATEGORIES
207
+ .filter(c => categories.includes(c.id))
208
+ .reduce((sum, c) => sum + c.skills, 0);
209
+ break;
210
+ }
211
+ } else if (choice === 'individual') {
212
+ // Individual skill selection
213
+ step4_individual:
214
+ while (true) {
215
+ showMenuHeader();
216
+ const result = await askIndividualSkills();
217
+
218
+ if (result.action === 'back') {
219
+ continue step3_choice;
220
+ }
221
+ if (result.action === 'retry') {
222
+ continue step4_individual;
223
+ }
224
+
225
+ selectedSkills = result.skills;
226
+ skillCount = selectedSkills.length;
227
+ break;
228
+ }
229
+ }
230
+
231
+ // STEP 5: Select agents + Confirmation
232
+ let targetAgents = agents;
233
+ step5_agents:
234
+ while (true) {
235
+ showMenuHeader();
236
+ const agentResult = await askSelectAgents(agents);
237
+
238
+ if (agentResult.action === 'back') {
239
+ continue step3_choice;
240
+ }
241
+ if (agentResult.action === 'retry') {
242
+ continue step5_agents;
243
+ }
244
+
245
+ targetAgents = agentResult.agents;
246
+
247
+ // STEP 6: Confirmation
248
+ showMenuHeader();
249
+ const confirmAction = await askConfirmation(skillCount, targetAgents, categories, selectedSkills, installType);
250
+
251
+ if (confirmAction === 'exit') {
252
+ console.log(chalk.dim(' Goodbye!'));
253
+ console.log();
254
+ return;
255
+ }
256
+ if (confirmAction === 'back') {
257
+ continue step5_agents;
258
+ }
259
+
260
+ break;
261
+ }
262
+
263
+ // STEP 7: Installation
264
+ console.log();
265
+ console.log(chalk.cyan(' Installing...'));
266
+ console.log();
267
+
268
+ let installedCount;
269
+ if (selectedSkills.length > 0) {
270
+ // Install specific skills
271
+ installedCount = await installSpecificSkills(selectedSkills, targetAgents);
272
+ } else {
273
+ // Install by categories
274
+ installedCount = await installSkills(categories, targetAgents);
275
+ }
276
+
277
+ // STEP 8: Success!
278
+ await sleep(500);
279
+ showSuccess(installedCount, targetAgents);
280
+ return;
281
+ }
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Direct command mode (for power users)
287
+ */
288
+ async function commandMode(options) {
289
+ if (options.command === 'list') {
290
+ listInstalledSkills();
291
+ return;
292
+ }
293
+
294
+ if (options.command === 'update') {
295
+ const agents = detectAgents();
296
+ if (agents.length === 0) {
297
+ console.log(chalk.yellow('No agents detected.'));
298
+ return;
299
+ }
300
+ const installedPaths = getInstalledSkillPaths();
301
+ if (installedPaths.length === 0) {
302
+ console.log(chalk.yellow('No skills installed to update.'));
303
+ return;
304
+ }
305
+ console.log(chalk.cyan(`Updating ${installedPaths.length} installed skills...`));
306
+ await updateInstalledSkills(agents);
307
+ console.log(chalk.green('✓ Skills updated!'));
308
+ return;
309
+ }
310
+
311
+ if (options.command === 'install' || options.all || options.category || options.skill) {
312
+ const agents = detectAgents();
313
+ if (agents.length === 0) {
314
+ console.log(chalk.yellow('No agents detected.'));
315
+ return;
316
+ }
317
+
318
+ let categories;
319
+ if (options.all) {
320
+ categories = getAllCategoryIds();
321
+ } else if (options.category) {
322
+ categories = [options.category];
323
+ } else if (options.skill) {
324
+ const matchingCategory = CATEGORIES.find(c =>
325
+ c.id.includes(options.skill) || c.name.toLowerCase().includes(options.skill.toLowerCase())
326
+ );
327
+ if (matchingCategory) {
328
+ categories = [matchingCategory.id];
329
+ } else {
330
+ console.log(chalk.yellow(`Category or skill "${options.skill}" not found.`));
331
+ return;
332
+ }
333
+ } else {
334
+ categories = getAllCategoryIds();
335
+ }
336
+
337
+ console.log(chalk.cyan('Installing skills...'));
338
+ await installSkills(categories, agents);
339
+ console.log(chalk.green('✓ Done!'));
340
+ return;
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Main entry point
346
+ */
347
+ export async function main() {
348
+ const args = process.argv.slice(2);
349
+ const options = parseArgs(args);
350
+
351
+ // If any command-line options provided, use command mode
352
+ if (options.command || options.all || options.category || options.skill) {
353
+ await commandMode(options);
354
+ } else {
355
+ // Otherwise, use interactive flow
356
+ await interactiveFlow();
357
+ }
358
+ }