setup-vibeflow 0.1.1 → 0.3.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/index.js +150 -31
- package/package.json +5 -2
package/index.js
CHANGED
|
@@ -8,9 +8,8 @@ import pc from 'picocolors';
|
|
|
8
8
|
|
|
9
9
|
const REPO = 'pe-menezes/vibeflow';
|
|
10
10
|
const BRANCH = 'main';
|
|
11
|
-
const BASE_URL = `https://raw.githubusercontent.com/${REPO}/${BRANCH}/copilot`;
|
|
12
11
|
|
|
13
|
-
const
|
|
12
|
+
const COPILOT_FILES = [
|
|
14
13
|
{ src: 'github/prompts/vibeflow-analyze.prompt.md', dest: '.github/prompts/vibeflow-analyze.prompt.md' },
|
|
15
14
|
{ src: 'github/prompts/vibeflow-audit.prompt.md', dest: '.github/prompts/vibeflow-audit.prompt.md' },
|
|
16
15
|
{ src: 'github/prompts/vibeflow-discover.prompt.md', dest: '.github/prompts/vibeflow-discover.prompt.md' },
|
|
@@ -24,8 +23,65 @@ const FILES = [
|
|
|
24
23
|
{ src: 'github/instructions/vibeflow/vibeflow.instructions.md', dest: '.github/instructions/vibeflow/vibeflow.instructions.md' },
|
|
25
24
|
];
|
|
26
25
|
|
|
26
|
+
const CURSOR_FILES = [
|
|
27
|
+
{ src: 'rules/vibeflow.mdc', dest: '.cursor/rules/vibeflow.mdc' },
|
|
28
|
+
{ src: 'rules/vibeflow-architect.mdc', dest: '.cursor/rules/vibeflow-architect.mdc' },
|
|
29
|
+
{ src: 'skills/vibeflow-analyze/SKILL.md', dest: '.cursor/skills/vibeflow-analyze/SKILL.md' },
|
|
30
|
+
{ src: 'skills/vibeflow-audit/SKILL.md', dest: '.cursor/skills/vibeflow-audit/SKILL.md' },
|
|
31
|
+
{ src: 'skills/vibeflow-discover/SKILL.md', dest: '.cursor/skills/vibeflow-discover/SKILL.md' },
|
|
32
|
+
{ src: 'skills/vibeflow-gen-spec/SKILL.md', dest: '.cursor/skills/vibeflow-gen-spec/SKILL.md' },
|
|
33
|
+
{ src: 'skills/vibeflow-prompt-pack/SKILL.md', dest: '.cursor/skills/vibeflow-prompt-pack/SKILL.md' },
|
|
34
|
+
{ src: 'skills/vibeflow-quick/SKILL.md', dest: '.cursor/skills/vibeflow-quick/SKILL.md' },
|
|
35
|
+
{ src: 'skills/vibeflow-teach/SKILL.md', dest: '.cursor/skills/vibeflow-teach/SKILL.md' },
|
|
36
|
+
{ src: 'skills/vibeflow-stats/SKILL.md', dest: '.cursor/skills/vibeflow-stats/SKILL.md' },
|
|
37
|
+
{ src: 'skills/vibeflow-spec-driven-dev/SKILL.md', dest: '.cursor/skills/vibeflow-spec-driven-dev/SKILL.md' },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const EDITIONS = {
|
|
41
|
+
copilot: {
|
|
42
|
+
name: 'Copilot',
|
|
43
|
+
baseUrl: `https://raw.githubusercontent.com/${REPO}/${BRANCH}/copilot`,
|
|
44
|
+
files: COPILOT_FILES,
|
|
45
|
+
marker: '.github/prompts/vibeflow-analyze.prompt.md',
|
|
46
|
+
markerLegacy: '.github/prompts/vibeflow/vibeflow-analyze.prompt.md',
|
|
47
|
+
agentsSrc: 'AGENTS.md',
|
|
48
|
+
doneMessage: `Run ${pc.bold('/vibeflow-analyze')} in Copilot Chat to get started.`,
|
|
49
|
+
handleCopilotInstructions: true,
|
|
50
|
+
},
|
|
51
|
+
cursor: {
|
|
52
|
+
name: 'Cursor',
|
|
53
|
+
baseUrl: `https://raw.githubusercontent.com/${REPO}/${BRANCH}/cursor`,
|
|
54
|
+
files: CURSOR_FILES,
|
|
55
|
+
marker: '.cursor/rules/vibeflow.mdc',
|
|
56
|
+
markerLegacy: null,
|
|
57
|
+
agentsSrc: 'AGENTS.md',
|
|
58
|
+
doneMessage: `Type ${pc.bold('/vibeflow-analyze')} in Cursor Agent chat to get started.`,
|
|
59
|
+
handleCopilotInstructions: false,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
27
63
|
const DUPLICATE_MARKER = 'vibeflow-architect';
|
|
28
64
|
|
|
65
|
+
const GITIGNORE_MARKER = '# Vibeflow — installed + generated (remove to track in git)';
|
|
66
|
+
|
|
67
|
+
const GITIGNORE_BLOCKS = {
|
|
68
|
+
copilot: `
|
|
69
|
+
# Vibeflow — installed + generated (remove to track in git)
|
|
70
|
+
.vibeflow/
|
|
71
|
+
.github/prompts/vibeflow-*.prompt.md
|
|
72
|
+
.github/agents/vibeflow-architect.agent.md
|
|
73
|
+
.github/skills/vibeflow-spec-driven-dev/
|
|
74
|
+
.github/instructions/vibeflow/
|
|
75
|
+
`,
|
|
76
|
+
cursor: `
|
|
77
|
+
# Vibeflow — installed + generated (remove to track in git)
|
|
78
|
+
.vibeflow/
|
|
79
|
+
.cursor/rules/vibeflow.mdc
|
|
80
|
+
.cursor/rules/vibeflow-architect.mdc
|
|
81
|
+
.cursor/skills/vibeflow-*/
|
|
82
|
+
`,
|
|
83
|
+
};
|
|
84
|
+
|
|
29
85
|
// --- Helpers ---
|
|
30
86
|
|
|
31
87
|
function log(icon, msg) {
|
|
@@ -38,8 +94,8 @@ function ensureDir(dirPath) {
|
|
|
38
94
|
}
|
|
39
95
|
}
|
|
40
96
|
|
|
41
|
-
async function downloadFile(srcPath) {
|
|
42
|
-
const url = `${
|
|
97
|
+
async function downloadFile(baseUrl, srcPath) {
|
|
98
|
+
const url = `${baseUrl}/${srcPath}`;
|
|
43
99
|
const res = await fetch(url);
|
|
44
100
|
if (!res.ok) {
|
|
45
101
|
throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
|
|
@@ -48,27 +104,67 @@ async function downloadFile(srcPath) {
|
|
|
48
104
|
}
|
|
49
105
|
|
|
50
106
|
function extractAgentsAppendContent(fullContent) {
|
|
51
|
-
// Remove the instruction note at the top (everything before and including the first ---)
|
|
52
107
|
const separatorIndex = fullContent.indexOf('\n---\n');
|
|
53
108
|
if (separatorIndex === -1) return fullContent;
|
|
54
109
|
return fullContent.slice(separatorIndex + '\n---\n'.length);
|
|
55
110
|
}
|
|
56
111
|
|
|
57
112
|
function extractCopilotInstructionsSnippet(fullContent) {
|
|
58
|
-
// Extract the markdown block between ```markdown and ```
|
|
59
113
|
const match = fullContent.match(/```markdown\n([\s\S]*?)```/);
|
|
60
114
|
if (!match) return null;
|
|
61
115
|
return match[1].trim();
|
|
62
116
|
}
|
|
63
117
|
|
|
118
|
+
function detectEdition() {
|
|
119
|
+
const args = process.argv.slice(2);
|
|
120
|
+
if (args.includes('--cursor')) return 'cursor';
|
|
121
|
+
if (args.includes('--copilot')) return 'copilot';
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function printUsage() {
|
|
126
|
+
console.log('');
|
|
127
|
+
console.log(` ${pc.bold(pc.cyan('Vibeflow'))} ${pc.dim('— Setup')}`);
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log(` ${pc.bold('Usage:')} npx setup-vibeflow@latest ${pc.cyan('<edition>')}`);
|
|
130
|
+
console.log('');
|
|
131
|
+
console.log(` ${pc.bold('Editions:')}`);
|
|
132
|
+
console.log(` ${pc.cyan('--copilot')} Install for GitHub Copilot ${pc.dim('(.github/prompts, agents, instructions)')}`);
|
|
133
|
+
console.log(` ${pc.cyan('--cursor')} Install for Cursor ${pc.dim('(.cursor/rules, skills)')}`);
|
|
134
|
+
console.log('');
|
|
135
|
+
console.log(` ${pc.bold('Options:')}`);
|
|
136
|
+
console.log(` ${pc.cyan('--force')} Overwrite existing files`);
|
|
137
|
+
console.log('');
|
|
138
|
+
console.log(` ${pc.bold('Examples:')}`);
|
|
139
|
+
console.log(` ${pc.dim('$')} npx setup-vibeflow@latest --copilot`);
|
|
140
|
+
console.log(` ${pc.dim('$')} npx setup-vibeflow@latest --cursor`);
|
|
141
|
+
console.log(` ${pc.dim('$')} npx setup-vibeflow@latest --cursor --force`);
|
|
142
|
+
console.log('');
|
|
143
|
+
}
|
|
144
|
+
|
|
64
145
|
// --- Main ---
|
|
65
146
|
|
|
66
147
|
async function main() {
|
|
67
148
|
const force = process.argv.includes('--force');
|
|
149
|
+
const help = process.argv.includes('--help') || process.argv.includes('-h');
|
|
68
150
|
const cwd = process.cwd();
|
|
69
151
|
|
|
152
|
+
if (help) {
|
|
153
|
+
printUsage();
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const editionKey = detectEdition();
|
|
158
|
+
|
|
159
|
+
if (!editionKey) {
|
|
160
|
+
printUsage();
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const edition = EDITIONS[editionKey];
|
|
165
|
+
|
|
70
166
|
console.log('');
|
|
71
|
-
console.log(` ${pc.bold(pc.cyan('Vibeflow'))} ${pc.dim(
|
|
167
|
+
console.log(` ${pc.bold(pc.cyan('Vibeflow'))} ${pc.dim(`— ${edition.name} Edition`)}`);
|
|
72
168
|
console.log('');
|
|
73
169
|
|
|
74
170
|
// Check Node.js version
|
|
@@ -78,10 +174,10 @@ async function main() {
|
|
|
78
174
|
process.exit(1);
|
|
79
175
|
}
|
|
80
176
|
|
|
81
|
-
// Check if already installed
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
if ((existsSync(
|
|
177
|
+
// Check if already installed
|
|
178
|
+
const markerPath = join(cwd, edition.marker);
|
|
179
|
+
const markerLegacyPath = edition.markerLegacy ? join(cwd, edition.markerLegacy) : null;
|
|
180
|
+
if ((existsSync(markerPath) || (markerLegacyPath && existsSync(markerLegacyPath))) && !force) {
|
|
85
181
|
log(pc.yellow('!'), 'Vibeflow already installed. Use --force to reinstall.');
|
|
86
182
|
console.log('');
|
|
87
183
|
process.exit(0);
|
|
@@ -91,7 +187,7 @@ async function main() {
|
|
|
91
187
|
let created = 0;
|
|
92
188
|
let skipped = 0;
|
|
93
189
|
|
|
94
|
-
for (const file of
|
|
190
|
+
for (const file of edition.files) {
|
|
95
191
|
const destPath = join(cwd, file.dest);
|
|
96
192
|
const destDir = join(destPath, '..');
|
|
97
193
|
|
|
@@ -102,7 +198,7 @@ async function main() {
|
|
|
102
198
|
}
|
|
103
199
|
|
|
104
200
|
try {
|
|
105
|
-
const content = await downloadFile(file.src);
|
|
201
|
+
const content = await downloadFile(edition.baseUrl, file.src);
|
|
106
202
|
ensureDir(destDir);
|
|
107
203
|
writeFileSync(destPath, content, 'utf-8');
|
|
108
204
|
log(pc.green('+'), file.dest);
|
|
@@ -118,7 +214,7 @@ async function main() {
|
|
|
118
214
|
// Handle AGENTS.md
|
|
119
215
|
const agentsPath = join(cwd, 'AGENTS.md');
|
|
120
216
|
try {
|
|
121
|
-
const agentsSource = await downloadFile(
|
|
217
|
+
const agentsSource = await downloadFile(edition.baseUrl, edition.agentsSrc);
|
|
122
218
|
const appendContent = extractAgentsAppendContent(agentsSource);
|
|
123
219
|
|
|
124
220
|
if (existsSync(agentsPath)) {
|
|
@@ -138,27 +234,50 @@ async function main() {
|
|
|
138
234
|
log(pc.red('x'), `AGENTS.md — ${err.message}`);
|
|
139
235
|
}
|
|
140
236
|
|
|
141
|
-
// Handle copilot-instructions.md
|
|
142
|
-
|
|
237
|
+
// Handle copilot-instructions.md (Copilot only)
|
|
238
|
+
if (edition.handleCopilotInstructions) {
|
|
239
|
+
const copilotInstrPath = join(cwd, '.github/copilot-instructions.md');
|
|
240
|
+
try {
|
|
241
|
+
if (existsSync(copilotInstrPath)) {
|
|
242
|
+
const existing = readFileSync(copilotInstrPath, 'utf-8');
|
|
243
|
+
if (existing.includes('vibeflow') && !force) {
|
|
244
|
+
log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(vibeflow snippet exists, skipped)')}`);
|
|
245
|
+
} else {
|
|
246
|
+
const snippetSource = await downloadFile(edition.baseUrl, 'copilot-instructions.md');
|
|
247
|
+
const snippet = extractCopilotInstructionsSnippet(snippetSource);
|
|
248
|
+
if (snippet) {
|
|
249
|
+
const updated = existing.trimEnd() + '\n\n' + snippet + '\n';
|
|
250
|
+
writeFileSync(copilotInstrPath, updated, 'utf-8');
|
|
251
|
+
log(pc.green('+'), `.github/copilot-instructions.md ${pc.dim('(appended vibeflow snippet)')}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(not found, skipping — instructions auto-loaded)')}`);
|
|
256
|
+
}
|
|
257
|
+
} catch (err) {
|
|
258
|
+
log(pc.red('x'), `.github/copilot-instructions.md — ${err.message}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Append Vibeflow paths to .gitignore (default: do not track; user can remove to track)
|
|
263
|
+
const gitignorePath = join(cwd, '.gitignore');
|
|
143
264
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
265
|
+
const block = GITIGNORE_BLOCKS[editionKey];
|
|
266
|
+
if (block) {
|
|
267
|
+
let content = '';
|
|
268
|
+
if (existsSync(gitignorePath)) {
|
|
269
|
+
content = readFileSync(gitignorePath, 'utf-8');
|
|
270
|
+
}
|
|
271
|
+
if (!content.includes(GITIGNORE_MARKER)) {
|
|
272
|
+
const updated = (content.trimEnd() ? content.trimEnd() + '\n' : '') + block.trim() + '\n';
|
|
273
|
+
writeFileSync(gitignorePath, updated, 'utf-8');
|
|
274
|
+
log(pc.green('+'), `.gitignore ${pc.dim('(Vibeflow paths added — remove that block to track in git)')}`);
|
|
148
275
|
} else {
|
|
149
|
-
|
|
150
|
-
const snippet = extractCopilotInstructionsSnippet(snippetSource);
|
|
151
|
-
if (snippet) {
|
|
152
|
-
const updated = existing.trimEnd() + '\n\n' + snippet + '\n';
|
|
153
|
-
writeFileSync(copilotInstrPath, updated, 'utf-8');
|
|
154
|
-
log(pc.green('+'), `.github/copilot-instructions.md ${pc.dim('(appended vibeflow snippet)')}`);
|
|
155
|
-
}
|
|
276
|
+
log(pc.dim('-'), `${pc.dim('.gitignore')} ${pc.dim('(Vibeflow block already present)')}`);
|
|
156
277
|
}
|
|
157
|
-
} else {
|
|
158
|
-
log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(not found, skipping — instructions auto-loaded)')}`);
|
|
159
278
|
}
|
|
160
279
|
} catch (err) {
|
|
161
|
-
log(pc.red('x'), `.
|
|
280
|
+
log(pc.red('x'), `.gitignore — ${err.message}`);
|
|
162
281
|
}
|
|
163
282
|
|
|
164
283
|
// Summary
|
|
@@ -169,7 +288,7 @@ async function main() {
|
|
|
169
288
|
log(pc.yellow('!'), pc.bold('All files already exist. Nothing to do.'));
|
|
170
289
|
}
|
|
171
290
|
console.log('');
|
|
172
|
-
log(pc.cyan('→'),
|
|
291
|
+
log(pc.cyan('→'), edition.doneMessage);
|
|
173
292
|
console.log('');
|
|
174
293
|
}
|
|
175
294
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "setup-vibeflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Install Vibeflow (spec-driven development) in your project",
|
|
5
5
|
"bin": {
|
|
6
6
|
"setup-vibeflow": "./index.js"
|
|
@@ -13,9 +13,12 @@
|
|
|
13
13
|
"vibeflow",
|
|
14
14
|
"copilot",
|
|
15
15
|
"github-copilot",
|
|
16
|
+
"cursor",
|
|
17
|
+
"cursor-ide",
|
|
16
18
|
"spec-driven",
|
|
17
19
|
"prompts",
|
|
18
|
-
"agents"
|
|
20
|
+
"agents",
|
|
21
|
+
"skills"
|
|
19
22
|
],
|
|
20
23
|
"author": "pe-menezes",
|
|
21
24
|
"license": "MIT",
|