@dedesfr/prompter 0.8.23 → 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.
Files changed (247) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +105 -77
  3. package/dist/cli/index.js +25 -1
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/commands/init.d.ts +1 -7
  6. package/dist/commands/init.d.ts.map +1 -1
  7. package/dist/commands/init.js +60 -299
  8. package/dist/commands/init.js.map +1 -1
  9. package/dist/commands/login.d.ts +4 -0
  10. package/dist/commands/login.d.ts.map +1 -0
  11. package/dist/commands/login.js +56 -0
  12. package/dist/commands/login.js.map +1 -0
  13. package/dist/commands/logout.d.ts +4 -0
  14. package/dist/commands/logout.d.ts.map +1 -0
  15. package/dist/commands/logout.js +14 -0
  16. package/dist/commands/logout.js.map +1 -0
  17. package/dist/commands/update.d.ts.map +1 -1
  18. package/dist/commands/update.js +31 -41
  19. package/dist/commands/update.js.map +1 -1
  20. package/dist/commands/whoami.d.ts +4 -0
  21. package/dist/commands/whoami.d.ts.map +1 -0
  22. package/dist/commands/whoami.js +42 -0
  23. package/dist/commands/whoami.js.map +1 -0
  24. package/dist/core/auth-store.d.ts +10 -0
  25. package/dist/core/auth-store.d.ts.map +1 -0
  26. package/dist/core/auth-store.js +39 -0
  27. package/dist/core/auth-store.js.map +1 -0
  28. package/dist/core/configurators/slash/antigravity.d.ts +2 -5
  29. package/dist/core/configurators/slash/antigravity.d.ts.map +1 -1
  30. package/dist/core/configurators/slash/antigravity.js +2 -57
  31. package/dist/core/configurators/slash/antigravity.js.map +1 -1
  32. package/dist/core/configurators/slash/base.d.ts +6 -18
  33. package/dist/core/configurators/slash/base.d.ts.map +1 -1
  34. package/dist/core/configurators/slash/base.js +8 -77
  35. package/dist/core/configurators/slash/base.js.map +1 -1
  36. package/dist/core/configurators/slash/claude.d.ts +2 -5
  37. package/dist/core/configurators/slash/claude.d.ts.map +1 -1
  38. package/dist/core/configurators/slash/claude.js +2 -57
  39. package/dist/core/configurators/slash/claude.js.map +1 -1
  40. package/dist/core/configurators/slash/codex.d.ts +2 -5
  41. package/dist/core/configurators/slash/codex.d.ts.map +1 -1
  42. package/dist/core/configurators/slash/codex.js +2 -57
  43. package/dist/core/configurators/slash/codex.js.map +1 -1
  44. package/dist/core/configurators/slash/droid.d.ts +2 -5
  45. package/dist/core/configurators/slash/droid.d.ts.map +1 -1
  46. package/dist/core/configurators/slash/droid.js +2 -32
  47. package/dist/core/configurators/slash/droid.js.map +1 -1
  48. package/dist/core/configurators/slash/forge.d.ts +2 -5
  49. package/dist/core/configurators/slash/forge.d.ts.map +1 -1
  50. package/dist/core/configurators/slash/forge.js +2 -32
  51. package/dist/core/configurators/slash/forge.js.map +1 -1
  52. package/dist/core/configurators/slash/github-copilot.d.ts +2 -7
  53. package/dist/core/configurators/slash/github-copilot.d.ts.map +1 -1
  54. package/dist/core/configurators/slash/github-copilot.js +2 -96
  55. package/dist/core/configurators/slash/github-copilot.js.map +1 -1
  56. package/dist/core/configurators/slash/index.d.ts +1 -1
  57. package/dist/core/configurators/slash/index.d.ts.map +1 -1
  58. package/dist/core/configurators/slash/index.js +1 -1
  59. package/dist/core/configurators/slash/index.js.map +1 -1
  60. package/dist/core/configurators/slash/kilocode.d.ts +2 -5
  61. package/dist/core/configurators/slash/kilocode.d.ts.map +1 -1
  62. package/dist/core/configurators/slash/kilocode.js +2 -57
  63. package/dist/core/configurators/slash/kilocode.js.map +1 -1
  64. package/dist/core/configurators/slash/opencode.d.ts +2 -5
  65. package/dist/core/configurators/slash/opencode.d.ts.map +1 -1
  66. package/dist/core/configurators/slash/opencode.js +2 -57
  67. package/dist/core/configurators/slash/opencode.js.map +1 -1
  68. package/dist/core/configurators/slash/registry.d.ts +4 -4
  69. package/dist/core/configurators/slash/registry.d.ts.map +1 -1
  70. package/dist/core/configurators/slash/registry.js.map +1 -1
  71. package/dist/core/registry.d.ts +18 -0
  72. package/dist/core/registry.d.ts.map +1 -0
  73. package/dist/core/registry.js +94 -0
  74. package/dist/core/registry.js.map +1 -0
  75. package/dist/core/templates/index.d.ts +0 -1
  76. package/dist/core/templates/index.d.ts.map +1 -1
  77. package/dist/core/templates/index.js +0 -1
  78. package/dist/core/templates/index.js.map +1 -1
  79. package/package.json +7 -1
  80. package/AGENTS.md +0 -123
  81. package/CLAUDE.md +0 -17
  82. package/build.js +0 -20
  83. package/convex-setup.md +0 -403
  84. package/dist/core/templates/slash-command-templates.d.ts +0 -7
  85. package/dist/core/templates/slash-command-templates.d.ts.map +0 -1
  86. package/dist/core/templates/slash-command-templates.js +0 -1041
  87. package/dist/core/templates/slash-command-templates.js.map +0 -1
  88. package/prompt/ai-humanizer.md +0 -45
  89. package/prompt/api-contract-generator.md +0 -234
  90. package/prompt/apply.md +0 -17
  91. package/prompt/archive.md +0 -21
  92. package/prompt/design-system.md +0 -210
  93. package/prompt/document-explainer.md +0 -149
  94. package/prompt/epic-generator.md +0 -198
  95. package/prompt/epic-single.md +0 -47
  96. package/prompt/erd-generator.md +0 -130
  97. package/prompt/fsd-generator.md +0 -157
  98. package/prompt/prd-agent-generator.md +0 -147
  99. package/prompt/prd-generator.md +0 -195
  100. package/prompt/product-brief.md +0 -289
  101. package/prompt/proposal.md +0 -22
  102. package/prompt/qa-test-scenario.md +0 -133
  103. package/prompt/skill-creator.md +0 -350
  104. package/prompt/story-generator.md +0 -278
  105. package/prompt/story-single.md +0 -70
  106. package/prompt/tdd-generator.md +0 -294
  107. package/prompt/tdd-lite-generator.md +0 -224
  108. package/prompt/wireframe-generator.md +0 -219
  109. package/skills/ai-context-generator/SKILL.md +0 -54
  110. package/skills/ai-context-generator/references/AGENTS.template.md +0 -83
  111. package/skills/ai-context-generator/references/CLAUDE.template.md +0 -39
  112. package/skills/ai-context-generator/references/behavioral-guidelines.md +0 -71
  113. package/skills/ai-context-generator/references/discovery-checklist.md +0 -40
  114. package/skills/ai-context-generator/references/examples/AGENTS.good.md +0 -103
  115. package/skills/ai-context-generator/references/extraction-checklist.md +0 -23
  116. package/skills/ai-context-generator/references/overlays/laravel.md +0 -44
  117. package/skills/cerebro/SKILL.md +0 -187
  118. package/skills/cerebro/references/agents.md +0 -213
  119. package/skills/code-review/SKILL.md +0 -373
  120. package/skills/code-review/assets/report-template-agent.md +0 -212
  121. package/skills/code-review/assets/report-template-compact.md +0 -81
  122. package/skills/code-review/assets/report-template-full.md +0 -264
  123. package/skills/code-review/assets/report-template-human.md +0 -168
  124. package/skills/code-review/references/universal-patterns.md +0 -495
  125. package/skills/design-md/README.md +0 -34
  126. package/skills/design-md/SKILL.md +0 -172
  127. package/skills/design-md/examples/DESIGN.md +0 -154
  128. package/skills/design-system-generator/SKILL.md +0 -324
  129. package/skills/design-system-generator/assets/design-system-template.md +0 -348
  130. package/skills/design-system-generator/references/extraction-patterns.md +0 -321
  131. package/skills/doc-builder/SKILL.md +0 -115
  132. package/skills/doc-builder/references/ui-patterns.md +0 -394
  133. package/skills/document-translator/SKILL.md +0 -58
  134. package/skills/enhance-prompt/README.md +0 -34
  135. package/skills/enhance-prompt/SKILL.md +0 -204
  136. package/skills/enhance-prompt/references/KEYWORDS.md +0 -114
  137. package/skills/feature-planner/SKILL.md +0 -305
  138. package/skills/feature-planner/assets/implementation-plan-template.md +0 -85
  139. package/skills/frontend-design/LICENSE.txt +0 -177
  140. package/skills/frontend-design/SKILL.md +0 -42
  141. package/skills/gamma-builder/SKILL.md +0 -134
  142. package/skills/laravel-code-review/SKILL.md +0 -383
  143. package/skills/laravel-code-review/assets/report-template-agent.md +0 -195
  144. package/skills/laravel-code-review/assets/report-template-compact.md +0 -79
  145. package/skills/laravel-code-review/assets/report-template-full.md +0 -253
  146. package/skills/laravel-code-review/assets/report-template-human.md +0 -159
  147. package/skills/laravel-code-review/references/laravel-patterns.md +0 -571
  148. package/skills/laravel-code-review/references/php84-features.md +0 -442
  149. package/skills/mcp-builder/LICENSE.txt +0 -202
  150. package/skills/mcp-builder/SKILL.md +0 -236
  151. package/skills/mcp-builder/reference/evaluation.md +0 -602
  152. package/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  153. package/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  154. package/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  155. package/skills/mcp-builder/scripts/connections.py +0 -151
  156. package/skills/mcp-builder/scripts/evaluation.py +0 -373
  157. package/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  158. package/skills/mcp-builder/scripts/requirements.txt +0 -2
  159. package/skills/meeting-notes/SKILL.md +0 -159
  160. package/skills/meeting-notes/evals/evals.json +0 -23
  161. package/skills/project-orchestrator/SKILL.md +0 -487
  162. package/skills/project-orchestrator/assets/caddy-vps-setup.md +0 -180
  163. package/skills/project-orchestrator/assets/plan-summary-template.md +0 -159
  164. package/skills/prompter-specs/SKILL.md +0 -115
  165. package/skills/prompter-workflow/SKILL.md +0 -166
  166. package/skills/prompter-workflow/evals/evals.json +0 -89
  167. package/skills/sph-generator/SKILL.md +0 -488
  168. package/skills/ui-ux-pro/SKILL.md +0 -199
  169. package/skills/ui-ux-pro/assets/design-spec-template.md +0 -173
  170. package/skills/ui-ux-pro/references/component-patterns.md +0 -255
  171. package/skills/ui-ux-pro/references/design-principles.md +0 -167
  172. package/src/cli/index.ts +0 -223
  173. package/src/commands/archive.ts +0 -302
  174. package/src/commands/change.ts +0 -292
  175. package/src/commands/config.ts +0 -233
  176. package/src/commands/guide.ts +0 -50
  177. package/src/commands/init.ts +0 -899
  178. package/src/commands/list.ts +0 -194
  179. package/src/commands/show.ts +0 -138
  180. package/src/commands/spec.ts +0 -251
  181. package/src/commands/update.ts +0 -156
  182. package/src/commands/upgrade.ts +0 -30
  183. package/src/commands/validate.ts +0 -326
  184. package/src/core/artifact-graph/graph.ts +0 -167
  185. package/src/core/artifact-graph/index.ts +0 -44
  186. package/src/core/artifact-graph/instruction-loader.ts +0 -302
  187. package/src/core/artifact-graph/resolver.ts +0 -226
  188. package/src/core/artifact-graph/schema.ts +0 -124
  189. package/src/core/artifact-graph/state.ts +0 -64
  190. package/src/core/artifact-graph/types.ts +0 -65
  191. package/src/core/completions/command-registry.ts +0 -382
  192. package/src/core/completions/completion-provider.ts +0 -128
  193. package/src/core/completions/generators/bash-generator.ts +0 -191
  194. package/src/core/completions/generators/fish-generator.ts +0 -188
  195. package/src/core/completions/generators/powershell-generator.ts +0 -223
  196. package/src/core/completions/generators/zsh-generator.ts +0 -281
  197. package/src/core/completions/templates/bash-templates.ts +0 -24
  198. package/src/core/completions/templates/fish-templates.ts +0 -40
  199. package/src/core/completions/templates/powershell-templates.ts +0 -25
  200. package/src/core/completions/templates/zsh-templates.ts +0 -36
  201. package/src/core/completions/types.ts +0 -90
  202. package/src/core/config-schema.ts +0 -230
  203. package/src/core/config.ts +0 -181
  204. package/src/core/configurators/slash/antigravity.ts +0 -70
  205. package/src/core/configurators/slash/base.ts +0 -203
  206. package/src/core/configurators/slash/claude.ts +0 -70
  207. package/src/core/configurators/slash/codex.ts +0 -70
  208. package/src/core/configurators/slash/droid.ts +0 -44
  209. package/src/core/configurators/slash/forge.ts +0 -44
  210. package/src/core/configurators/slash/github-copilot.ts +0 -114
  211. package/src/core/configurators/slash/index.ts +0 -10
  212. package/src/core/configurators/slash/kilocode.ts +0 -70
  213. package/src/core/configurators/slash/opencode.ts +0 -70
  214. package/src/core/configurators/slash/registry.ts +0 -51
  215. package/src/core/converters/json-converter.ts +0 -62
  216. package/src/core/global-config.ts +0 -136
  217. package/src/core/parsers/change-parser.ts +0 -234
  218. package/src/core/parsers/markdown-parser.ts +0 -237
  219. package/src/core/parsers/requirement-blocks.ts +0 -234
  220. package/src/core/prompt-templates.ts +0 -3504
  221. package/src/core/schemas/base.schema.ts +0 -20
  222. package/src/core/schemas/change.schema.ts +0 -42
  223. package/src/core/schemas/index.ts +0 -20
  224. package/src/core/schemas/spec.schema.ts +0 -17
  225. package/src/core/skill-discovery.ts +0 -68
  226. package/src/core/specs-apply.ts +0 -483
  227. package/src/core/styles/palette.ts +0 -8
  228. package/src/core/templates/agents-template.ts +0 -459
  229. package/src/core/templates/claude-template.ts +0 -2
  230. package/src/core/templates/index.ts +0 -4
  231. package/src/core/templates/project-template.ts +0 -32
  232. package/src/core/templates/slash-command-templates.ts +0 -1068
  233. package/src/core/validation/constants.ts +0 -48
  234. package/src/core/validation/types.ts +0 -19
  235. package/src/core/validation/validator.ts +0 -449
  236. package/src/core/view.ts +0 -219
  237. package/src/index.ts +0 -1
  238. package/src/utils/change-metadata.ts +0 -171
  239. package/src/utils/change-utils.ts +0 -131
  240. package/src/utils/file-system.ts +0 -252
  241. package/src/utils/index.ts +0 -12
  242. package/src/utils/interactive.ts +0 -29
  243. package/src/utils/item-discovery.ts +0 -66
  244. package/src/utils/match.ts +0 -26
  245. package/src/utils/shell-detection.ts +0 -62
  246. package/src/utils/task-progress.ts +0 -43
  247. package/tsconfig.json +0 -28
