@dedesfr/prompter 0.9.0 → 1.1.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 (225) hide show
  1. package/CHANGELOG.md +35 -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.map +1 -1
  6. package/dist/commands/init.js +35 -9
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/login.d.ts +4 -0
  9. package/dist/commands/login.d.ts.map +1 -0
  10. package/dist/commands/login.js +56 -0
  11. package/dist/commands/login.js.map +1 -0
  12. package/dist/commands/logout.d.ts +4 -0
  13. package/dist/commands/logout.d.ts.map +1 -0
  14. package/dist/commands/logout.js +14 -0
  15. package/dist/commands/logout.js.map +1 -0
  16. package/dist/commands/update.d.ts +0 -2
  17. package/dist/commands/update.d.ts.map +1 -1
  18. package/dist/commands/update.js +19 -48
  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/config.d.ts +0 -7
  29. package/dist/core/config.d.ts.map +1 -1
  30. package/dist/core/config.js +0 -128
  31. package/dist/core/config.js.map +1 -1
  32. package/dist/core/registry.d.ts +18 -0
  33. package/dist/core/registry.d.ts.map +1 -0
  34. package/dist/core/registry.js +94 -0
  35. package/dist/core/registry.js.map +1 -0
  36. package/package.json +7 -1
  37. package/AGENTS.md +0 -123
  38. package/CLAUDE.md +0 -17
  39. package/build.js +0 -20
  40. package/convex-setup.md +0 -403
  41. package/dist/core/prompt-templates.d.ts +0 -23
  42. package/dist/core/prompt-templates.d.ts.map +0 -1
  43. package/dist/core/prompt-templates.js +0 -3485
  44. package/dist/core/prompt-templates.js.map +0 -1
  45. package/prompt/ai-humanizer.md +0 -45
  46. package/prompt/api-contract-generator.md +0 -234
  47. package/prompt/apply.md +0 -17
  48. package/prompt/archive.md +0 -21
  49. package/prompt/design-system.md +0 -210
  50. package/prompt/document-explainer.md +0 -149
  51. package/prompt/epic-generator.md +0 -198
  52. package/prompt/epic-single.md +0 -47
  53. package/prompt/erd-generator.md +0 -130
  54. package/prompt/fsd-generator.md +0 -157
  55. package/prompt/prd-agent-generator.md +0 -147
  56. package/prompt/prd-generator.md +0 -195
  57. package/prompt/product-brief.md +0 -289
  58. package/prompt/proposal.md +0 -22
  59. package/prompt/qa-test-scenario.md +0 -133
  60. package/prompt/skill-creator.md +0 -350
  61. package/prompt/story-generator.md +0 -278
  62. package/prompt/story-single.md +0 -70
  63. package/prompt/tdd-generator.md +0 -294
  64. package/prompt/tdd-lite-generator.md +0 -224
  65. package/prompt/wireframe-generator.md +0 -219
  66. package/skills/ai-context-generator/SKILL.md +0 -54
  67. package/skills/ai-context-generator/references/AGENTS.template.md +0 -83
  68. package/skills/ai-context-generator/references/CLAUDE.template.md +0 -39
  69. package/skills/ai-context-generator/references/behavioral-guidelines.md +0 -71
  70. package/skills/ai-context-generator/references/discovery-checklist.md +0 -40
  71. package/skills/ai-context-generator/references/examples/AGENTS.good.md +0 -103
  72. package/skills/ai-context-generator/references/extraction-checklist.md +0 -23
  73. package/skills/ai-context-generator/references/overlays/laravel.md +0 -44
  74. package/skills/ai-humanizer/SKILL.md +0 -50
  75. package/skills/api-contract-generator/SKILL.md +0 -243
  76. package/skills/apply/SKILL.md +0 -23
  77. package/skills/archive/SKILL.md +0 -27
  78. package/skills/cerebro/SKILL.md +0 -187
  79. package/skills/cerebro/references/agents.md +0 -213
  80. package/skills/code-review/SKILL.md +0 -373
  81. package/skills/code-review/assets/report-template-agent.md +0 -212
  82. package/skills/code-review/assets/report-template-compact.md +0 -81
  83. package/skills/code-review/assets/report-template-full.md +0 -264
  84. package/skills/code-review/assets/report-template-human.md +0 -168
  85. package/skills/code-review/references/universal-patterns.md +0 -495
  86. package/skills/design-md/README.md +0 -34
  87. package/skills/design-md/SKILL.md +0 -172
  88. package/skills/design-md/examples/DESIGN.md +0 -154
  89. package/skills/design-system/SKILL.md +0 -216
  90. package/skills/design-system-generator/SKILL.md +0 -324
  91. package/skills/design-system-generator/assets/design-system-template.md +0 -348
  92. package/skills/design-system-generator/references/extraction-patterns.md +0 -321
  93. package/skills/doc-builder/SKILL.md +0 -115
  94. package/skills/doc-builder/references/ui-patterns.md +0 -394
  95. package/skills/document-explainer/SKILL.md +0 -155
  96. package/skills/document-translator/SKILL.md +0 -58
  97. package/skills/enhance/SKILL.md +0 -47
  98. package/skills/enhance-prompt/README.md +0 -34
  99. package/skills/enhance-prompt/SKILL.md +0 -204
  100. package/skills/enhance-prompt/references/KEYWORDS.md +0 -114
  101. package/skills/epic-generator/SKILL.md +0 -204
  102. package/skills/epic-single/SKILL.md +0 -63
  103. package/skills/erd-generator/SKILL.md +0 -138
  104. package/skills/feature-planner/SKILL.md +0 -305
  105. package/skills/feature-planner/assets/implementation-plan-template.md +0 -85
  106. package/skills/frontend-design/LICENSE.txt +0 -177
  107. package/skills/frontend-design/SKILL.md +0 -42
  108. package/skills/fsd-generator/SKILL.md +0 -163
  109. package/skills/gamma-builder/SKILL.md +0 -134
  110. package/skills/laravel-code-review/SKILL.md +0 -383
  111. package/skills/laravel-code-review/assets/report-template-agent.md +0 -195
  112. package/skills/laravel-code-review/assets/report-template-compact.md +0 -79
  113. package/skills/laravel-code-review/assets/report-template-full.md +0 -253
  114. package/skills/laravel-code-review/assets/report-template-human.md +0 -159
  115. package/skills/laravel-code-review/references/laravel-patterns.md +0 -571
  116. package/skills/laravel-code-review/references/php84-features.md +0 -442
  117. package/skills/mcp-builder/LICENSE.txt +0 -202
  118. package/skills/mcp-builder/SKILL.md +0 -236
  119. package/skills/mcp-builder/reference/evaluation.md +0 -602
  120. package/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  121. package/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  122. package/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  123. package/skills/mcp-builder/scripts/connections.py +0 -151
  124. package/skills/mcp-builder/scripts/evaluation.py +0 -373
  125. package/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  126. package/skills/mcp-builder/scripts/requirements.txt +0 -2
  127. package/skills/meeting-notes/SKILL.md +0 -159
  128. package/skills/meeting-notes/evals/evals.json +0 -23
  129. package/skills/prd-agent-generator/SKILL.md +0 -132
  130. package/skills/prd-generator/SKILL.md +0 -211
  131. package/skills/product-brief/SKILL.md +0 -141
  132. package/skills/project-orchestrator/SKILL.md +0 -487
  133. package/skills/project-orchestrator/assets/caddy-vps-setup.md +0 -180
  134. package/skills/project-orchestrator/assets/plan-summary-template.md +0 -159
  135. package/skills/prompter-specs/SKILL.md +0 -115
  136. package/skills/prompter-workflow/SKILL.md +0 -166
  137. package/skills/prompter-workflow/evals/evals.json +0 -89
  138. package/skills/proposal/SKILL.md +0 -28
  139. package/skills/qa-test-scenario/SKILL.md +0 -149
  140. package/skills/skill-creator/SKILL.md +0 -173
  141. package/skills/sph-generator/SKILL.md +0 -488
  142. package/skills/story-generator/SKILL.md +0 -285
  143. package/skills/story-single/SKILL.md +0 -86
  144. package/skills/tdd-generator/SKILL.md +0 -300
  145. package/skills/tdd-lite-generator/SKILL.md +0 -230
  146. package/skills/ui-ux-pro/SKILL.md +0 -199
  147. package/skills/ui-ux-pro/assets/design-spec-template.md +0 -173
  148. package/skills/ui-ux-pro/references/component-patterns.md +0 -255
  149. package/skills/ui-ux-pro/references/design-principles.md +0 -167
  150. package/skills/wireframe-generator/SKILL.md +0 -227
  151. package/src/cli/index.ts +0 -223
  152. package/src/commands/archive.ts +0 -302
  153. package/src/commands/change.ts +0 -292
  154. package/src/commands/config.ts +0 -233
  155. package/src/commands/guide.ts +0 -50
  156. package/src/commands/init.ts +0 -597
  157. package/src/commands/list.ts +0 -194
  158. package/src/commands/show.ts +0 -138
  159. package/src/commands/spec.ts +0 -251
  160. package/src/commands/update.ts +0 -129
  161. package/src/commands/upgrade.ts +0 -30
  162. package/src/commands/validate.ts +0 -326
  163. package/src/core/artifact-graph/graph.ts +0 -167
  164. package/src/core/artifact-graph/index.ts +0 -44
  165. package/src/core/artifact-graph/instruction-loader.ts +0 -302
  166. package/src/core/artifact-graph/resolver.ts +0 -226
  167. package/src/core/artifact-graph/schema.ts +0 -124
  168. package/src/core/artifact-graph/state.ts +0 -64
  169. package/src/core/artifact-graph/types.ts +0 -65
  170. package/src/core/completions/command-registry.ts +0 -382
  171. package/src/core/completions/completion-provider.ts +0 -128
  172. package/src/core/completions/generators/bash-generator.ts +0 -191
  173. package/src/core/completions/generators/fish-generator.ts +0 -188
  174. package/src/core/completions/generators/powershell-generator.ts +0 -223
  175. package/src/core/completions/generators/zsh-generator.ts +0 -281
  176. package/src/core/completions/templates/bash-templates.ts +0 -24
  177. package/src/core/completions/templates/fish-templates.ts +0 -40
  178. package/src/core/completions/templates/powershell-templates.ts +0 -25
  179. package/src/core/completions/templates/zsh-templates.ts +0 -36
  180. package/src/core/completions/types.ts +0 -90
  181. package/src/core/config-schema.ts +0 -230
  182. package/src/core/config.ts +0 -181
  183. package/src/core/configurators/slash/antigravity.ts +0 -10
  184. package/src/core/configurators/slash/base.ts +0 -109
  185. package/src/core/configurators/slash/claude.ts +0 -10
  186. package/src/core/configurators/slash/codex.ts +0 -10
  187. package/src/core/configurators/slash/droid.ts +0 -10
  188. package/src/core/configurators/slash/forge.ts +0 -10
  189. package/src/core/configurators/slash/github-copilot.ts +0 -10
  190. package/src/core/configurators/slash/index.ts +0 -10
  191. package/src/core/configurators/slash/kilocode.ts +0 -10
  192. package/src/core/configurators/slash/opencode.ts +0 -10
  193. package/src/core/configurators/slash/registry.ts +0 -51
  194. package/src/core/converters/json-converter.ts +0 -62
  195. package/src/core/global-config.ts +0 -136
  196. package/src/core/parsers/change-parser.ts +0 -234
  197. package/src/core/parsers/markdown-parser.ts +0 -237
  198. package/src/core/parsers/requirement-blocks.ts +0 -234
  199. package/src/core/prompt-templates.ts +0 -3504
  200. package/src/core/schemas/base.schema.ts +0 -20
  201. package/src/core/schemas/change.schema.ts +0 -42
  202. package/src/core/schemas/index.ts +0 -20
  203. package/src/core/schemas/spec.schema.ts +0 -17
  204. package/src/core/skill-discovery.ts +0 -68
  205. package/src/core/specs-apply.ts +0 -483
  206. package/src/core/styles/palette.ts +0 -8
  207. package/src/core/templates/agents-template.ts +0 -459
  208. package/src/core/templates/claude-template.ts +0 -2
  209. package/src/core/templates/index.ts +0 -3
  210. package/src/core/templates/project-template.ts +0 -32
  211. package/src/core/validation/constants.ts +0 -48
  212. package/src/core/validation/types.ts +0 -19
  213. package/src/core/validation/validator.ts +0 -449
  214. package/src/core/view.ts +0 -219
  215. package/src/index.ts +0 -1
  216. package/src/utils/change-metadata.ts +0 -171
  217. package/src/utils/change-utils.ts +0 -131
  218. package/src/utils/file-system.ts +0 -252
  219. package/src/utils/index.ts +0 -12
  220. package/src/utils/interactive.ts +0 -29
  221. package/src/utils/item-discovery.ts +0 -66
  222. package/src/utils/match.ts +0 -26
  223. package/src/utils/shell-detection.ts +0 -62
  224. package/src/utils/task-progress.ts +0 -43
  225. package/tsconfig.json +0 -28
