@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.
- package/CHANGELOG.md +70 -0
- package/README.md +105 -77
- package/dist/cli/index.js +25 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +1 -7
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +60 -299
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +56 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +4 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +14 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +31 -41
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/whoami.d.ts +4 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +42 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/core/auth-store.d.ts +10 -0
- package/dist/core/auth-store.d.ts.map +1 -0
- package/dist/core/auth-store.js +39 -0
- package/dist/core/auth-store.js.map +1 -0
- package/dist/core/configurators/slash/antigravity.d.ts +2 -5
- package/dist/core/configurators/slash/antigravity.d.ts.map +1 -1
- package/dist/core/configurators/slash/antigravity.js +2 -57
- package/dist/core/configurators/slash/antigravity.js.map +1 -1
- package/dist/core/configurators/slash/base.d.ts +6 -18
- package/dist/core/configurators/slash/base.d.ts.map +1 -1
- package/dist/core/configurators/slash/base.js +8 -77
- package/dist/core/configurators/slash/base.js.map +1 -1
- package/dist/core/configurators/slash/claude.d.ts +2 -5
- package/dist/core/configurators/slash/claude.d.ts.map +1 -1
- package/dist/core/configurators/slash/claude.js +2 -57
- package/dist/core/configurators/slash/claude.js.map +1 -1
- package/dist/core/configurators/slash/codex.d.ts +2 -5
- package/dist/core/configurators/slash/codex.d.ts.map +1 -1
- package/dist/core/configurators/slash/codex.js +2 -57
- package/dist/core/configurators/slash/codex.js.map +1 -1
- package/dist/core/configurators/slash/droid.d.ts +2 -5
- package/dist/core/configurators/slash/droid.d.ts.map +1 -1
- package/dist/core/configurators/slash/droid.js +2 -32
- package/dist/core/configurators/slash/droid.js.map +1 -1
- package/dist/core/configurators/slash/forge.d.ts +2 -5
- package/dist/core/configurators/slash/forge.d.ts.map +1 -1
- package/dist/core/configurators/slash/forge.js +2 -32
- package/dist/core/configurators/slash/forge.js.map +1 -1
- package/dist/core/configurators/slash/github-copilot.d.ts +2 -7
- package/dist/core/configurators/slash/github-copilot.d.ts.map +1 -1
- package/dist/core/configurators/slash/github-copilot.js +2 -96
- package/dist/core/configurators/slash/github-copilot.js.map +1 -1
- package/dist/core/configurators/slash/index.d.ts +1 -1
- package/dist/core/configurators/slash/index.d.ts.map +1 -1
- package/dist/core/configurators/slash/index.js +1 -1
- package/dist/core/configurators/slash/index.js.map +1 -1
- package/dist/core/configurators/slash/kilocode.d.ts +2 -5
- package/dist/core/configurators/slash/kilocode.d.ts.map +1 -1
- package/dist/core/configurators/slash/kilocode.js +2 -57
- package/dist/core/configurators/slash/kilocode.js.map +1 -1
- package/dist/core/configurators/slash/opencode.d.ts +2 -5
- package/dist/core/configurators/slash/opencode.d.ts.map +1 -1
- package/dist/core/configurators/slash/opencode.js +2 -57
- package/dist/core/configurators/slash/opencode.js.map +1 -1
- package/dist/core/configurators/slash/registry.d.ts +4 -4
- package/dist/core/configurators/slash/registry.d.ts.map +1 -1
- package/dist/core/configurators/slash/registry.js.map +1 -1
- package/dist/core/registry.d.ts +18 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +94 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/templates/index.d.ts +0 -1
- package/dist/core/templates/index.d.ts.map +1 -1
- package/dist/core/templates/index.js +0 -1
- package/dist/core/templates/index.js.map +1 -1
- package/package.json +7 -1
- package/AGENTS.md +0 -123
- package/CLAUDE.md +0 -17
- package/build.js +0 -20
- package/convex-setup.md +0 -403
- package/dist/core/templates/slash-command-templates.d.ts +0 -7
- package/dist/core/templates/slash-command-templates.d.ts.map +0 -1
- package/dist/core/templates/slash-command-templates.js +0 -1041
- package/dist/core/templates/slash-command-templates.js.map +0 -1
- package/prompt/ai-humanizer.md +0 -45
- package/prompt/api-contract-generator.md +0 -234
- package/prompt/apply.md +0 -17
- package/prompt/archive.md +0 -21
- package/prompt/design-system.md +0 -210
- package/prompt/document-explainer.md +0 -149
- package/prompt/epic-generator.md +0 -198
- package/prompt/epic-single.md +0 -47
- package/prompt/erd-generator.md +0 -130
- package/prompt/fsd-generator.md +0 -157
- package/prompt/prd-agent-generator.md +0 -147
- package/prompt/prd-generator.md +0 -195
- package/prompt/product-brief.md +0 -289
- package/prompt/proposal.md +0 -22
- package/prompt/qa-test-scenario.md +0 -133
- package/prompt/skill-creator.md +0 -350
- package/prompt/story-generator.md +0 -278
- package/prompt/story-single.md +0 -70
- package/prompt/tdd-generator.md +0 -294
- package/prompt/tdd-lite-generator.md +0 -224
- package/prompt/wireframe-generator.md +0 -219
- package/skills/ai-context-generator/SKILL.md +0 -54
- package/skills/ai-context-generator/references/AGENTS.template.md +0 -83
- package/skills/ai-context-generator/references/CLAUDE.template.md +0 -39
- package/skills/ai-context-generator/references/behavioral-guidelines.md +0 -71
- package/skills/ai-context-generator/references/discovery-checklist.md +0 -40
- package/skills/ai-context-generator/references/examples/AGENTS.good.md +0 -103
- package/skills/ai-context-generator/references/extraction-checklist.md +0 -23
- package/skills/ai-context-generator/references/overlays/laravel.md +0 -44
- package/skills/cerebro/SKILL.md +0 -187
- package/skills/cerebro/references/agents.md +0 -213
- package/skills/code-review/SKILL.md +0 -373
- package/skills/code-review/assets/report-template-agent.md +0 -212
- package/skills/code-review/assets/report-template-compact.md +0 -81
- package/skills/code-review/assets/report-template-full.md +0 -264
- package/skills/code-review/assets/report-template-human.md +0 -168
- package/skills/code-review/references/universal-patterns.md +0 -495
- package/skills/design-md/README.md +0 -34
- package/skills/design-md/SKILL.md +0 -172
- package/skills/design-md/examples/DESIGN.md +0 -154
- package/skills/design-system-generator/SKILL.md +0 -324
- package/skills/design-system-generator/assets/design-system-template.md +0 -348
- package/skills/design-system-generator/references/extraction-patterns.md +0 -321
- package/skills/doc-builder/SKILL.md +0 -115
- package/skills/doc-builder/references/ui-patterns.md +0 -394
- package/skills/document-translator/SKILL.md +0 -58
- package/skills/enhance-prompt/README.md +0 -34
- package/skills/enhance-prompt/SKILL.md +0 -204
- package/skills/enhance-prompt/references/KEYWORDS.md +0 -114
- package/skills/feature-planner/SKILL.md +0 -305
- package/skills/feature-planner/assets/implementation-plan-template.md +0 -85
- package/skills/frontend-design/LICENSE.txt +0 -177
- package/skills/frontend-design/SKILL.md +0 -42
- package/skills/gamma-builder/SKILL.md +0 -134
- package/skills/laravel-code-review/SKILL.md +0 -383
- package/skills/laravel-code-review/assets/report-template-agent.md +0 -195
- package/skills/laravel-code-review/assets/report-template-compact.md +0 -79
- package/skills/laravel-code-review/assets/report-template-full.md +0 -253
- package/skills/laravel-code-review/assets/report-template-human.md +0 -159
- package/skills/laravel-code-review/references/laravel-patterns.md +0 -571
- package/skills/laravel-code-review/references/php84-features.md +0 -442
- package/skills/mcp-builder/LICENSE.txt +0 -202
- package/skills/mcp-builder/SKILL.md +0 -236
- package/skills/mcp-builder/reference/evaluation.md +0 -602
- package/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
- package/skills/mcp-builder/reference/node_mcp_server.md +0 -970
- package/skills/mcp-builder/reference/python_mcp_server.md +0 -719
- package/skills/mcp-builder/scripts/connections.py +0 -151
- package/skills/mcp-builder/scripts/evaluation.py +0 -373
- package/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
- package/skills/mcp-builder/scripts/requirements.txt +0 -2
- package/skills/meeting-notes/SKILL.md +0 -159
- package/skills/meeting-notes/evals/evals.json +0 -23
- package/skills/project-orchestrator/SKILL.md +0 -487
- package/skills/project-orchestrator/assets/caddy-vps-setup.md +0 -180
- package/skills/project-orchestrator/assets/plan-summary-template.md +0 -159
- package/skills/prompter-specs/SKILL.md +0 -115
- package/skills/prompter-workflow/SKILL.md +0 -166
- package/skills/prompter-workflow/evals/evals.json +0 -89
- package/skills/sph-generator/SKILL.md +0 -488
- package/skills/ui-ux-pro/SKILL.md +0 -199
- package/skills/ui-ux-pro/assets/design-spec-template.md +0 -173
- package/skills/ui-ux-pro/references/component-patterns.md +0 -255
- package/skills/ui-ux-pro/references/design-principles.md +0 -167
- package/src/cli/index.ts +0 -223
- package/src/commands/archive.ts +0 -302
- package/src/commands/change.ts +0 -292
- package/src/commands/config.ts +0 -233
- package/src/commands/guide.ts +0 -50
- package/src/commands/init.ts +0 -899
- package/src/commands/list.ts +0 -194
- package/src/commands/show.ts +0 -138
- package/src/commands/spec.ts +0 -251
- package/src/commands/update.ts +0 -156
- package/src/commands/upgrade.ts +0 -30
- package/src/commands/validate.ts +0 -326
- package/src/core/artifact-graph/graph.ts +0 -167
- package/src/core/artifact-graph/index.ts +0 -44
- package/src/core/artifact-graph/instruction-loader.ts +0 -302
- package/src/core/artifact-graph/resolver.ts +0 -226
- package/src/core/artifact-graph/schema.ts +0 -124
- package/src/core/artifact-graph/state.ts +0 -64
- package/src/core/artifact-graph/types.ts +0 -65
- package/src/core/completions/command-registry.ts +0 -382
- package/src/core/completions/completion-provider.ts +0 -128
- package/src/core/completions/generators/bash-generator.ts +0 -191
- package/src/core/completions/generators/fish-generator.ts +0 -188
- package/src/core/completions/generators/powershell-generator.ts +0 -223
- package/src/core/completions/generators/zsh-generator.ts +0 -281
- package/src/core/completions/templates/bash-templates.ts +0 -24
- package/src/core/completions/templates/fish-templates.ts +0 -40
- package/src/core/completions/templates/powershell-templates.ts +0 -25
- package/src/core/completions/templates/zsh-templates.ts +0 -36
- package/src/core/completions/types.ts +0 -90
- package/src/core/config-schema.ts +0 -230
- package/src/core/config.ts +0 -181
- package/src/core/configurators/slash/antigravity.ts +0 -70
- package/src/core/configurators/slash/base.ts +0 -203
- package/src/core/configurators/slash/claude.ts +0 -70
- package/src/core/configurators/slash/codex.ts +0 -70
- package/src/core/configurators/slash/droid.ts +0 -44
- package/src/core/configurators/slash/forge.ts +0 -44
- package/src/core/configurators/slash/github-copilot.ts +0 -114
- package/src/core/configurators/slash/index.ts +0 -10
- package/src/core/configurators/slash/kilocode.ts +0 -70
- package/src/core/configurators/slash/opencode.ts +0 -70
- package/src/core/configurators/slash/registry.ts +0 -51
- package/src/core/converters/json-converter.ts +0 -62
- package/src/core/global-config.ts +0 -136
- package/src/core/parsers/change-parser.ts +0 -234
- package/src/core/parsers/markdown-parser.ts +0 -237
- package/src/core/parsers/requirement-blocks.ts +0 -234
- package/src/core/prompt-templates.ts +0 -3504
- package/src/core/schemas/base.schema.ts +0 -20
- package/src/core/schemas/change.schema.ts +0 -42
- package/src/core/schemas/index.ts +0 -20
- package/src/core/schemas/spec.schema.ts +0 -17
- package/src/core/skill-discovery.ts +0 -68
- package/src/core/specs-apply.ts +0 -483
- package/src/core/styles/palette.ts +0 -8
- package/src/core/templates/agents-template.ts +0 -459
- package/src/core/templates/claude-template.ts +0 -2
- package/src/core/templates/index.ts +0 -4
- package/src/core/templates/project-template.ts +0 -32
- package/src/core/templates/slash-command-templates.ts +0 -1068
- package/src/core/validation/constants.ts +0 -48
- package/src/core/validation/types.ts +0 -19
- package/src/core/validation/validator.ts +0 -449
- package/src/core/view.ts +0 -219
- package/src/index.ts +0 -1
- package/src/utils/change-metadata.ts +0 -171
- package/src/utils/change-utils.ts +0 -131
- package/src/utils/file-system.ts +0 -252
- package/src/utils/index.ts +0 -12
- package/src/utils/interactive.ts +0 -29
- package/src/utils/item-discovery.ts +0 -66
- package/src/utils/match.ts +0 -26
- package/src/utils/shell-detection.ts +0 -62
- package/src/utils/task-progress.ts +0 -43
- package/tsconfig.json +0 -28
package/src/commands/init.ts
DELETED
|
@@ -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
|
-
}
|