@dedesfr/prompter 0.8.22 → 0.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.
Files changed (102) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/cli/index.js +1 -1
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/init.d.ts +1 -7
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +32 -294
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.d.ts.map +1 -1
  9. package/dist/commands/update.js +17 -40
  10. package/dist/commands/update.js.map +1 -1
  11. package/dist/core/configurators/slash/antigravity.d.ts +2 -5
  12. package/dist/core/configurators/slash/antigravity.d.ts.map +1 -1
  13. package/dist/core/configurators/slash/antigravity.js +2 -57
  14. package/dist/core/configurators/slash/antigravity.js.map +1 -1
  15. package/dist/core/configurators/slash/base.d.ts +6 -18
  16. package/dist/core/configurators/slash/base.d.ts.map +1 -1
  17. package/dist/core/configurators/slash/base.js +8 -77
  18. package/dist/core/configurators/slash/base.js.map +1 -1
  19. package/dist/core/configurators/slash/claude.d.ts +2 -5
  20. package/dist/core/configurators/slash/claude.d.ts.map +1 -1
  21. package/dist/core/configurators/slash/claude.js +2 -57
  22. package/dist/core/configurators/slash/claude.js.map +1 -1
  23. package/dist/core/configurators/slash/codex.d.ts +2 -5
  24. package/dist/core/configurators/slash/codex.d.ts.map +1 -1
  25. package/dist/core/configurators/slash/codex.js +2 -57
  26. package/dist/core/configurators/slash/codex.js.map +1 -1
  27. package/dist/core/configurators/slash/droid.d.ts +2 -5
  28. package/dist/core/configurators/slash/droid.d.ts.map +1 -1
  29. package/dist/core/configurators/slash/droid.js +2 -32
  30. package/dist/core/configurators/slash/droid.js.map +1 -1
  31. package/dist/core/configurators/slash/forge.d.ts +2 -5
  32. package/dist/core/configurators/slash/forge.d.ts.map +1 -1
  33. package/dist/core/configurators/slash/forge.js +2 -32
  34. package/dist/core/configurators/slash/forge.js.map +1 -1
  35. package/dist/core/configurators/slash/github-copilot.d.ts +2 -7
  36. package/dist/core/configurators/slash/github-copilot.d.ts.map +1 -1
  37. package/dist/core/configurators/slash/github-copilot.js +2 -96
  38. package/dist/core/configurators/slash/github-copilot.js.map +1 -1
  39. package/dist/core/configurators/slash/index.d.ts +1 -1
  40. package/dist/core/configurators/slash/index.d.ts.map +1 -1
  41. package/dist/core/configurators/slash/index.js +1 -1
  42. package/dist/core/configurators/slash/index.js.map +1 -1
  43. package/dist/core/configurators/slash/kilocode.d.ts +2 -5
  44. package/dist/core/configurators/slash/kilocode.d.ts.map +1 -1
  45. package/dist/core/configurators/slash/kilocode.js +2 -57
  46. package/dist/core/configurators/slash/kilocode.js.map +1 -1
  47. package/dist/core/configurators/slash/opencode.d.ts +2 -5
  48. package/dist/core/configurators/slash/opencode.d.ts.map +1 -1
  49. package/dist/core/configurators/slash/opencode.js +2 -57
  50. package/dist/core/configurators/slash/opencode.js.map +1 -1
  51. package/dist/core/configurators/slash/registry.d.ts +4 -4
  52. package/dist/core/configurators/slash/registry.d.ts.map +1 -1
  53. package/dist/core/configurators/slash/registry.js.map +1 -1
  54. package/dist/core/templates/index.d.ts +0 -1
  55. package/dist/core/templates/index.d.ts.map +1 -1
  56. package/dist/core/templates/index.js +0 -1
  57. package/dist/core/templates/index.js.map +1 -1
  58. package/package.json +1 -1
  59. package/skills/ai-humanizer/SKILL.md +50 -0
  60. package/skills/api-contract-generator/SKILL.md +243 -0
  61. package/skills/apply/SKILL.md +23 -0
  62. package/skills/archive/SKILL.md +27 -0
  63. package/skills/design-system/SKILL.md +216 -0
  64. package/skills/document-explainer/SKILL.md +155 -0
  65. package/skills/enhance/SKILL.md +47 -0
  66. package/skills/epic-generator/SKILL.md +204 -0
  67. package/skills/epic-single/SKILL.md +63 -0
  68. package/skills/erd-generator/SKILL.md +138 -0
  69. package/skills/fsd-generator/SKILL.md +163 -0
  70. package/skills/prd-agent-generator/SKILL.md +132 -0
  71. package/skills/prd-generator/SKILL.md +211 -0
  72. package/skills/product-brief/SKILL.md +141 -0
  73. package/skills/project-orchestrator/SKILL.md +15 -6
  74. package/skills/project-orchestrator/assets/caddy-vps-setup.md +180 -0
  75. package/skills/proposal/SKILL.md +28 -0
  76. package/skills/qa-test-scenario/SKILL.md +149 -0
  77. package/skills/skill-creator/SKILL.md +173 -0
  78. package/skills/story-generator/SKILL.md +285 -0
  79. package/skills/story-single/SKILL.md +86 -0
  80. package/skills/tdd-generator/SKILL.md +300 -0
  81. package/skills/tdd-lite-generator/SKILL.md +230 -0
  82. package/skills/wireframe-generator/SKILL.md +227 -0
  83. package/src/cli/index.ts +1 -1
  84. package/src/commands/init.ts +32 -334
  85. package/src/commands/update.ts +20 -47
  86. package/src/core/configurators/slash/antigravity.ts +2 -62
  87. package/src/core/configurators/slash/base.ts +11 -105
  88. package/src/core/configurators/slash/claude.ts +2 -62
  89. package/src/core/configurators/slash/codex.ts +2 -62
  90. package/src/core/configurators/slash/droid.ts +2 -36
  91. package/src/core/configurators/slash/forge.ts +2 -36
  92. package/src/core/configurators/slash/github-copilot.ts +2 -106
  93. package/src/core/configurators/slash/index.ts +1 -1
  94. package/src/core/configurators/slash/kilocode.ts +2 -62
  95. package/src/core/configurators/slash/opencode.ts +2 -62
  96. package/src/core/configurators/slash/registry.ts +5 -5
  97. package/src/core/templates/index.ts +0 -1
  98. package/dist/core/templates/slash-command-templates.d.ts +0 -7
  99. package/dist/core/templates/slash-command-templates.d.ts.map +0 -1
  100. package/dist/core/templates/slash-command-templates.js +0 -1041
  101. package/dist/core/templates/slash-command-templates.js.map +0 -1
  102. package/src/core/templates/slash-command-templates.ts +0 -1068