@@ -1,597 +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, PrompterConfig } from '../core/config.js';
7
- import { projectTemplate, agentsTemplate, claudeTemplate } from '../core/templates/index.js';
8
- import { registry } from '../core/configurators/slash/index.js';
9
- import { discoverSkills, SkillMetadata } from '../core/skill-discovery.js';
10
-
11
- interface InitOptions {
12
- tools?: string[];
13
- skills?: string[];
14
- noInteractive?: boolean;
15
- }
16
-
17
- export class InitCommand {
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[] {
23
- const categories = [
24
- {
25
- name: 'šŸ“‹ Planning & Strategy',
26
- skills: ['project-orchestrator', 'feature-planner', 'prd-generator', 'prd-agent-generator', 'product-brief']
27
- },
28
- {
29
- name: 'šŸŽÆ Agile & Backlog',
30
- skills: ['epic-single', 'epic-generator', 'story-single', 'story-generator']
31
- },
32
- {
33
- name: 'šŸ“ Specification & Architecture',
34
- skills: ['fsd-generator', 'tdd-generator', 'tdd-lite-generator', 'erd-generator', 'api-contract-generator']
35
- },
36
- {
37
- name: 'šŸŽØ Design & UI/UX',
38
- skills: ['ui-ux-pro', 'design-system-generator', 'design-system', 'wireframe-generator', 'design-md', 'frontend-design']
39
- },
40
- {
41
- name: 'āš™ļø Development & Code Review',
42
- skills: ['code-review', 'laravel-code-review', 'mcp-builder', 'skill-creator']
43
- },
44
- {
45
- name: 'āœ… Testing & QA',
46
- skills: ['qa-test-scenario']
47
- },
48
- {
49
- name: '⚔ Prompter Workflow',
50
- skills: ['prompter-workflow', 'prompter-specs', 'proposal', 'apply', 'archive']
51
- },
52
- {
53
- name: 'šŸ“ Documentation',
54
- skills: ['doc-builder', 'document-translator', 'document-explainer', 'ai-context-generator', 'meeting-notes', 'sph-generator']
55
- },
56
- {
57
- name: '✨ Content & Productivity',
58
- skills: ['enhance', 'enhance-prompt', 'ai-humanizer', 'gamma-builder', 'cerebro']
59
- }
60
- ];
61
-
62
- const categorized = new Set<string>();
63
- const choices: any[] = [];
64
-
65
- for (const category of categories) {
66
- const skillsInCategory = category.skills
67
- .map(name => availableSkills.find(s => s.name === name))
68
- .filter((s): s is SkillMetadata => !!s);
69
-
70
- if (skillsInCategory.length === 0) continue;
71
-
72
- choices.push(new Separator(chalk.bold.cyan(category.name)));
73
- for (const skill of skillsInCategory) {
74
- categorized.add(skill.name);
75
- choices.push({
76
- name: ` ${skill.name} ${chalk.gray('- ' + this.truncateDescription(skill.description))}`,
77
- value: skill.name,
78
- checked: currentSkillNames.includes(skill.name)
79
- });
80
- }
81
- }
82
-
83
- // Uncategorized skills
84
- const uncategorized = availableSkills.filter(s => !categorized.has(s.name));
85
- if (uncategorized.length > 0) {
86
- choices.push(new Separator(chalk.bold.cyan('šŸ”§ Other')));
87
- for (const skill of uncategorized) {
88
- choices.push({
89
- name: ` ${skill.name} ${chalk.gray('- ' + this.truncateDescription(skill.description))}`,
90
- value: skill.name,
91
- checked: currentSkillNames.includes(skill.name)
92
- });
93
- }
94
- }
95
-
96
- return choices;
97
- }
98
-
99
- async execute(options: InitOptions = {}): Promise<void> {
100
- const projectPath = process.cwd();
101
- const isReInitialization = await PrompterConfig.prompterDirExists(projectPath);
102
-
103
- // Display ASCII art banner for initial setup
104
- if (!isReInitialization) {
105
- console.log(chalk.cyan(`
106
- ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ
107
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
108
- ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ
109
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
110
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
111
- `));
112
- console.log(chalk.white.bold('Welcome to Prompter!\n'));
113
- }
114
-
115
- if (isReInitialization) {
116
- console.log(chalk.blue('\nšŸ”„ Re-configuring Prompter tools...\n'));
117
- } else {
118
- console.log(chalk.blue('šŸš€ Initializing Prompter...\n'));
119
- }
120
-
121
- // Detect currently configured tools if re-initializing
122
- let currentTools: string[] = [];
123
- if (isReInitialization) {
124
- currentTools = await this.detectConfiguredTools(projectPath);
125
- if (currentTools.length > 0) {
126
- console.log(chalk.gray('Currently configured tools: ') + chalk.cyan(currentTools.map(t => {
127
- const tool = SUPPORTED_TOOLS.find(st => st.value === t);
128
- return tool ? tool.name : t;
129
- }).join(', ')));
130
- console.log();
131
- }
132
- }
133
-
134
- // Select tools
135
- let selectedTools: string[] = [];
136
-
137
- if (options.tools && options.tools.length > 0) {
138
- // Handle comma-separated values in a single string or array of strings
139
- selectedTools = options.tools.flatMap(tool => tool.split(',').map(t => t.trim()));
140
- } else if (!options.noInteractive) {
141
- try {
142
- const message = isReInitialization
143
- ? 'Select AI tools to configure (check/uncheck to add/remove):'
144
- : 'Select AI tools to configure:';
145
-
146
- selectedTools = await checkbox({
147
- message,
148
- choices: SUPPORTED_TOOLS.map(tool => ({
149
- name: tool.name,
150
- value: tool.value,
151
- checked: isReInitialization
152
- ? currentTools.includes(tool.value)
153
- : tool.value === 'antigravity' // Default check Antigravity for new init
154
- }))
155
- });
156
- } catch (error) {
157
- // User cancelled
158
- console.log(chalk.yellow(isReInitialization ? '\nRe-configuration cancelled.' : '\nInitialization cancelled.'));
159
- return;
160
- }
161
- } else if (isReInitialization && selectedTools.length === 0) {
162
- // In non-interactive re-init without tools specified, keep current tools
163
- selectedTools = currentTools;
164
- }
165
-
166
- // Select skills — resolve from the package directory, not the user's project
167
- // dist/commands/init.js → go up two levels to reach the package root
168
- const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
169
- const availableSkills = await discoverSkills(path.join(packageDir, 'skills'));
170
- let selectedSkills: SkillMetadata[] = [];
171
-
172
- if (options.skills && options.skills.length > 0) {
173
- const requestedNames = options.skills.flatMap(s => s.split(',').map(s => s.trim()));
174
- selectedSkills = availableSkills.filter(s => requestedNames.includes(s.name));
175
- } else if (!options.noInteractive && availableSkills.length > 0) {
176
- try {
177
- const prompterPathForDetection = path.join(projectPath, PROMPTER_DIR);
178
- const currentSkillNames = await this.detectInstalledSkills(prompterPathForDetection);
179
-
180
- const selectedSkillNames = await checkbox({
181
- message: 'Select skills to install:',
182
- choices: this.getCategorizedSkillChoices(availableSkills, currentSkillNames),
183
- pageSize: 20
184
- });
185
- selectedSkills = availableSkills.filter(s => selectedSkillNames.includes(s.name));
186
- } catch (error) {
187
- // User cancelled
188
- console.log(chalk.yellow(isReInitialization ? '\nRe-configuration cancelled.' : '\nInitialization cancelled.'));
189
- return;
190
- }
191
- }
192
-
193
- // Create or ensure prompter directory
194
- const prompterPath = await PrompterConfig.ensurePrompterDir(projectPath);
195
- if (!isReInitialization) {
196
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/')}`);
197
- }
198
-
199
- // Create project.md if not exists
200
- const projectMdPath = path.join(prompterPath, 'project.md');
201
- const projectMdExists = await this.fileExists(projectMdPath);
202
- if (!projectMdExists) {
203
- try {
204
- if (!projectTemplate) {
205
- throw new Error('project.md template is undefined');
206
- }
207
- await fs.writeFile(projectMdPath, projectTemplate, 'utf-8');
208
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/project.md')}`);
209
- } catch (error) {
210
- console.error(chalk.red('āœ—') + ` Failed to create project.md: ${error}`);
211
- }
212
- } else if (isReInitialization) {
213
- console.log(chalk.gray(' project.md already exists, keeping it'));
214
- }
215
-
216
- // Create or update AGENTS.md for universal support
217
- const agentsMdPath = path.join(prompterPath, 'AGENTS.md');
218
- const agentsExists = await this.fileExists(agentsMdPath);
219
- try {
220
- if (!agentsTemplate) {
221
- throw new Error('AGENTS.md template is undefined');
222
- }
223
- await fs.writeFile(agentsMdPath, agentsTemplate, 'utf-8');
224
- if (!agentsExists) {
225
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/AGENTS.md')}`);
226
- } else if (isReInitialization) {
227
- console.log(chalk.green('āœ“') + ` Updated ${chalk.cyan(PROMPTER_DIR + '/AGENTS.md')}`);
228
- }
229
- } catch (error) {
230
- console.error(chalk.red('āœ—') + ` Failed to ${agentsExists ? 'update' : 'create'} AGENTS.md: ${error}`);
231
- }
232
-
233
- // Create or update CLAUDE.md for Claude Code support
234
- const claudeMdPath = path.join(prompterPath, 'CLAUDE.md');
235
- const claudeExists = await this.fileExists(claudeMdPath);
236
- try {
237
- if (!claudeTemplate) {
238
- throw new Error('CLAUDE.md template is undefined');
239
- }
240
- await fs.writeFile(claudeMdPath, claudeTemplate, 'utf-8');
241
- if (!claudeExists) {
242
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(PROMPTER_DIR + '/CLAUDE.md')}`);
243
- } else if (isReInitialization) {
244
- console.log(chalk.green('āœ“') + ` Updated ${chalk.cyan(PROMPTER_DIR + '/CLAUDE.md')}`);
245
- }
246
- } catch (error) {
247
- console.error(chalk.red('āœ—') + ` Failed to ${claudeExists ? 'update' : 'create'} CLAUDE.md: ${error}`);
248
- }
249
-
250
- // Ensure root AGENTS.md has Prompter instructions
251
- await this.ensureRootAgentsFile(projectPath);
252
-
253
- // Ensure root CLAUDE.md has Prompter instructions
254
- await this.ensureRootClaudeFile(projectPath);
255
-
256
- // Handle tool changes
257
- const toolsToAdd = selectedTools.filter(t => !currentTools.includes(t));
258
- const toolsToRemove = currentTools.filter(t => !selectedTools.includes(t));
259
- const toolsToKeep = selectedTools.filter(t => currentTools.includes(t));
260
-
261
- // Remove old tool files
262
- if (toolsToRemove.length > 0) {
263
- console.log(chalk.blue('\nšŸ—‘ļø Removing workflow files...\n'));
264
- for (const toolId of toolsToRemove) {
265
- const configurator = registry.get(toolId);
266
- if (configurator) {
267
- try {
268
- const files = await this.removeToolFiles(projectPath, configurator);
269
- for (const file of files) {
270
- console.log(chalk.yellow('āœ“') + ` Removed ${chalk.cyan(file)}`);
271
- }
272
- } catch (error) {
273
- console.log(chalk.red('āœ—') + ` Failed to remove files for ${toolId}: ${error}`);
274
- }
275
- }
276
- }
277
- }
278
-
279
- // Show kept tools
280
- if (isReInitialization && toolsToKeep.length > 0 && (toolsToAdd.length > 0 || toolsToRemove.length > 0)) {
281
- console.log(chalk.blue('\n✨ Keeping existing tools:\n'));
282
- for (const toolId of toolsToKeep) {
283
- const tool = SUPPORTED_TOOLS.find(t => t.value === toolId);
284
- if (tool) {
285
- console.log(chalk.gray(' • ') + chalk.cyan(tool.name));
286
- }
287
- }
288
- }
289
-
290
- // --- Skills setup ---
291
- const skillChanges = await this.setupSkills(projectPath, prompterPath, selectedTools, selectedSkills);
292
-
293
- // Success message
294
- if (isReInitialization) {
295
- console.log(chalk.green('\nāœ… Prompter tools updated successfully!\n'));
296
- if (toolsToAdd.length > 0 || toolsToRemove.length > 0 || skillChanges.added.length > 0 || skillChanges.removed.length > 0) {
297
- console.log(chalk.blue('Summary:'));
298
- if (toolsToAdd.length > 0) {
299
- console.log(chalk.green(' Tools Added: ') + toolsToAdd.map(t => {
300
- const tool = SUPPORTED_TOOLS.find(st => st.value === t);
301
- return tool ? tool.name : t;
302
- }).join(', '));
303
- }
304
- if (toolsToRemove.length > 0) {
305
- console.log(chalk.yellow(' Tools Removed: ') + toolsToRemove.map(t => {
306
- const tool = SUPPORTED_TOOLS.find(st => st.value === t);
307
- return tool ? tool.name : t;
308
- }).join(', '));
309
- }
310
- if (skillChanges.added.length > 0) {
311
- console.log(chalk.green(' Skills Added: ') + skillChanges.added.join(', '));
312
- }
313
- if (skillChanges.removed.length > 0) {
314
- console.log(chalk.yellow(' Skills Removed: ') + skillChanges.removed.join(', '));
315
- }
316
- console.log();
317
- } else {
318
- console.log(chalk.gray(' No changes made.\n'));
319
- }
320
- } else {
321
- console.log(chalk.green('\nāœ… Prompter initialized successfully!\n'));
322
- if (skillChanges.added.length > 0) {
323
- console.log(chalk.gray(`Installed ${skillChanges.added.length} skill(s).\n`));
324
- }
325
- console.log(chalk.gray('Run `prompter guide` for next steps.\n'));
326
- }
327
- }
328
-
329
- private async fileExists(filePath: string): Promise<boolean> {
330
- try {
331
- await fs.access(filePath);
332
- return true;
333
- } catch {
334
- return false;
335
- }
336
- }
337
-
338
- private async detectConfiguredTools(projectPath: string): Promise<string[]> {
339
- const configuredTools: string[] = [];
340
- const allConfigurators = registry.getAll();
341
-
342
- for (const configurator of allConfigurators) {
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
349
- }
350
- }
351
-
352
- return configuredTools;
353
- }
354
-
355
- private async removeToolFiles(projectPath: string, configurator: any): Promise<string[]> {
356
- await configurator.removeAllDeployedSkills(projectPath);
357
- return [configurator.getSkillsRootDir() + '/'];
358
- }
359
-
360
-
361
-
362
- private async ensureRootClaudeFile(projectPath: string): Promise<void> {
363
- const rootClaudePath = path.join(projectPath, 'CLAUDE.md');
364
- const instructionsBlock = `<!-- PROMPTER:START -->
365
- # Prompter Instructions
366
-
367
- These instructions are for AI assistants working in this project.
368
-
369
- Always open \`@/prompter/CLAUDE.md\` when the request:
370
- - Mentions planning or proposals (words like proposal, spec, change, plan)
371
- - Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
372
- - Sounds ambiguous and you need the authoritative spec before coding
373
-
374
- Use \`@/prompter/CLAUDE.md\` to learn:
375
- - How to create and apply change proposals
376
- - Spec format and conventions
377
- - Project structure and guidelines
378
- - Show Remaining Tasks
379
-
380
- <!-- PROMPTER:END -->`;
381
-
382
- const rootClaudeExists = await this.fileExists(rootClaudePath);
383
-
384
- if (!rootClaudeExists) {
385
- await fs.writeFile(rootClaudePath, instructionsBlock + '\n', 'utf-8');
386
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan('CLAUDE.md')} in root`);
387
- } else {
388
- const content = await fs.readFile(rootClaudePath, 'utf-8');
389
- const startMarker = '<!-- PROMPTER:START -->';
390
- const endMarker = '<!-- PROMPTER:END -->';
391
- const startIndex = content.indexOf(startMarker);
392
- const endIndex = content.indexOf(endMarker);
393
-
394
- if (startIndex === -1 || endIndex === -1) {
395
- const updatedContent = instructionsBlock + '\n\n' + content;
396
- await fs.writeFile(rootClaudePath, updatedContent, 'utf-8');
397
- console.log(chalk.green('āœ“') + ` Added Prompter instructions to ${chalk.cyan('CLAUDE.md')}`);
398
- } else {
399
- const before = content.substring(0, startIndex);
400
- const after = content.substring(endIndex + endMarker.length);
401
- const updatedContent = before + instructionsBlock + after;
402
- await fs.writeFile(rootClaudePath, updatedContent, 'utf-8');
403
- console.log(chalk.gray(' CLAUDE.md instructions block already exists, updated'));
404
- }
405
- }
406
- }
407
-
408
- private async setupSkills(
409
- projectPath: string,
410
- prompterPath: string,
411
- selectedTools: string[],
412
- selectedSkills: SkillMetadata[]
413
- ): Promise<{ added: string[]; removed: string[] }> {
414
- const result = { added: [] as string[], removed: [] as string[] };
415
-
416
- const installedSkillNames = await this.detectInstalledSkills(prompterPath);
417
- const selectedSkillNames = selectedSkills.map(s => s.name);
418
-
419
- const skillsToAdd = selectedSkills.filter(s => !installedSkillNames.includes(s.name));
420
- const skillsToRemove = installedSkillNames.filter(n => !selectedSkillNames.includes(n));
421
- const skillsToKeep = selectedSkills.filter(s => installedSkillNames.includes(s.name));
422
-
423
- const skillsTargetDir = path.join(prompterPath, 'skills');
424
-
425
- // Remove deselected skills
426
- if (skillsToRemove.length > 0) {
427
- console.log(chalk.blue('\nšŸ—‘ļø Removing skills...\n'));
428
-
429
- for (const skillName of skillsToRemove) {
430
- const staleDir = path.join(skillsTargetDir, skillName);
431
- try {
432
- await fs.rm(staleDir, { recursive: true, force: true });
433
- console.log(chalk.yellow('āœ“') + ` Removed skill ${chalk.cyan(skillName)}`);
434
- result.removed.push(skillName);
435
- } catch {
436
- // ignore
437
- }
438
-
439
- for (const toolId of selectedTools) {
440
- const configurator = registry.get(toolId);
441
- if (!configurator) continue;
442
- const removed = await configurator.removeSkillFiles(projectPath, [skillName]);
443
- for (const file of removed) {
444
- console.log(chalk.yellow('āœ“') + ` Removed ${chalk.cyan(file)}`);
445
- }
446
- }
447
- }
448
- }
449
-
450
- // Install new skills
451
- if (skillsToAdd.length > 0) {
452
- console.log(chalk.blue('\n🧩 Installing skills...\n'));
453
- await fs.mkdir(skillsTargetDir, { recursive: true });
454
-
455
- for (const skill of skillsToAdd) {
456
- const targetDir = path.join(skillsTargetDir, skill.name);
457
- try {
458
- await this.copyDirectory(skill.sourcePath, targetDir);
459
- console.log(chalk.green('āœ“') + ` Installed skill ${chalk.cyan(skill.name)}`);
460
- result.added.push(skill.name);
461
- } catch (error) {
462
- console.log(chalk.red('āœ—') + ` Failed to install skill ${skill.name}: ${error}`);
463
- }
464
- }
465
-
466
- if (selectedTools.length > 0) {
467
- console.log(chalk.blue('\nšŸ“ Creating skill workflow files...\n'));
468
- for (const toolId of selectedTools) {
469
- const configurator = registry.get(toolId);
470
- if (!configurator) continue;
471
- try {
472
- const files = await configurator.generateSkills(projectPath, skillsToAdd);
473
- for (const file of files) {
474
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan(file)}`);
475
- }
476
- } catch (error) {
477
- console.log(chalk.red('āœ—') + ` Failed to create skill files for ${toolId}: ${error}`);
478
- }
479
- }
480
- }
481
- }
482
-
483
- // Update kept skills
484
- if (skillsToKeep.length > 0) {
485
- await fs.mkdir(skillsTargetDir, { recursive: true });
486
-
487
- for (const skill of skillsToKeep) {
488
- const targetDir = path.join(skillsTargetDir, skill.name);
489
- try {
490
- await this.copyDirectory(skill.sourcePath, targetDir);
491
- } catch {
492
- // ignore update errors
493
- }
494
- }
495
-
496
- for (const toolId of selectedTools) {
497
- const configurator = registry.get(toolId);
498
- if (!configurator) continue;
499
- try {
500
- await configurator.generateSkills(projectPath, skillsToKeep);
501
- } catch {
502
- // ignore
503
- }
504
- }
505
- }
506
-
507
- return result;
508
- }
509
-
510
- private async detectInstalledSkills(prompterPath: string): Promise<string[]> {
511
- const skillsDir = path.join(prompterPath, 'skills');
512
- const names: string[] = [];
513
-
514
- try {
515
- const entries = await fs.readdir(skillsDir, { withFileTypes: true });
516
- for (const entry of entries) {
517
- if (!entry.isDirectory()) continue;
518
- const skillMdPath = path.join(skillsDir, entry.name, 'SKILL.md');
519
- if (await this.fileExists(skillMdPath)) {
520
- names.push(entry.name);
521
- }
522
- }
523
- } catch {
524
- // skills directory doesn't exist yet
525
- }
526
-
527
- return names;
528
- }
529
-
530
- private async copyDirectory(src: string, dest: string): Promise<void> {
531
- await fs.mkdir(dest, { recursive: true });
532
- const entries = await fs.readdir(src, { withFileTypes: true });
533
-
534
- for (const entry of entries) {
535
- const srcPath = path.join(src, entry.name);
536
- const destPath = path.join(dest, entry.name);
537
-
538
- if (entry.isDirectory()) {
539
- await this.copyDirectory(srcPath, destPath);
540
- } else {
541
- await fs.copyFile(srcPath, destPath);
542
- }
543
- }
544
- }
545
-
546
- private async ensureRootAgentsFile(projectPath: string): Promise<void> {
547
- const rootAgentsPath = path.join(projectPath, 'AGENTS.md');
548
- const instructionsBlock = `<!-- PROMPTER:START -->
549
- # Prompter Instructions
550
-
551
- These instructions are for AI assistants working in this project.
552
-
553
- Always open \`@/prompter/AGENTS.md\` when the request:
554
- - Mentions planning or proposals (words like proposal, spec, change, plan)
555
- - Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
556
- - Sounds ambiguous and you need the authoritative spec before coding
557
-
558
- Use \`@/prompter/AGENTS.md\` to learn:
559
- - How to create and apply change proposals
560
- - Spec format and conventions
561
- - Project structure and guidelines
562
- - Show Remaining Tasks
563
-
564
- <!-- PROMPTER:END -->`;
565
-
566
- const rootAgentsExists = await this.fileExists(rootAgentsPath);
567
-
568
- if (!rootAgentsExists) {
569
- // Create new file with instructions block
570
- await fs.writeFile(rootAgentsPath, instructionsBlock + '\n', 'utf-8');
571
- console.log(chalk.green('āœ“') + ` Created ${chalk.cyan('AGENTS.md')} in root`);
572
- } else {
573
- // Read existing file
574
- const content = await fs.readFile(rootAgentsPath, 'utf-8');
575
-
576
- // Check if instructions block already exists
577
- const startMarker = '<!-- PROMPTER:START -->';
578
- const endMarker = '<!-- PROMPTER:END -->';
579
- const startIndex = content.indexOf(startMarker);
580
- const endIndex = content.indexOf(endMarker);
581
-
582
- if (startIndex === -1 || endIndex === -1) {
583
- // Add instructions block at the top
584
- const updatedContent = instructionsBlock + '\n\n' + content;
585
- await fs.writeFile(rootAgentsPath, updatedContent, 'utf-8');
586
- console.log(chalk.green('āœ“') + ` Added Prompter instructions to ${chalk.cyan('AGENTS.md')}`);
587
- } else {
588
- // Replace existing block
589
- const before = content.substring(0, startIndex);
590
- const after = content.substring(endIndex + endMarker.length);
591
- const updatedContent = before + instructionsBlock + after;
592
- await fs.writeFile(rootAgentsPath, updatedContent, 'utf-8');
593
- console.log(chalk.gray(' AGENTS.md instructions block already exists, updated'));
594
- }
595
- }
596
- }
597
- }