@@ -1,899 +0,0 @@
1
- import { promises as fs } from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import chalk from 'chalk';
5
- import { checkbox, Separator } from '@inquirer/prompts';
6
- import { PROMPTER_DIR, SUPPORTED_TOOLS, AVAILABLE_PROMPTS, PrompterConfig } from '../core/config.js';
7
- import { projectTemplate, agentsTemplate, claudeTemplate } from '../core/templates/index.js';
8
- import { PROMPT_TEMPLATES } from '../core/prompt-templates.js';
9
- import { registry } from '../core/configurators/slash/index.js';
10
- import { SlashCommandId } from '../core/templates/index.js';
11
- import { discoverSkills, SkillMetadata } from '../core/skill-discovery.js';
12
-
13
- interface InitOptions {
14
- tools?: string[];
15
- prompts?: string[];
16
- skills?: string[];
17
- noInteractive?: boolean;
18
- }
19
-
20
- export class InitCommand {
21
- private getCategorizedPromptChoices(currentPrompts: string[]): any[] {
22
- const categories = [
23
- {
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']
30
- },
31
- {
32
- name: 'šŸŽÆ Agile & Project Management',
33
- prompts: ['epic-single', 'epic-generator', 'story-single', 'story-generator']
34
- },
35
- {
36
- name: 'āœ… Testing & Quality Assurance',
37
- prompts: ['qa-test-scenario']
38
- },
39
- {
40
- name: 'šŸŽØ Design & UI/UX',
41
- prompts: ['design-system', 'wireframe-generator']
42
- },
43
- {
44
- name: 'āš™ļø Development Workflow',
45
- prompts: ['proposal', 'apply', 'archive']
46
- },
47
- {
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']
78
- },
79
- {
80
- name: 'šŸŽØ Design & UI/UX',
81
- skills: ['ui-ux-pro', 'design-system-generator', 'design-md', 'frontend-design']
82
- },
83
- {
84
- name: 'āš™ļø Development & Code Review',
85
- skills: ['code-review', 'laravel-code-review', 'mcp-builder']
86
- },
87
- {
88
- name: 'šŸ“ Documentation',
89
- skills: ['doc-builder', 'document-translator', 'ai-context-generator', 'meeting-notes', 'sph-generator']
90
- },
91
- {
92
- name: '✨ Content & Productivity',
93
- skills: ['gamma-builder', 'enhance-prompt']
94
- }
95
- ];
96
-
97
- const categorized = new Set<string>();
98
- const choices: any[] = [];
99
-
100
- for (const category of categories) {
101
- const skillsInCategory = category.skills
102
- .map(name => availableSkills.find(s => s.name === name))
103
- .filter((s): s is SkillMetadata => !!s);
104
-
105
- if (skillsInCategory.length === 0) continue;
106
-
107
- choices.push(new Separator(chalk.bold.cyan(category.name)));
108
- for (const skill of skillsInCategory) {
109
- categorized.add(skill.name);
110
- choices.push({
111
- name: ` ${skill.name}`,
112
- value: skill.name,
113
- checked: currentSkillNames.includes(skill.name)
114
- });
115
- }
116
- }
117
-
118
- // Uncategorized skills
119
- const uncategorized = availableSkills.filter(s => !categorized.has(s.name));
120
- if (uncategorized.length > 0) {
121
- choices.push(new Separator(chalk.bold.cyan('šŸ”§ Other')));
122
- for (const skill of uncategorized) {
123
- choices.push({
124
- name: ` ${skill.name}`,
125
- value: skill.name,
126
- checked: currentSkillNames.includes(skill.name)
127
- });
128
- }
129
- }
130
-
131
- return choices;
132
- }
133
-
134
- async execute(options: InitOptions = {}): Promise<void> {
135
- const projectPath = process.cwd();
136
- const isReInitialization = await PrompterConfig.prompterDirExists(projectPath);
137
-
138
- // Display ASCII art banner for initial setup
139
- if (!isReInitialization) {
140
- console.log(chalk.cyan(`
141
- ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ
142
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
143
- ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ
144
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
145
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
146
- `));
147
- console.log(chalk.white.bold('Welcome to Prompter!\n'));
148
- }
149
-
150
- if (isReInitialization) {
151
- console.log(chalk.blue('\nšŸ”„ Re-configuring Prompter tools...\n'));
152
- } else {
153
- console.log(chalk.blue('šŸš€ Initializing Prompter...\n'));
154
- }
155
-
156
- // Detect currently configured tools if re-initializing
157
- let currentTools: string[] = [];
158
- if (isReInitialization) {
159
- currentTools = await this.detectConfiguredTools(projectPath);
160
- if (currentTools.length > 0) {
161
- console.log(chalk.gray('Currently configured tools: ') + chalk.cyan(currentTools.map(t => {
162
- const tool = SUPPORTED_TOOLS.find(st => st.value === t);
163
- return tool ? tool.name : t;
164
- }).join(', ')));
165
- console.log();
166
- }
167
- }
168
-
169
- // Select tools
170
- let selectedTools: string[] = [];
171
-
172
- if (options.tools && options.tools.length > 0) {
173
- // Handle comma-separated values in a single string or array of strings
174
- selectedTools = options.tools.flatMap(tool => tool.split(',').map(t => t.trim()));
175
- } else if (!options.noInteractive) {
176
- try {
177
- const message = isReInitialization
178
- ? 'Select AI tools to configure (check/uncheck to add/remove):'
179
- : 'Select AI tools to configure:';
180
-
181
- selectedTools = await checkbox({
182
- message,
183
- choices: SUPPORTED_TOOLS.map(tool => ({
184
- name: tool.name,
185
- value: tool.value,
186
- checked: isReInitialization
187
- ? currentTools.includes(tool.value)
188
- : tool.value === 'antigravity' // Default check Antigravity for new init
189
- }))
190
- });
191
- } catch (error) {
192
- // User cancelled
193
- console.log(chalk.yellow(isReInitialization ? '\nRe-configuration cancelled.' : '\nInitialization cancelled.'));
194
- return;
195
- }
196
- } else if (isReInitialization && selectedTools.length === 0) {
197
- // In non-interactive re-init without tools specified, keep current tools
198
- selectedTools = currentTools;
199
- }
200
-
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
- // Select skills — resolve from the package directory, not the user's project
226
- // dist/commands/init.js → go up two levels to reach the package root
227
- const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
228
- const availableSkills = await discoverSkills(path.join(packageDir, 'skills'));
229
- let selectedSkills: SkillMetadata[] = [];
230
-
231
- if (options.skills && options.skills.length > 0) {
232
- const requestedNames = options.skills.flatMap(s => s.split(',').map(s => s.trim()));
233
- selectedSkills = availableSkills.filter(s => requestedNames.includes(s.name));
234
- } else if (!options.noInteractive && availableSkills.length > 0) {
235
- try {
236
- const prompterPathForDetection = path.join(projectPath, PROMPTER_DIR);
237
- const currentSkillNames = await this.detectInstalledSkills(prompterPathForDetection);
238
-
239
- const selectedSkillNames = await checkbox({
240
- message: 'Select skills to install:',
241
- choices: this.getCategorizedSkillChoices(availableSkills, currentSkillNames),
242
- pageSize: 20
243
- });
244
- selectedSkills = availableSkills.filter(s => selectedSkillNames.includes(s.name));
245
- } catch (error) {
246
- // User cancelled
247
- console.log(chalk.yellow(isReInitialization ? '\nRe-configuration cancelled.' : '\nInitialization cancelled.'));
248
- return;
249
- }
250
- }
251
-
252
- // Create or ensure prompter directory
253
- const prompterPath = await PrompterConfig.ensurePrompterDir(projectPath);
254
- if (!isReInitialization) {
255
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/')}`);
256
- }
257
-
258
- // Create project.md if not exists
259
- const projectMdPath = path.join(prompterPath, 'project.md');
260
- const projectMdExists = await this.fileExists(projectMdPath);
261
- if (!projectMdExists) {
262
- try {
263
- if (!projectTemplate) {
264
- throw new Error('project.md template is undefined');
265
- }
266
- await fs.writeFile(projectMdPath, projectTemplate, 'utf-8');
267
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/project.md')}`);
268
- } catch (error) {
269
- console.error(chalk.red('āœ—') + ` Failed to create project.md: ${error}`);
270
- }
271
- } else if (isReInitialization) {
272
- console.log(chalk.gray(' project.md already exists, keeping it'));
273
- }
274
-
275
- // Create or update AGENTS.md for universal support
276
- const agentsMdPath = path.join(prompterPath, 'AGENTS.md');
277
- const agentsExists = await this.fileExists(agentsMdPath);
278
- try {
279
- if (!agentsTemplate) {
280
- throw new Error('AGENTS.md template is undefined');
281
- }
282
- await fs.writeFile(agentsMdPath, agentsTemplate, 'utf-8');
283
- if (!agentsExists) {
284
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/AGENTS.md')}`);
285
- } else if (isReInitialization) {
286
- console.log(chalk.green('āœ“') + ` Updated ${chalk.cyan(PROMPTER_DIR + '/AGENTS.md')}`);
287
- }
288
- } catch (error) {
289
- console.error(chalk.red('āœ—') + ` Failed to ${agentsExists ? 'update' : 'create'} AGENTS.md: ${error}`);
290
- }
291
-
292
- // Create or update CLAUDE.md for Claude Code support
293
- const claudeMdPath = path.join(prompterPath, 'CLAUDE.md');
294
- const claudeExists = await this.fileExists(claudeMdPath);
295
- try {
296
- if (!claudeTemplate) {
297
- throw new Error('CLAUDE.md template is undefined');
298
- }
299
- await fs.writeFile(claudeMdPath, claudeTemplate, 'utf-8');
300
- if (!claudeExists) {
301
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/CLAUDE.md')}`);
302
- } else if (isReInitialization) {
303
- console.log(chalk.green('āœ“') + ` Updated ${chalk.cyan(PROMPTER_DIR + '/CLAUDE.md')}`);
304
- }
305
- } catch (error) {
306
- console.error(chalk.red('āœ—') + ` Failed to ${claudeExists ? 'update' : 'create'} CLAUDE.md: ${error}`);
307
- }
308
-
309
- // Ensure root AGENTS.md has Prompter instructions
310
- await this.ensureRootAgentsFile(projectPath);
311
-
312
- // Ensure root CLAUDE.md has Prompter instructions
313
- await this.ensureRootClaudeFile(projectPath);
314
-
315
- // Handle tool changes
316
- const toolsToAdd = selectedTools.filter(t => !currentTools.includes(t));
317
- const toolsToRemove = currentTools.filter(t => !selectedTools.includes(t));
318
- const toolsToKeep = selectedTools.filter(t => currentTools.includes(t));
319
-
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
- // Remove old tool files
328
- if (toolsToRemove.length > 0) {
329
- console.log(chalk.blue('\nšŸ—‘ļø Removing workflow files...\n'));
330
- for (const toolId of toolsToRemove) {
331
- const configurator = registry.get(toolId);
332
- if (configurator) {
333
- try {
334
- const files = await this.removeToolFiles(projectPath, configurator);
335
- for (const file of files) {
336
- console.log(chalk.yellow('āœ“') + ` Removed ${chalk.cyan(file)}`);
337
- }
338
- } catch (error) {
339
- console.log(chalk.red('āœ—') + ` Failed to remove files for ${toolId}: ${error}`);
340
- }
341
- }
342
- }
343
- }
344
-
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
- // Show kept tools
415
- if (isReInitialization && toolsToKeep.length > 0 && (toolsToAdd.length > 0 || toolsToRemove.length > 0)) {
416
- console.log(chalk.blue('\n✨ Keeping existing tools:\n'));
417
- for (const toolId of toolsToKeep) {
418
- const tool = SUPPORTED_TOOLS.find(t => t.value === toolId);
419
- if (tool) {
420
- console.log(chalk.gray(' • ') + chalk.cyan(tool.name));
421
- }
422
- }
423
- }
424
-
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
- // --- Skills setup ---
444
- const skillChanges = await this.setupSkills(projectPath, prompterPath, selectedTools, selectedSkills);
445
-
446
- // Success message
447
- if (isReInitialization) {
448
- 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) {
450
- console.log(chalk.blue('Summary:'));
451
- if (toolsToAdd.length > 0) {
452
- console.log(chalk.green(' Tools Added: ') + toolsToAdd.map(t => {
453
- const tool = SUPPORTED_TOOLS.find(st => st.value === t);
454
- return tool ? tool.name : t;
455
- }).join(', '));
456
- }
457
- if (toolsToRemove.length > 0) {
458
- console.log(chalk.yellow(' Tools Removed: ') + toolsToRemove.map(t => {
459
- const tool = SUPPORTED_TOOLS.find(st => st.value === t);
460
- return tool ? tool.name : t;
461
- }).join(', '));
462
- }
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
- if (skillChanges.added.length > 0) {
476
- console.log(chalk.green(' Skills Added: ') + skillChanges.added.join(', '));
477
- }
478
- if (skillChanges.removed.length > 0) {
479
- console.log(chalk.yellow(' Skills Removed: ') + skillChanges.removed.join(', '));
480
- }
481
- console.log();
482
- } else {
483
- console.log(chalk.gray(' No changes made.\n'));
484
- }
485
- } else {
486
- 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
- if (skillChanges.added.length > 0) {
491
- console.log(chalk.gray(`Installed ${skillChanges.added.length} skill(s).\n`));
492
- }
493
- console.log(chalk.gray('Run `prompter guide` for next steps.\n'));
494
- }
495
- }
496
-
497
- private async fileExists(filePath: string): Promise<boolean> {
498
- try {
499
- await fs.access(filePath);
500
- return true;
501
- } catch {
502
- return false;
503
- }
504
- }
505
-
506
- private async detectConfiguredTools(projectPath: string): Promise<string[]> {
507
- const configuredTools: string[] = [];
508
- const allConfigurators = registry.getAll();
509
-
510
- 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);
524
- }
525
- }
526
-
527
- return configuredTools;
528
- }
529
-
530
- 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;
546
- }
547
-
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
-
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
-
664
- private async ensureRootClaudeFile(projectPath: string): Promise<void> {
665
- const rootClaudePath = path.join(projectPath, 'CLAUDE.md');
666
- const instructionsBlock = `<!-- PROMPTER:START -->
667
- # Prompter Instructions
668
-
669
- These instructions are for AI assistants working in this project.
670
-
671
- Always open \`@/prompter/CLAUDE.md\` when the request:
672
- - Mentions planning or proposals (words like proposal, spec, change, plan)
673
- - Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
674
- - Sounds ambiguous and you need the authoritative spec before coding
675
-
676
- Use \`@/prompter/CLAUDE.md\` to learn:
677
- - How to create and apply change proposals
678
- - Spec format and conventions
679
- - Project structure and guidelines
680
- - Show Remaining Tasks
681
-
682
- <!-- PROMPTER:END -->`;
683
-
684
- const rootClaudeExists = await this.fileExists(rootClaudePath);
685
-
686
- if (!rootClaudeExists) {
687
- await fs.writeFile(rootClaudePath, instructionsBlock + '\n', 'utf-8');
688
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan('CLAUDE.md')} in root`);
689
- } else {
690
- const content = await fs.readFile(rootClaudePath, 'utf-8');
691
- const startMarker = '<!-- PROMPTER:START -->';
692
- const endMarker = '<!-- PROMPTER:END -->';
693
- const startIndex = content.indexOf(startMarker);
694
- const endIndex = content.indexOf(endMarker);
695
-
696
- if (startIndex === -1 || endIndex === -1) {
697
- const updatedContent = instructionsBlock + '\n\n' + content;
698
- await fs.writeFile(rootClaudePath, updatedContent, 'utf-8');
699
- console.log(chalk.green('āœ“') + ` Added Prompter instructions to ${chalk.cyan('CLAUDE.md')}`);
700
- } else {
701
- const before = content.substring(0, startIndex);
702
- const after = content.substring(endIndex + endMarker.length);
703
- const updatedContent = before + instructionsBlock + after;
704
- await fs.writeFile(rootClaudePath, updatedContent, 'utf-8');
705
- console.log(chalk.gray(' CLAUDE.md instructions block already exists, updated'));
706
- }
707
- }
708
- }
709
-
710
- private async setupSkills(
711
- projectPath: string,
712
- prompterPath: string,
713
- selectedTools: string[],
714
- selectedSkills: SkillMetadata[]
715
- ): Promise<{ added: string[]; removed: string[] }> {
716
- const result = { added: [] as string[], removed: [] as string[] };
717
-
718
- const installedSkillNames = await this.detectInstalledSkills(prompterPath);
719
- const selectedSkillNames = selectedSkills.map(s => s.name);
720
-
721
- const skillsToAdd = selectedSkills.filter(s => !installedSkillNames.includes(s.name));
722
- const skillsToRemove = installedSkillNames.filter(n => !selectedSkillNames.includes(n));
723
- const skillsToKeep = selectedSkills.filter(s => installedSkillNames.includes(s.name));
724
-
725
- const skillsTargetDir = path.join(prompterPath, 'skills');
726
-
727
- // Remove deselected skills
728
- if (skillsToRemove.length > 0) {
729
- console.log(chalk.blue('\nšŸ—‘ļø Removing skills...\n'));
730
-
731
- for (const skillName of skillsToRemove) {
732
- const staleDir = path.join(skillsTargetDir, skillName);
733
- try {
734
- await fs.rm(staleDir, { recursive: true, force: true });
735
- console.log(chalk.yellow('āœ“') + ` Removed skill ${chalk.cyan(skillName)}`);
736
- result.removed.push(skillName);
737
- } catch {
738
- // ignore
739
- }
740
-
741
- for (const toolId of selectedTools) {
742
- const configurator = registry.get(toolId);
743
- if (!configurator) continue;
744
- const removed = await configurator.removeSkillFiles(projectPath, [skillName]);
745
- for (const file of removed) {
746
- console.log(chalk.yellow('āœ“') + ` Removed ${chalk.cyan(file)}`);
747
- }
748
- }
749
- }
750
- }
751
-
752
- // Install new skills
753
- if (skillsToAdd.length > 0) {
754
- console.log(chalk.blue('\n🧩 Installing skills...\n'));
755
- await fs.mkdir(skillsTargetDir, { recursive: true });
756
-
757
- for (const skill of skillsToAdd) {
758
- const targetDir = path.join(skillsTargetDir, skill.name);
759
- try {
760
- await this.copyDirectory(skill.sourcePath, targetDir);
761
- console.log(chalk.green('āœ“') + ` Installed skill ${chalk.cyan(skill.name)}`);
762
- result.added.push(skill.name);
763
- } catch (error) {
764
- console.log(chalk.red('āœ—') + ` Failed to install skill ${skill.name}: ${error}`);
765
- }
766
- }
767
-
768
- if (selectedTools.length > 0) {
769
- console.log(chalk.blue('\nšŸ“ Creating skill workflow files...\n'));
770
- for (const toolId of selectedTools) {
771
- const configurator = registry.get(toolId);
772
- if (!configurator) continue;
773
- try {
774
- const files = await configurator.generateSkills(projectPath, skillsToAdd);
775
- for (const file of files) {
776
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(file)}`);
777
- }
778
- } catch (error) {
779
- console.log(chalk.red('āœ—') + ` Failed to create skill files for ${toolId}: ${error}`);
780
- }
781
- }
782
- }
783
- }
784
-
785
- // Update kept skills
786
- if (skillsToKeep.length > 0) {
787
- await fs.mkdir(skillsTargetDir, { recursive: true });
788
-
789
- for (const skill of skillsToKeep) {
790
- const targetDir = path.join(skillsTargetDir, skill.name);
791
- try {
792
- await this.copyDirectory(skill.sourcePath, targetDir);
793
- } catch {
794
- // ignore update errors
795
- }
796
- }
797
-
798
- for (const toolId of selectedTools) {
799
- const configurator = registry.get(toolId);
800
- if (!configurator) continue;
801
- try {
802
- await configurator.generateSkills(projectPath, skillsToKeep);
803
- } catch {
804
- // ignore
805
- }
806
- }
807
- }
808
-
809
- return result;
810
- }
811
-
812
- private async detectInstalledSkills(prompterPath: string): Promise<string[]> {
813
- const skillsDir = path.join(prompterPath, 'skills');
814
- const names: string[] = [];
815
-
816
- try {
817
- const entries = await fs.readdir(skillsDir, { withFileTypes: true });
818
- for (const entry of entries) {
819
- if (!entry.isDirectory()) continue;
820
- const skillMdPath = path.join(skillsDir, entry.name, 'SKILL.md');
821
- if (await this.fileExists(skillMdPath)) {
822
- names.push(entry.name);
823
- }
824
- }
825
- } catch {
826
- // skills directory doesn't exist yet
827
- }
828
-
829
- return names;
830
- }
831
-
832
- private async copyDirectory(src: string, dest: string): Promise<void> {
833
- await fs.mkdir(dest, { recursive: true });
834
- const entries = await fs.readdir(src, { withFileTypes: true });
835
-
836
- for (const entry of entries) {
837
- const srcPath = path.join(src, entry.name);
838
- const destPath = path.join(dest, entry.name);
839
-
840
- if (entry.isDirectory()) {
841
- await this.copyDirectory(srcPath, destPath);
842
- } else {
843
- await fs.copyFile(srcPath, destPath);
844
- }
845
- }
846
- }
847
-
848
- private async ensureRootAgentsFile(projectPath: string): Promise<void> {
849
- const rootAgentsPath = path.join(projectPath, 'AGENTS.md');
850
- const instructionsBlock = `<!-- PROMPTER:START -->
851
- # Prompter Instructions
852
-
853
- These instructions are for AI assistants working in this project.
854
-
855
- Always open \`@/prompter/AGENTS.md\` when the request:
856
- - Mentions planning or proposals (words like proposal, spec, change, plan)
857
- - Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
858
- - Sounds ambiguous and you need the authoritative spec before coding
859
-
860
- Use \`@/prompter/AGENTS.md\` to learn:
861
- - How to create and apply change proposals
862
- - Spec format and conventions
863
- - Project structure and guidelines
864
- - Show Remaining Tasks
865
-
866
- <!-- PROMPTER:END -->`;
867
-
868
- const rootAgentsExists = await this.fileExists(rootAgentsPath);
869
-
870
- if (!rootAgentsExists) {
871
- // Create new file with instructions block
872
- await fs.writeFile(rootAgentsPath, instructionsBlock + '\n', 'utf-8');
873
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan('AGENTS.md')} in root`);
874
- } else {
875
- // Read existing file
876
- const content = await fs.readFile(rootAgentsPath, 'utf-8');
877
-
878
- // Check if instructions block already exists
879
- const startMarker = '<!-- PROMPTER:START -->';
880
- const endMarker = '<!-- PROMPTER:END -->';
881
- const startIndex = content.indexOf(startMarker);
882
- const endIndex = content.indexOf(endMarker);
883
-
884
- if (startIndex === -1 || endIndex === -1) {
885
- // Add instructions block at the top
886
- const updatedContent = instructionsBlock + '\n\n' + content;
887
- await fs.writeFile(rootAgentsPath, updatedContent, 'utf-8');
888
- console.log(chalk.green('āœ“') + ` Added Prompter instructions to ${chalk.cyan('AGENTS.md')}`);
889
- } else {
890
- // Replace existing block
891
- const before = content.substring(0, startIndex);
892
- const after = content.substring(endIndex + endMarker.length);
893
- const updatedContent = before + instructionsBlock + after;
894
- await fs.writeFile(rootAgentsPath, updatedContent, 'utf-8');
895
- console.log(chalk.gray(' AGENTS.md instructions block already exists, updated'));
896
- }
897
- }
898
- }
899
- }