symfonia-ai-tools 1.8.0 → 1.9.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 CHANGED
@@ -19,21 +19,33 @@ symfonia-ai-tools
19
19
 
20
20
  The configurator guides you through:
21
21
  1. Language selection (Polish / English)
22
- 2. Project type, description, tech stack
23
- 3. Instruction & skill packs (checkboxes)
24
- 4. AI tools to configure (checkboxes)
25
- 5. Skills to install (checkboxes — base + from selected packs)
26
- 6. Paths, commands, CI pipeline, JIRA prefix
27
- 7. MCP servers (checkboxes + tokens)
28
- 8. CLI installation (checkboxes)
22
+ 2. **Install scope** choose what to install
23
+ 3. Project type, description, tech stack *(full setup only)*
24
+ 4. Instruction & skill packs (checkboxes)
25
+ 5. AI tools to configure (checkboxes)
26
+ 6. Skills to install (checkboxes base + from selected packs)
27
+ 7. Paths, commands, CI pipeline, JIRA prefix *(full setup only)*
28
+ 8. MCP servers (checkboxes + tokens)
29
+ 9. CLI installation (checkboxes) *(full setup only)*
29
30
 
30
31
  The entire configurator uses arrow-key navigation — no typing numbers.
31
32
 
32
- Finally, it automatically runs GSD:
33
+ Finally (full setup only), it automatically runs GSD:
33
34
  - **New project** → `/gsd-new-project`
34
35
  - **Existing project** → `/gsd-map-codebase` → `/gsd-new-project`
35
36
 
36
- ### Installation modes (existing project)
37
+ ### Install scopes
38
+
39
+ | Scope | What it installs | Use case |
40
+ |-------|-----------------|----------|
41
+ | **Full setup** | Everything — files, skills, MCP, CLI, GSD bootstrap | First-time setup or full reinstall |
42
+ | **Skills only** | Selected skills → `.ai/skills/` + mirrors | Add new skills to existing project |
43
+ | **MCP only** | MCP server configuration | Add/update MCP servers |
44
+ | **Skills + MCP** | Skills and MCP servers | Add skills and MCP in one go |
45
+
46
+ Slim scopes (skills only, MCP only, skills + MCP) skip project metadata, commands, CI, JIRA, and CLI installation — they only ask for what's needed.
47
+
48
+ ### Installation modes (existing project, full setup)
37
49
 
38
50
  | Mode | Description |
39
51
  |------|-------------|
