@dedesfr/prompter 0.9.0 ā 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 +21 -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.map +1 -1
- package/dist/commands/init.js +32 -9
- 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 +18 -5
- 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/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/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/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/ai-humanizer/SKILL.md +0 -50
- package/skills/api-contract-generator/SKILL.md +0 -243
- package/skills/apply/SKILL.md +0 -23
- package/skills/archive/SKILL.md +0 -27
- 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/SKILL.md +0 -216
- 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-explainer/SKILL.md +0 -155
- package/skills/document-translator/SKILL.md +0 -58
- package/skills/enhance/SKILL.md +0 -47
- 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/epic-generator/SKILL.md +0 -204
- package/skills/epic-single/SKILL.md +0 -63
- package/skills/erd-generator/SKILL.md +0 -138
- 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/fsd-generator/SKILL.md +0 -163
- 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/prd-agent-generator/SKILL.md +0 -132
- package/skills/prd-generator/SKILL.md +0 -211
- package/skills/product-brief/SKILL.md +0 -141
- 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/proposal/SKILL.md +0 -28
- package/skills/qa-test-scenario/SKILL.md +0 -149
- package/skills/skill-creator/SKILL.md +0 -173
- package/skills/sph-generator/SKILL.md +0 -488
- package/skills/story-generator/SKILL.md +0 -285
- package/skills/story-single/SKILL.md +0 -86
- package/skills/tdd-generator/SKILL.md +0 -300
- package/skills/tdd-lite-generator/SKILL.md +0 -230
- 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/skills/wireframe-generator/SKILL.md +0 -227
- 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 -597
- 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 -129
- 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 -10
- package/src/core/configurators/slash/base.ts +0 -109
- package/src/core/configurators/slash/claude.ts +0 -10
- package/src/core/configurators/slash/codex.ts +0 -10
- package/src/core/configurators/slash/droid.ts +0 -10
- package/src/core/configurators/slash/forge.ts +0 -10
- package/src/core/configurators/slash/github-copilot.ts +0 -10
- package/src/core/configurators/slash/index.ts +0 -10
- package/src/core/configurators/slash/kilocode.ts +0 -10
- package/src/core/configurators/slash/opencode.ts +0 -10
- 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 -3
- package/src/core/templates/project-template.ts +0 -32
- 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,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
|
-
}
|