@@ -3,94 +3,59 @@ import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import chalk from 'chalk';
5
5
  import { checkbox, Separator } from '@inquirer/prompts';
6
- import { PROMPTER_DIR, SUPPORTED_TOOLS, AVAILABLE_PROMPTS, PrompterConfig } from '../core/config.js';
6
+ import { PROMPTER_DIR, SUPPORTED_TOOLS, PrompterConfig } from '../core/config.js';
7
7
  import { projectTemplate, agentsTemplate, claudeTemplate } from '../core/templates/index.js';
8
- import { PROMPT_TEMPLATES } from '../core/prompt-templates.js';
9
8
  import { registry } from '../core/configurators/slash/index.js';
10
- import { SlashCommandId } from '../core/templates/index.js';
11
9
  import { discoverSkills, SkillMetadata } from '../core/skill-discovery.js';
12
10
 
13
11
  interface InitOptions {
14
12
  tools?: string[];
15
- prompts?: string[];
16
13
  skills?: string[];
17
14
  noInteractive?: boolean;
18
15
  }
19
16
 
20
17
  export class InitCommand {
21
- private getCategorizedPromptChoices(currentPrompts: string[]): any[] {
18
+ private truncateDescription(desc: string, max = 72): string {
19
+ return desc.length > max ? desc.slice(0, max - 1) + '…' : desc;
20
+ }
21
+
22
+ private getCategorizedSkillChoices(availableSkills: SkillMetadata[], currentSkillNames: string[]): any[] {
22
23
  const categories = [
23
24
  {
24
- name: '📋 Product Planning & Strategy',
25
- prompts: ['product-brief', 'prd-generator', 'prd-agent-generator']
26
- },
27
- {
28
- name: '📐 Specification & Documentation',
29
- prompts: ['fsd-generator', 'tdd-generator', 'tdd-lite-generator', 'erd-generator', 'api-contract-generator']
25
+ name: '📋 Planning & Strategy',
26
+ skills: ['project-orchestrator', 'feature-planner', 'prd-generator', 'prd-agent-generator', 'product-brief']
30
27
  },
31
28
  {
32
- name: '🎯 Agile & Project Management',
33
- prompts: ['epic-single', 'epic-generator', 'story-single', 'story-generator']
29
+ name: '🎯 Agile & Backlog',
30
+ skills: ['epic-single', 'epic-generator', 'story-single', 'story-generator']
34
31
  },
35
32
  {
36
- name: ' Testing & Quality Assurance',
37
- prompts: ['qa-test-scenario']
33
+ name: '📐 Specification & Architecture',
34
+ skills: ['fsd-generator', 'tdd-generator', 'tdd-lite-generator', 'erd-generator', 'api-contract-generator']
38
35
  },
39
36
  {
40
37
  name: '🎨 Design & UI/UX',
41
- prompts: ['design-system', 'wireframe-generator']
42
- },
43
- {
44
- name: '⚙️ Development Workflow',
45
- prompts: ['proposal', 'apply', 'archive']
38
+ skills: ['ui-ux-pro', 'design-system-generator', 'design-system', 'wireframe-generator', 'design-md', 'frontend-design']
46
39
  },
47
40
  {
48
- name: '📝 Content & Documentation',
49
- prompts: ['ai-humanizer', 'document-explainer', 'skill-creator']
50
- }
51
- ];
52
-
53
- const choices: any[] = [];
54
-
55
- for (const category of categories) {
56
- choices.push(new Separator(chalk.bold.cyan(category.name)));
57
-
58
- for (const promptValue of category.prompts) {
59
- const prompt = AVAILABLE_PROMPTS.find(p => p.value === promptValue);
60
- if (prompt) {
61
- choices.push({
62
- name: ` ${prompt.name} ${chalk.gray('- ' + prompt.description)}`,
63
- value: prompt.value,
64
- checked: currentPrompts.includes(prompt.value)
65
- });
66
- }
67
- }
68
- }
69
-
70
- return choices;
71
- }
72
-
73
- private getCategorizedSkillChoices(availableSkills: SkillMetadata[], currentSkillNames: string[]): any[] {
74
- const categories = [
75
- {
76
- name: '📋 Planning & Strategy',
77
- skills: ['project-orchestrator', 'feature-planner', 'prompter-workflow', 'prompter-specs']
41
+ name: '⚙️ Development & Code Review',
42
+ skills: ['code-review', 'laravel-code-review', 'mcp-builder', 'skill-creator']
78
43
  },
79
44
  {
80
- name: '🎨 Design & UI/UX',
81
- skills: ['ui-ux-pro', 'design-system-generator', 'design-md', 'frontend-design']
45
+ name: ' Testing & QA',
46
+ skills: ['qa-test-scenario']
82
47
  },
83
48
  {
84
- name: '⚙️ Development & Code Review',
85
- skills: ['code-review', 'laravel-code-review', 'mcp-builder']
49
+ name: ' Prompter Workflow',
50
+ skills: ['prompter-workflow', 'prompter-specs', 'proposal', 'apply', 'archive']
86
51
  },
87
52
  {
88
53
  name: '📝 Documentation',
89
- skills: ['doc-builder', 'document-translator', 'ai-context-generator', 'meeting-notes', 'sph-generator']
54
+ skills: ['doc-builder', 'document-translator', 'document-explainer', 'ai-context-generator', 'meeting-notes', 'sph-generator']
90
55
  },
91
56
  {
92
57
  name: '✨ Content & Productivity',
93
- skills: ['gamma-builder', 'enhance-prompt']
58
+ skills: ['enhance', 'enhance-prompt', 'ai-humanizer', 'gamma-builder', 'cerebro']
94
59
  }
95
60
  ];
96
61
 
@@ -108,7 +73,7 @@ export class InitCommand {
108
73
  for (const skill of skillsInCategory) {
109
74
  categorized.add(skill.name);
110
75
  choices.push({
111
- name: ` ${skill.name}`,
76
+ name: ` ${skill.name} ${chalk.gray('- ' + this.truncateDescription(skill.description))}`,
112
77
  value: skill.name,
113
78
  checked: currentSkillNames.includes(skill.name)
114
79
  });
@@ -121,7 +86,7 @@ export class InitCommand {
121
86
  choices.push(new Separator(chalk.bold.cyan('🔧 Other')));
122
87
  for (const skill of uncategorized) {
123
88
  choices.push({
124
- name: ` ${skill.name}`,
89
+ name: ` ${skill.name} ${chalk.gray('- ' + this.truncateDescription(skill.description))}`,
125
90
  value: skill.name,
126
91
  checked: currentSkillNames.includes(skill.name)
127
92
  });
@@ -198,30 +163,6 @@ export class InitCommand {
198
163
  selectedTools = currentTools;
199
164
  }
200
165
 
201
- // Select prompts
202
- let selectedPrompts: string[] = [];
203
-
204
- if (options.prompts && options.prompts.length > 0) {
205
- // Handle comma-separated values in a single string or array of strings
206
- selectedPrompts = options.prompts.flatMap(prompt => prompt.split(',').map(p => p.trim()));
207
- } else if (!options.noInteractive) {
208
- try {
209
- // Detect currently installed prompts (use path.join to get prompter path)
210
- const prompterPathForDetection = path.join(projectPath, PROMPTER_DIR);
211
- const currentPrompts = await this.detectInstalledPrompts(prompterPathForDetection);
212
-
213
- selectedPrompts = await checkbox({
214
- message: 'Select prompt templates to install:',
215
- choices: this.getCategorizedPromptChoices(currentPrompts),
216
- pageSize: 20
217
- });
218
- } catch (error) {
219
- // User cancelled
220
- console.log(chalk.yellow(isReInitialization ? '\nRe-configuration cancelled.' : '\nInitialization cancelled.'));
221
- return;
222
- }
223
- }
224
-
225
166
  // Select skills — resolve from the package directory, not the user's project
226
167
  // dist/commands/init.js → go up two levels to reach the package root
227
168
  const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
@@ -317,13 +258,6 @@ export class InitCommand {
317
258
  const toolsToRemove = currentTools.filter(t => !selectedTools.includes(t));
318
259
  const toolsToKeep = selectedTools.filter(t => currentTools.includes(t));
319
260
 
320
- // Handle prompt changes
321
- const prompterPathForDetection = path.join(projectPath, PROMPTER_DIR);
322
- const currentPrompts = await this.detectInstalledPrompts(prompterPathForDetection);
323
- const promptsToAdd = selectedPrompts.filter(p => !currentPrompts.includes(p));
324
- const promptsToRemove = currentPrompts.filter(p => !selectedPrompts.includes(p));
325
- const promptsToKeep = selectedPrompts.filter(p => currentPrompts.includes(p));
326
-
327
261
  // Remove old tool files
328
262
  if (toolsToRemove.length > 0) {
329
263
  console.log(chalk.blue('\n🗑️ Removing workflow files...\n'));
@@ -342,75 +276,6 @@ export class InitCommand {
342
276
  }
343
277
  }
344
278
 
345
- // Remove unchecked prompts
346
- if (promptsToRemove.length > 0) {
347
- console.log(chalk.blue('\n🗑️ Removing prompt templates...\n'));
348
-
349
- // Remove from prompter/ folder
350
- const removedPrompts = await this.removePrompts(prompterPath, promptsToRemove);
351
- for (const promptName of removedPrompts) {
352
- console.log(chalk.yellow('✓') + ` Removed ${chalk.cyan(promptName)}`);
353
- }
354
-
355
- // Remove workflow files from all configured tools
356
- await this.removeWorkflowFilesForPrompts(projectPath, currentTools, promptsToRemove);
357
- }
358
-
359
- // Generate workflow files for new tools
360
- if (toolsToAdd.length > 0) {
361
- console.log(chalk.blue('\n📝 Creating workflow files...\n'));
362
-
363
- // Convert selected prompt values to SlashCommandIds
364
- const slashCommandIds: SlashCommandId[] = selectedPrompts as SlashCommandId[];
365
-
366
- for (const toolId of toolsToAdd) {
367
- const configurator = registry.get(toolId);
368
- if (configurator) {
369
- try {
370
- // Pass selected prompts to only generate those workflow files
371
- // Pass empty array if no prompts selected to generate nothing
372
- const files = await configurator.generateAll(projectPath, slashCommandIds);
373
- for (const file of files) {
374
- console.log(chalk.green('✓') + ` Created ${chalk.cyan(file)}`);
375
- }
376
- } catch (error) {
377
- console.log(chalk.red('✗') + ` Failed to create files for ${toolId}: ${error}`);
378
- }
379
- }
380
- }
381
- }
382
-
383
- // Add missing workflow files for existing tools
384
- if (isReInitialization && toolsToKeep.length > 0) {
385
- const missingFiles: string[] = [];
386
-
387
- // Convert selected prompt values to SlashCommandIds
388
- const slashCommandIds: SlashCommandId[] = selectedPrompts as SlashCommandId[];
389
-
390
- for (const toolId of toolsToKeep) {
391
- const configurator = registry.get(toolId);
392
- if (configurator) {
393
- try {
394
- // Pass selected prompts to only generate those workflow files
395
- // Pass empty array if no prompts selected to generate nothing
396
- const files = await configurator.generateAll(projectPath, slashCommandIds);
397
- for (const file of files) {
398
- missingFiles.push(file);
399
- }
400
- } catch (error) {
401
- // Ignore errors for kept tools
402
- }
403
- }
404
- }
405
-
406
- if (missingFiles.length > 0) {
407
- console.log(chalk.blue('\n📝 Adding missing workflow files...\n'));
408
- for (const file of missingFiles) {
409
- console.log(chalk.green('✓') + ` Created ${chalk.cyan(file)}`);
410
- }
411
- }
412
- }
413
-
414
279
  // Show kept tools
415
280
  if (isReInitialization && toolsToKeep.length > 0 && (toolsToAdd.length > 0 || toolsToRemove.length > 0)) {
416
281
  console.log(chalk.blue('\n✨ Keeping existing tools:\n'));
@@ -422,31 +287,13 @@ export class InitCommand {
422
287
  }
423
288
  }
424
289
 
425
- // Install new prompts
426
- if (promptsToAdd.length > 0) {
427
- console.log(chalk.blue('\n📋 Installing prompt templates...\n'));
428
- const installedPrompts = await this.installPrompts(projectPath, prompterPath, promptsToAdd);
429
- for (const promptName of installedPrompts) {
430
- console.log(chalk.green('✓') + ` Installed ${chalk.cyan(promptName)}`);
431
- }
432
- }
433
-
434
- // Update existing prompts in prompter/core/
435
- if (isReInitialization && promptsToKeep.length > 0) {
436
- console.log(chalk.blue('\n🔄 Updating existing prompt templates...\n'));
437
- const updatedPrompts = await this.installPrompts(projectPath, prompterPath, promptsToKeep);
438
- for (const promptName of updatedPrompts) {
439
- console.log(chalk.green('✓') + ` Updated ${chalk.cyan(promptName)}`);
440
- }
441
- }
442
-
443
290
  // --- Skills setup ---
444
291
  const skillChanges = await this.setupSkills(projectPath, prompterPath, selectedTools, selectedSkills);
445
292
 
446
293
  // Success message
447
294
  if (isReInitialization) {
448
295
  console.log(chalk.green('\n✅ Prompter tools updated successfully!\n'));
449
- if (toolsToAdd.length > 0 || toolsToRemove.length > 0 || promptsToAdd.length > 0 || promptsToRemove.length > 0 || skillChanges.added.length > 0 || skillChanges.removed.length > 0) {
296
+ if (toolsToAdd.length > 0 || toolsToRemove.length > 0 || skillChanges.added.length > 0 || skillChanges.removed.length > 0) {
450
297
  console.log(chalk.blue('Summary:'));
451
298
  if (toolsToAdd.length > 0) {
452
299
  console.log(chalk.green(' Tools Added: ') + toolsToAdd.map(t => {
@@ -460,18 +307,6 @@ export class InitCommand {
460
307
  return tool ? tool.name : t;
461
308
  }).join(', '));
462
309
  }
463
- if (promptsToAdd.length > 0) {
464
- console.log(chalk.green(' Prompts Added: ') + promptsToAdd.map(p => {
465
- const prompt = AVAILABLE_PROMPTS.find(ap => ap.value === p);
466
- return prompt ? prompt.name : p;
467
- }).join(', '));
468
- }
469
- if (promptsToRemove.length > 0) {
470
- console.log(chalk.yellow(' Prompts Removed: ') + promptsToRemove.map(p => {
471
- const prompt = AVAILABLE_PROMPTS.find(ap => ap.value === p);
472
- return prompt ? prompt.name : p;
473
- }).join(', '));
474
- }
475
310
  if (skillChanges.added.length > 0) {
476
311
  console.log(chalk.green(' Skills Added: ') + skillChanges.added.join(', '));
477
312
  }
@@ -484,9 +319,6 @@ export class InitCommand {
484
319
  }
485
320
  } else {
486
321
  console.log(chalk.green('\n✅ Prompter initialized successfully!\n'));
487
- if (promptsToAdd.length > 0) {
488
- console.log(chalk.gray(`Installed ${promptsToAdd.length} prompt template(s).\n`));
489
- }
490
322
  if (skillChanges.added.length > 0) {
491
323
  console.log(chalk.gray(`Installed ${skillChanges.added.length} skill(s).\n`));
492
324
  }
@@ -508,19 +340,12 @@ export class InitCommand {
508
340
  const allConfigurators = registry.getAll();
509
341
 
510
342
  for (const configurator of allConfigurators) {
511
- const targets = configurator.getTargets();
512
- let hasFiles = false;
513
-
514
- for (const target of targets) {
515
- const filePath = path.join(projectPath, target.path);
516
- if (await this.fileExists(filePath)) {
517
- hasFiles = true;
518
- break;
519
- }
520
- }
521
-
522
- if (hasFiles) {
523
- configuredTools.push(configurator.toolId);
343
+ const skillsRoot = path.join(projectPath, configurator.getSkillsRootDir());
344
+ try {
345
+ const stat = await fs.stat(skillsRoot);
346
+ if (stat.isDirectory()) configuredTools.push(configurator.toolId);
347
+ } catch {
348
+ // directory doesn't exist — tool not configured
524
349
  }
525
350
  }
526
351
 
@@ -528,138 +353,11 @@ export class InitCommand {
528
353
  }
529
354
 
530
355
  private async removeToolFiles(projectPath: string, configurator: any): Promise<string[]> {
531
- const removedFiles: string[] = [];
532
- const targets = configurator.getTargets();
533
-
534
- for (const target of targets) {
535
- const filePath = path.join(projectPath, target.path);
536
- if (await this.fileExists(filePath)) {
537
- await fs.unlink(filePath);
538
- removedFiles.push(target.path);
539
-
540
- // Remove empty parent directories
541
- await this.removeEmptyDirs(path.dirname(filePath), projectPath);
542
- }
543
- }
544
-
545
- return removedFiles;
356
+ await configurator.removeAllDeployedSkills(projectPath);
357
+ return [configurator.getSkillsRootDir() + '/'];
546
358
  }
547
359
 
548
- private async removeEmptyDirs(dirPath: string, projectPath: string): Promise<void> {
549
- // Don't remove the project directory itself
550
- if (dirPath === projectPath || dirPath === path.dirname(projectPath)) {
551
- return;
552
- }
553
360
 
554
- try {
555
- const files = await fs.readdir(dirPath);
556
- if (files.length === 0) {
557
- await fs.rmdir(dirPath);
558
- // Recursively check parent
559
- await this.removeEmptyDirs(path.dirname(dirPath), projectPath);
560
- }
561
- } catch {
562
- // Directory doesn't exist or can't be removed, ignore
563
- }
564
- }
565
-
566
- private async detectInstalledPrompts(prompterPath: string): Promise<string[]> {
567
- const installedPrompts: string[] = [];
568
- const corePath = path.join(prompterPath, 'core');
569
-
570
- for (const prompt of AVAILABLE_PROMPTS) {
571
- const promptFilePath = path.join(corePath, prompt.sourceFile);
572
- if (await this.fileExists(promptFilePath)) {
573
- installedPrompts.push(prompt.value);
574
- }
575
- }
576
-
577
- return installedPrompts;
578
- }
579
-
580
- private async installPrompts(projectPath: string, prompterPath: string, selectedPrompts: string[]): Promise<string[]> {
581
- const installedPrompts: string[] = [];
582
- const corePath = path.join(prompterPath, 'core');
583
-
584
- // Ensure core directory exists
585
- await fs.mkdir(corePath, { recursive: true });
586
-
587
- for (const promptId of selectedPrompts) {
588
- const prompt = AVAILABLE_PROMPTS.find(p => p.value === promptId);
589
- if (!prompt) continue;
590
-
591
- const destPath = path.join(corePath, prompt.sourceFile);
592
-
593
- try {
594
- // Get template content from embedded templates
595
- const content = PROMPT_TEMPLATES[promptId];
596
-
597
- if (!content) {
598
- console.log(chalk.yellow(` Warning: Template not found for ${prompt.name}`));
599
- continue;
600
- }
601
-
602
- // Write the prompt file from embedded template (overwrites if exists)
603
- await fs.writeFile(destPath, content, 'utf-8');
604
- installedPrompts.push(prompt.name);
605
- } catch (error) {
606
- console.log(chalk.red(` Error installing ${prompt.name}: ${error}`));
607
- }
608
- }
609
-
610
- return installedPrompts;
611
- }
612
-
613
- private async removePrompts(prompterPath: string, promptsToRemove: string[]): Promise<string[]> {
614
- const removedPrompts: string[] = [];
615
- const corePath = path.join(prompterPath, 'core');
616
-
617
- for (const promptId of promptsToRemove) {
618
- const prompt = AVAILABLE_PROMPTS.find(p => p.value === promptId);
619
- if (!prompt) continue;
620
-
621
- const filePath = path.join(corePath, prompt.sourceFile);
622
-
623
- try {
624
- if (await this.fileExists(filePath)) {
625
- await fs.unlink(filePath);
626
- removedPrompts.push(prompt.name);
627
- }
628
- } catch (error) {
629
- console.log(chalk.red(` Error removing ${prompt.name}: ${error}`));
630
- }
631
- }
632
-
633
- return removedPrompts;
634
- }
635
-
636
- private async removeWorkflowFilesForPrompts(projectPath: string, toolIds: string[], promptIds: string[]): Promise<void> {
637
- const slashCommandIds: SlashCommandId[] = promptIds as SlashCommandId[];
638
-
639
- for (const toolId of toolIds) {
640
- const configurator = registry.get(toolId);
641
- if (!configurator) continue;
642
-
643
- // Get targets for the prompts to remove
644
- const targets = configurator.getTargets(slashCommandIds);
645
-
646
- for (const target of targets) {
647
- const filePath = path.join(projectPath, target.path);
648
-
649
- try {
650
- if (await this.fileExists(filePath)) {
651
- await fs.unlink(filePath);
652
- console.log(chalk.yellow('✓') + ` Removed ${chalk.cyan(target.path)}`);
653
-
654
- // Remove empty parent directories
655
- await this.removeEmptyDirs(path.dirname(filePath), projectPath);
656
- }
657
- } catch (error) {
658
- // Silently ignore errors for workflow file removal
659
- }
660
- }
661
- }
662
- }
663
361
 
664
362
  private async ensureRootClaudeFile(projectPath: string): Promise<void> {
665
363
  const rootClaudePath = path.join(projectPath, 'CLAUDE.md');
@@ -1,6 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import { promises as fs } from 'fs';
3
3
  import path from 'path';
4
+ import { fileURLToPath } from 'url';
4
5
  import { PrompterConfig, AVAILABLE_PROMPTS, PROMPTER_DIR } from '../core/config.js';
5
6
  import { registry } from '../core/configurators/slash/index.js';
6
7
  import { PROMPT_TEMPLATES } from '../core/prompt-templates.js';
@@ -32,17 +33,21 @@ export class UpdateCommand {
32
33
 
33
34
  let updatedCount = 0;
34
35
 
35
- // Update existing workflow files for configured tools only
36
+ // Clean up legacy slash command files and update skills for each tool
37
+ const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
38
+ const availableSkills = await discoverSkills(path.join(packageDir, 'skills'));
39
+
36
40
  for (const toolId of configuredTools) {
37
41
  const configurator = registry.get(toolId);
38
42
  if (!configurator) continue;
39
43
 
40
44
  try {
41
- // Only update existing files, don't create new ones
42
- const updatedFiles = await configurator.updateExisting(projectPath);
43
- for (const file of updatedFiles) {
44
- console.log(chalk.green('✓') + ` Updated ${chalk.cyan(file)}`);
45
- updatedCount++;
45
+ if (availableSkills.length > 0) {
46
+ const updatedSkillFiles = await configurator.updateExistingSkills(projectPath, availableSkills);
47
+ for (const file of updatedSkillFiles) {
48
+ console.log(chalk.green('✓') + ` Updated ${chalk.cyan(file)}`);
49
+ updatedCount++;
50
+ }
46
51
  }
47
52
  } catch (error) {
48
53
  console.log(chalk.red('✗') + ` Failed to update ${configurator.toolId}: ${error}`);
@@ -57,27 +62,6 @@ export class UpdateCommand {
57
62
  updatedCount++;
58
63
  }
59
64
 
60
- // Update existing skill workflow files
61
- const skillsDir = path.join(projectPath, 'skills');
62
- const availableSkills = await discoverSkills(skillsDir);
63
-
64
- if (availableSkills.length > 0) {
65
- for (const toolId of configuredTools) {
66
- const configurator = registry.get(toolId);
67
- if (!configurator) continue;
68
-
69
- try {
70
- const updatedSkillFiles = await configurator.updateExistingSkills(projectPath, availableSkills);
71
- for (const file of updatedSkillFiles) {
72
- console.log(chalk.green('✓') + ` Updated ${chalk.cyan(file)}`);
73
- updatedCount++;
74
- }
75
- } catch (error) {
76
- console.log(chalk.red('✗') + ` Failed to update skills for ${configurator.toolId}: ${error}`);
77
- }
78
- }
79
- }
80
-
81
65
  if (updatedCount === 0) {
82
66
  console.log(chalk.yellow('⚠️ No workflow files found to update.'));
83
67
  console.log(chalk.gray(' Run `prompter init` to create them.\n'));
@@ -100,19 +84,12 @@ export class UpdateCommand {
100
84
  const allConfigurators = registry.getAll();
101
85
 
102
86
  for (const configurator of allConfigurators) {
103
- const targets = configurator.getTargets();
104
- let hasFiles = false;
105
-
106
- for (const target of targets) {
107
- const filePath = path.join(projectPath, target.path);
108
- if (await this.fileExists(filePath)) {
109
- hasFiles = true;
110
- break;
111
- }
112
- }
113
-
114
- if (hasFiles) {
115
- configuredTools.push(configurator.toolId);
87
+ const skillsRoot = path.join(projectPath, configurator.getSkillsRootDir());
88
+ try {
89
+ const stat = await fs.stat(skillsRoot);
90
+ if (stat.isDirectory()) configuredTools.push(configurator.toolId);
91
+ } catch {
92
+ // directory doesn't exist — tool not configured
116
93
  }
117
94
  }
118
95
 
@@ -123,26 +100,22 @@ export class UpdateCommand {
123
100
  const updatedPrompts: string[] = [];
124
101
  const corePath = path.join(prompterPath, 'core');
125
102
 
126
- // Check if core directory exists
127
103
  if (!await this.fileExists(corePath)) {
128
104
  return updatedPrompts;
129
105
  }
130
106
 
131
- // Update each existing prompt file
132
107
  for (const prompt of AVAILABLE_PROMPTS) {
133
108
  const promptFilePath = path.join(corePath, prompt.sourceFile);
134
-
135
- // Only update if file exists
109
+
136
110
  if (await this.fileExists(promptFilePath)) {
137
111
  try {
138
112
  const content = PROMPT_TEMPLATES[prompt.value];
139
-
113
+
140
114
  if (!content) {
141
115
  console.log(chalk.yellow(` Warning: Template not found for ${prompt.name}`));
142
116
  continue;
143
117
  }
144
-
145
- // Update the prompt file
118
+
146
119
  await fs.writeFile(promptFilePath, content, 'utf-8');
147
120
  updatedPrompts.push(prompt.sourceFile);
148
121
  } catch (error) {
@@ -1,69 +1,9 @@
1
- import { SlashCommandConfigurator } from './base.js';
2
- import { SlashCommandId } from '../../templates/index.js';
1
+ import { ToolConfigurator } from './base.js';
3
2
 
4
- const FILE_PATHS: Record<SlashCommandId, string> = {
5
- enhance: '.agent/workflows/prompter-enhance.md',
6
- 'prd-generator': '.agent/workflows/prd-generator.md',
7
- 'prd-agent-generator': '.agent/workflows/prd-agent-generator.md',
8
- 'product-brief': '.agent/workflows/product-brief.md',
9
- 'epic-single': '.agent/workflows/epic-single.md',
10
- 'epic-generator': '.agent/workflows/epic-generator.md',
11
- 'story-single': '.agent/workflows/story-single.md',
12
- 'story-generator': '.agent/workflows/story-generator.md',
13
- 'qa-test-scenario': '.agent/workflows/qa-test-scenario.md',
14
- 'skill-creator': '.agent/workflows/skill-creator.md',
15
- 'ai-humanizer': '.agent/workflows/ai-humanizer.md',
16
- 'api-contract-generator': '.agent/workflows/api-contract-generator.md',
17
- 'apply': '.agent/workflows/apply.md',
18
- 'archive': '.agent/workflows/archive.md',
19
- 'design-system': '.agent/workflows/design-system.md',
20
- 'erd-generator': '.agent/workflows/erd-generator.md',
21
- 'fsd-generator': '.agent/workflows/fsd-generator.md',
22
- 'proposal': '.agent/workflows/proposal.md',
23
- 'tdd-generator': '.agent/workflows/tdd-generator.md',
24
- 'tdd-lite-generator': '.agent/workflows/tdd-lite-generator.md',
25
- 'wireframe-generator': '.agent/workflows/wireframe-generator.md',
26
- 'document-explainer': '.agent/workflows/document-explainer.md'
27
- };
28
-
29
- const DESCRIPTIONS: Record<SlashCommandId, string> = {
30
- enhance: 'Enhance a rough prompt into a professional specification',
31
- 'prd-generator': 'Generate a comprehensive Product Requirements Document (PRD)',
32
- 'prd-agent-generator': 'Generate a PRD with autonomous assumptions (non-interactive mode)',
33
- 'product-brief': 'Generate an executive-level product brief (1-page summary)',
34
- 'epic-single': 'Generate a single well-defined Jira Epic',
35
- 'epic-generator': 'Generate a comprehensive set of EPICs from documentation',
36
- 'story-single': 'Generate a single Jira User Story from requirements',
37
- 'story-generator': 'Generate comprehensive user stories from EPICs and FSD',
38
- 'qa-test-scenario': 'Generate focused QA test scenarios from PRD',
39
- 'skill-creator': 'Create a modular skill package that extends AI agent capabilities',
40
- 'ai-humanizer': 'Humanize and proofread AI-generated content for natural, publication-ready output',
41
- 'api-contract-generator': 'Generate OpenAPI specification from FSD and ERD',
42
- 'apply': 'Implement and apply an approved change proposal',
43
- 'archive': 'Archive a completed change and update specs',
44
- 'design-system': 'Generate comprehensive design system documentation for components and tokens',
45
- 'erd-generator': 'Generate Entity Relationship Diagram from FSD',
46
- 'fsd-generator': 'Generate Functional Specification Document from PRD',
47
- 'proposal': 'Create a new change proposal with spec deltas',
48
- 'tdd-generator': 'Generate comprehensive Technical Design Document',
49
- 'tdd-lite-generator': 'Generate lean Technical Design Document (TDD-Lite)',
50
- 'wireframe-generator': 'Generate UI/UX wireframes from technical specs',
51
- 'document-explainer': 'Analyze and explain complex documents into clear, actionable insights'
52
- };
53
-
54
- export class AntigravityConfigurator extends SlashCommandConfigurator {
3
+ export class AntigravityConfigurator extends ToolConfigurator {
55
4
  readonly toolId = 'antigravity';
56
5
  readonly isAvailable = true;
57
6
 
58
- protected getRelativePath(id: SlashCommandId): string {
59
- return FILE_PATHS[id];
60
- }
61
-
62
- protected getFrontmatter(id: SlashCommandId): string | undefined {
63
- const description = DESCRIPTIONS[id];
64
- return `---\ndescription: ${description}\n---`;
65
- }
66
-
67
7
  protected getSkillTargetDir(skillName: string): string {
68
8
  return `.agent/skills/${skillName}`;
69
9
  }