package/lib/i18n.mjs CHANGED
@@ -32,6 +32,15 @@ const translations = {
32
32
  'q.quit_hint': 'Wpisz',
33
33
  'q.quit_hint2': 'aby przerwac w dowolnym momencie.',
34
34
 
35
+ // questions.mjs — install scope
36
+ 'q.section.scope': 'Zakres instalacji',
37
+ 'q.scope.select': 'Co chcesz zainstalowac?',
38
+ 'q.scope.full': 'Pelny setup',
39
+ 'q.scope.full_hint': '(pliki, skille, MCP, CLI)',
40
+ 'q.scope.skills_only': 'Tylko skille',
41
+ 'q.scope.mcp_only': 'Tylko serwery MCP',
42
+ 'q.scope.skills_mcp': 'Skille + MCP',
43
+
35
44
  // questions.mjs — project
36
45
  'q.section.project': 'Projekt',
37
46
  'q.project_type': 'Typ projektu:',
@@ -143,12 +152,16 @@ const translations = {
143
152
  'i.mode.overwrite': 'nadpisz wszystko',
144
153
  'i.mode.skip': 'tylko nowe pliki',
145
154
  'i.mode.mcp': 'tylko MCP',
155
+ 'i.mode.skills': 'tylko skille',
156
+ 'i.mode.skills_mcp': 'skille + MCP',
146
157
  'i.dir': 'Katalog:',
147
158
  'i.mode_label': 'Tryb:',
148
159
  'i.step.base': 'Szablony bazowe',
149
160
  'i.step.pack': 'Pakiet',
150
161
  'i.step.guidelines': 'Skladanie',
151
162
  'i.step.mirror': 'Mirror',
163
+ 'i.step.skills': 'Kopiowanie skilli',
164
+ 'i.step.skills_mirror': 'Mirror skilli',
152
165
  'i.step.mcp': 'Konfiguracja MCP',
153
166
  'i.step.cli': 'Instalacja CLI',
154
167
 
@@ -170,6 +183,8 @@ const translations = {
170
183
 
171
184
  // installer.mjs — next steps
172
185
  'i.done.mcp': 'Konfiguracja MCP zakonczona!',
186
+ 'i.done.skills': 'Instalacja skilli zakonczona!',
187
+ 'i.done.skills_mcp': 'Instalacja skilli i MCP zakonczona!',
173
188
  'i.done.install': 'Instalacja zakonczona!',
174
189
  'i.done.check_mcp': 'Sprawdz MCP:',
175
190
  'i.done.install_gsd': 'Zainstaluj GSD',
@@ -213,6 +228,15 @@ const translations = {
213
228
  'q.quit_hint': 'Type',
214
229
  'q.quit_hint2': 'to abort at any time.',
215
230
 
231
+ // questions.mjs — install scope
232
+ 'q.section.scope': 'Installation scope',
233
+ 'q.scope.select': 'What do you want to install?',
234
+ 'q.scope.full': 'Full setup',
235
+ 'q.scope.full_hint': '(files, skills, MCP, CLI)',
236
+ 'q.scope.skills_only': 'Skills only',
237
+ 'q.scope.mcp_only': 'MCP servers only',
238
+ 'q.scope.skills_mcp': 'Skills + MCP',
239
+
216
240
  // questions.mjs — project
217
241
  'q.section.project': 'Project',
218
242
  'q.project_type': 'Project type:',
@@ -324,12 +348,16 @@ const translations = {
324
348
  'i.mode.overwrite': 'overwrite all',
325
349
  'i.mode.skip': 'new files only',
326
350
  'i.mode.mcp': 'MCP only',
351
+ 'i.mode.skills': 'skills only',
352
+ 'i.mode.skills_mcp': 'skills + MCP',
327
353
  'i.dir': 'Directory:',
328
354
  'i.mode_label': 'Mode:',
329
355
  'i.step.base': 'Base templates',
330
356
  'i.step.pack': 'Pack',
331
357
  'i.step.guidelines': 'Assembling',
332
358
  'i.step.mirror': 'Mirror',
359
+ 'i.step.skills': 'Copying skills',
360
+ 'i.step.skills_mirror': 'Mirroring skills',
333
361
  'i.step.mcp': 'MCP configuration',
334
362
  'i.step.cli': 'CLI installation',
335
363
 
@@ -351,6 +379,8 @@ const translations = {
351
379
 
352
380
  // installer.mjs — next steps
353
381
  'i.done.mcp': 'MCP configuration complete!',
382
+ 'i.done.skills': 'Skills installation complete!',
383
+ 'i.done.skills_mcp': 'Skills & MCP installation complete!',
354
384
  'i.done.install': 'Installation complete!',
355
385
  'i.done.check_mcp': 'Check MCP:',
356
386
  'i.done.install_gsd': 'Install GSD',
package/lib/installer.mjs CHANGED
@@ -116,6 +116,12 @@ export async function install(packageRoot, answers) {
116
116
  const templatesDir = join(packageRoot, 'templates');
117
117
  const mode = answers.installMode || 'fresh';
118
118
 
119
+ // Handle slim install scopes (skills-only, mcp-only, skills+mcp)
120
+ const installScope = answers.installScope || 'full';
121
+ if (installScope !== 'full') {
122
+ return await installSlim(targetDir, templatesDir, answers, installScope);
123
+ }
124
+
119
125
  const modeLabel = mode === 'fresh' ? boldGreen(t('i.mode.fresh'))
120
126
  : mode === 'overwrite' ? boldYellow(t('i.mode.overwrite'))
121
127
  : mode === 'skip-existing' ? boldCyan(t('i.mode.skip'))
@@ -183,6 +189,100 @@ export async function install(packageRoot, answers) {
183
189
  }
184
190
  }
185
191
 
192
+ // ─── Slim install (skills-only, mcp-only, skills+mcp) ───
193
+
194
+ async function installSlim(targetDir, templatesDir, answers, scope) {
195
+ const needsSkills = scope !== 'mcp-only';
196
+ const needsMcp = scope !== 'skills-only';
197
+ const needsMirror = needsSkills && (answers.toolCopilot || answers.toolClaude);
198
+
199
+ const totalSteps = (needsSkills ? 1 : 0) + (needsMirror ? 1 : 0) + (needsMcp ? 1 : 0);
200
+ let currentStep = 0;
201
+
202
+ const modeLabel = scope === 'skills-only' ? boldCyan(t('i.mode.skills'))
203
+ : scope === 'mcp-only' ? boldCyan(t('i.mode.mcp'))
204
+ : boldCyan(t('i.mode.skills_mcp'));
205
+
206
+ section(t('i.section.install'));
207
+ console.log(info(`${t('i.dir')} ${bold(targetDir)}`));
208
+ console.log(info(`${t('i.mode_label')} ${modeLabel}`));
209
+ console.log('');
210
+
211
+ if (needsSkills) {
212
+ step(++currentStep, totalSteps, t('i.step.skills'));
213
+ await installSkills(templatesDir, targetDir, answers);
214
+
215
+ if (needsMirror) {
216
+ step(++currentStep, totalSteps, t('i.step.skills_mirror'));
217
+ const aiSkillsDir = join(targetDir, '.ai', 'skills');
218
+ if (answers.toolCopilot) {
219
+ await mirrorDir(aiSkillsDir, join(targetDir, '.github', 'skills'), targetDir, 'overwrite');
220
+ }
221
+ if (answers.toolClaude) {
222
+ await mirrorDir(aiSkillsDir, join(targetDir, '.claude', 'skills'), targetDir, 'overwrite');
223
+ }
224
+ }
225
+ }
226
+
227
+ if (needsMcp) {
228
+ step(++currentStep, totalSteps, t('i.step.mcp'));
229
+ await generateMcpConfig(targetDir, answers);
230
+ }
231
+
232
+ console.log('');
233
+ const doneKey = scope === 'skills-only' ? 'i.done.skills'
234
+ : scope === 'mcp-only' ? 'i.done.mcp'
235
+ : 'i.done.skills_mcp';
236
+ box([boldGreen(` ${t(doneKey)}`)], boldGreen);
237
+ console.log('');
238
+
239
+ if (needsMcp && answers.toolClaude) {
240
+ console.log(info(`${t('i.done.check_mcp')} ${cyan('claude mcp list')}`));
241
+ }
242
+ }
243
+
244
+ async function installSkills(templatesDir, targetDir, answers) {
245
+ const selectedSkills = answers.selectedSkills || [];
246
+ if (selectedSkills.length === 0) {
247
+ console.log(` ${dim(t('q.skills.none'))}`);
248
+ return;
249
+ }
250
+
251
+ const aiSkillsDir = join(targetDir, '.ai', 'skills');
252
+ await mkdir(aiSkillsDir, { recursive: true });
253
+
254
+ // Base skills
255
+ const baseSkillsDir = join(templatesDir, 'base', '_ai', 'skills');
256
+ try {
257
+ const entries = await readdir(baseSkillsDir, { withFileTypes: true });
258
+ for (const e of entries) {
259
+ if (e.isDirectory() && selectedSkills.includes(e.name)) {
260
+ const dest = join(aiSkillsDir, e.name);
261
+ await mkdir(dest, { recursive: true });
262
+ await copyTemplateDir(join(baseSkillsDir, e.name), dest, answers, 'overwrite');
263
+ }
264
+ }
265
+ } catch { /* no base skills */ }
266
+
267
+ // Pack skills
268
+ const allPacks = await loadPacks(join(templatesDir, 'packs'));
269
+ for (const packId of (answers.packs || [])) {
270
+ const pack = allPacks[packId];
271
+ if (!pack) continue;
272
+ const packSkillsDir = join(pack._dir, '_ai', 'skills');
273
+ try {
274
+ const entries = await readdir(packSkillsDir, { withFileTypes: true });
275
+ for (const e of entries) {
276
+ if (e.isDirectory() && selectedSkills.includes(e.name)) {
277
+ const dest = join(aiSkillsDir, e.name);
278
+ await mkdir(dest, { recursive: true });
279
+ await copyTemplateDir(join(packSkillsDir, e.name), dest, answers, 'overwrite');
280
+ }
281
+ }
282
+ } catch { /* no pack skills */ }
283
+ }
284
+ }
285
+
186
286
  // ─── Guidelines assembly ───
187
287
 
188
288
  async function assembleGuidelines(templatesDir, targetDir, answers, selectedPacks, allPacks, mode) {
package/lib/questions.mjs CHANGED
@@ -80,6 +80,25 @@ export async function askQuestions(packsDir) {
80
80
  console.log('');
81
81
  console.log(` ${dim(t('q.quit_hint'))} ${yellow('"q"')} ${dim(t('q.quit_hint2'))}`);
82
82
 
83
+ // --- Install scope ---
84
+ section(t('q.section.scope'));
85
+ answers.installScope = await askChoice(t('q.scope.select'), [
86
+ 'full',
87
+ 'skills-only',
88
+ 'mcp-only',
89
+ 'skills+mcp',
90
+ ], [
91
+ `${boldGreen(t('q.scope.full'))} ${dim(t('q.scope.full_hint'))}`,
92
+ `${boldCyan(t('q.scope.skills_only'))}`,
93
+ `${boldCyan(t('q.scope.mcp_only'))}`,
94
+ `${boldCyan(t('q.scope.skills_mcp'))}`,
95
+ ]);
96
+
97
+ // Slim flows — early return
98
+ if (answers.installScope !== 'full') {
99
+ return await askSlimFlow(answers, packsDir);
100
+ }
101
+
83
102
  // --- Project type ---
84
103
  section(t('q.section.project'));
85
104
 
@@ -494,3 +513,88 @@ function printSummary(answers, allPacks) {
494
513
  tableRow(t('q.summary.gsd'), cyan(gsdSteps.join(dim(' → '))));
495
514
  }
496
515
  }
516
+
517
+ // ─── Slim flow (skills-only, mcp-only, skills+mcp) ───
518
+
519
+ async function askSlimFlow(answers, packsDir) {
520
+ const scope = answers.installScope;
521
+ const needsSkills = scope !== 'mcp-only';
522
+ const needsMcp = scope !== 'skills-only';
523
+
524
+ // --- Target directory ---
525
+ answers.targetDir = await ask(t('q.target_dir'), '.');
526
+ answers.installMode = 'overwrite';
527
+
528
+ // --- Tool selection ---
529
+ await askToolSelection(answers);
530
+
531
+ // --- Skills flow ---
532
+ let allPacks = {};
533
+ if (needsSkills) {
534
+ allPacks = await loadPacks(packsDir);
535
+ await askPackSelection(answers, allPacks);
536
+ const baseSkillsDir = join(packsDir, '..', 'base', '_ai', 'skills');
537
+ await askSkillSelection(answers, allPacks, baseSkillsDir);
538
+ await askPackPlaceholders(answers, allPacks);
539
+ checkCliDeps(answers.selectedSkills || []);
540
+ } else {
541
+ answers.packs = [];
542
+ answers.selectedSkills = [];
543
+ }
544
+
545
+ // --- MCP flow ---
546
+ if (needsMcp) {
547
+ const requiredMcps = collectRequiredMcps(answers.selectedSkills || []);
548
+ await askMcpServers(answers, requiredMcps);
549
+ } else {
550
+ answers.mcpJira = false;
551
+ answers.mcpBitbucket = false;
552
+ answers.mcpFigma = false;
553
+ answers.mcpGrafana = false;
554
+ answers.mcpContext7 = false;
555
+ }
556
+
557
+ // --- Defaults for unused fields ---
558
+ answers.installClaudeCli = false;
559
+ answers.installGsd = false;
560
+
561
+ // --- Summary ---
562
+ printSlimSummary(answers, allPacks);
563
+
564
+ const proceed = await askYN(`\n ${t('q.summary.continue')}`, true);
565
+ if (!proceed) throw new Error('USER_ABORT');
566
+
567
+ return answers;
568
+ }
569
+
570
+ function printSlimSummary(answers, allPacks) {
571
+ section(t('q.section.summary'));
572
+
573
+ tableRow(t('q.summary.dir'), answers.targetDir);
574
+
575
+ const tools = [];
576
+ if (answers.toolClaude) tools.push('Claude');
577
+ if (answers.toolCopilot) tools.push('Copilot');
578
+ if (answers.toolCursor) tools.push('Cursor');
579
+ if (answers.toolGemini) tools.push('Gemini');
580
+ if (answers.toolJunie) tools.push('Junie');
581
+ tableRow(t('q.summary.tools'), tools.length > 0 ? cyan(tools.join(dim(' · '))) : dim(t('q.summary.none')));
582
+
583
+ if (answers.installScope !== 'mcp-only') {
584
+ const packNames = (answers.packs || []).map(id => allPacks[id]?.name || id);
585
+ tableRow(t('q.summary.packs'), packNames.length > 0 ? cyan(packNames.join(dim(' · '))) : dim(t('q.summary.none')));
586
+
587
+ const skills = answers.selectedSkills || [];
588
+ tableRow(t('q.summary.skills'), skills.length > 0 ? cyan(skills.join(dim(' · '))) : dim(t('q.summary.none')));
589
+ }
590
+
591
+ if (answers.installScope !== 'skills-only') {
592
+ const mcps = [];
593
+ if (answers.mcpJira) mcps.push('Jira');
594
+ if (answers.mcpBitbucket) mcps.push('Bitbucket');
595
+ if (answers.mcpFigma) mcps.push('Figma');
596
+ if (answers.mcpGrafana) mcps.push('Grafana');
597
+ if (answers.mcpContext7) mcps.push('Context7');
598
+ tableRow(t('q.summary.mcp'), mcps.length > 0 ? cyan(mcps.join(dim(' · '))) : dim(t('q.summary.none')));
599
+ }
600
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "symfonia-ai-tools",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "AI tooling setup for your project - Claude Code, GitHub Copilot, Cursor, Gemini, Junie, GSD",
5
5
  "type": "module",
6
6
  "bin": {