setup-vibeflow 0.1.1 → 0.2.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 +111 -33
- 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,6 +23,43 @@ 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
|
|
|
29
65
|
// --- Helpers ---
|
|
@@ -38,8 +74,8 @@ function ensureDir(dirPath) {
|
|
|
38
74
|
}
|
|
39
75
|
}
|
|
40
76
|
|
|
41
|
-
async function downloadFile(srcPath) {
|
|
42
|
-
const url = `${
|
|
77
|
+
async function downloadFile(baseUrl, srcPath) {
|
|
78
|
+
const url = `${baseUrl}/${srcPath}`;
|
|
43
79
|
const res = await fetch(url);
|
|
44
80
|
if (!res.ok) {
|
|
45
81
|
throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
|
|
@@ -48,27 +84,67 @@ async function downloadFile(srcPath) {
|
|
|
48
84
|
}
|
|
49
85
|
|
|
50
86
|
function extractAgentsAppendContent(fullContent) {
|
|
51
|
-
// Remove the instruction note at the top (everything before and including the first ---)
|
|
52
87
|
const separatorIndex = fullContent.indexOf('\n---\n');
|
|
53
88
|
if (separatorIndex === -1) return fullContent;
|
|
54
89
|
return fullContent.slice(separatorIndex + '\n---\n'.length);
|
|
55
90
|
}
|
|
56
91
|
|
|
57
92
|
function extractCopilotInstructionsSnippet(fullContent) {
|
|
58
|
-
// Extract the markdown block between ```markdown and ```
|
|
59
93
|
const match = fullContent.match(/```markdown\n([\s\S]*?)```/);
|
|
60
94
|
if (!match) return null;
|
|
61
95
|
return match[1].trim();
|
|
62
96
|
}
|
|
63
97
|
|
|
98
|
+
function detectEdition() {
|
|
99
|
+
const args = process.argv.slice(2);
|
|
100
|
+
if (args.includes('--cursor')) return 'cursor';
|
|
101
|
+
if (args.includes('--copilot')) return 'copilot';
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function printUsage() {
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log(` ${pc.bold(pc.cyan('Vibeflow'))} ${pc.dim('— Setup')}`);
|
|
108
|
+
console.log('');
|
|
109
|
+
console.log(` ${pc.bold('Usage:')} npx setup-vibeflow@latest ${pc.cyan('<edition>')}`);
|
|
110
|
+
console.log('');
|
|
111
|
+
console.log(` ${pc.bold('Editions:')}`);
|
|
112
|
+
console.log(` ${pc.cyan('--copilot')} Install for GitHub Copilot ${pc.dim('(.github/prompts, agents, instructions)')}`);
|
|
113
|
+
console.log(` ${pc.cyan('--cursor')} Install for Cursor ${pc.dim('(.cursor/rules, skills)')}`);
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log(` ${pc.bold('Options:')}`);
|
|
116
|
+
console.log(` ${pc.cyan('--force')} Overwrite existing files`);
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log(` ${pc.bold('Examples:')}`);
|
|
119
|
+
console.log(` ${pc.dim('$')} npx setup-vibeflow@latest --copilot`);
|
|
120
|
+
console.log(` ${pc.dim('$')} npx setup-vibeflow@latest --cursor`);
|
|
121
|
+
console.log(` ${pc.dim('$')} npx setup-vibeflow@latest --cursor --force`);
|
|
122
|
+
console.log('');
|
|
123
|
+
}
|
|
124
|
+
|
|
64
125
|
// --- Main ---
|
|
65
126
|
|
|
66
127
|
async function main() {
|
|
67
128
|
const force = process.argv.includes('--force');
|
|
129
|
+
const help = process.argv.includes('--help') || process.argv.includes('-h');
|
|
68
130
|
const cwd = process.cwd();
|
|
69
131
|
|
|
132
|
+
if (help) {
|
|
133
|
+
printUsage();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const editionKey = detectEdition();
|
|
138
|
+
|
|
139
|
+
if (!editionKey) {
|
|
140
|
+
printUsage();
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const edition = EDITIONS[editionKey];
|
|
145
|
+
|
|
70
146
|
console.log('');
|
|
71
|
-
console.log(` ${pc.bold(pc.cyan('Vibeflow'))} ${pc.dim(
|
|
147
|
+
console.log(` ${pc.bold(pc.cyan('Vibeflow'))} ${pc.dim(`— ${edition.name} Edition`)}`);
|
|
72
148
|
console.log('');
|
|
73
149
|
|
|
74
150
|
// Check Node.js version
|
|
@@ -78,10 +154,10 @@ async function main() {
|
|
|
78
154
|
process.exit(1);
|
|
79
155
|
}
|
|
80
156
|
|
|
81
|
-
// Check if already installed
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
if ((existsSync(
|
|
157
|
+
// Check if already installed
|
|
158
|
+
const markerPath = join(cwd, edition.marker);
|
|
159
|
+
const markerLegacyPath = edition.markerLegacy ? join(cwd, edition.markerLegacy) : null;
|
|
160
|
+
if ((existsSync(markerPath) || (markerLegacyPath && existsSync(markerLegacyPath))) && !force) {
|
|
85
161
|
log(pc.yellow('!'), 'Vibeflow already installed. Use --force to reinstall.');
|
|
86
162
|
console.log('');
|
|
87
163
|
process.exit(0);
|
|
@@ -91,7 +167,7 @@ async function main() {
|
|
|
91
167
|
let created = 0;
|
|
92
168
|
let skipped = 0;
|
|
93
169
|
|
|
94
|
-
for (const file of
|
|
170
|
+
for (const file of edition.files) {
|
|
95
171
|
const destPath = join(cwd, file.dest);
|
|
96
172
|
const destDir = join(destPath, '..');
|
|
97
173
|
|
|
@@ -102,7 +178,7 @@ async function main() {
|
|
|
102
178
|
}
|
|
103
179
|
|
|
104
180
|
try {
|
|
105
|
-
const content = await downloadFile(file.src);
|
|
181
|
+
const content = await downloadFile(edition.baseUrl, file.src);
|
|
106
182
|
ensureDir(destDir);
|
|
107
183
|
writeFileSync(destPath, content, 'utf-8');
|
|
108
184
|
log(pc.green('+'), file.dest);
|
|
@@ -118,7 +194,7 @@ async function main() {
|
|
|
118
194
|
// Handle AGENTS.md
|
|
119
195
|
const agentsPath = join(cwd, 'AGENTS.md');
|
|
120
196
|
try {
|
|
121
|
-
const agentsSource = await downloadFile(
|
|
197
|
+
const agentsSource = await downloadFile(edition.baseUrl, edition.agentsSrc);
|
|
122
198
|
const appendContent = extractAgentsAppendContent(agentsSource);
|
|
123
199
|
|
|
124
200
|
if (existsSync(agentsPath)) {
|
|
@@ -138,27 +214,29 @@ async function main() {
|
|
|
138
214
|
log(pc.red('x'), `AGENTS.md — ${err.message}`);
|
|
139
215
|
}
|
|
140
216
|
|
|
141
|
-
// Handle copilot-instructions.md
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
217
|
+
// Handle copilot-instructions.md (Copilot only)
|
|
218
|
+
if (edition.handleCopilotInstructions) {
|
|
219
|
+
const copilotInstrPath = join(cwd, '.github/copilot-instructions.md');
|
|
220
|
+
try {
|
|
221
|
+
if (existsSync(copilotInstrPath)) {
|
|
222
|
+
const existing = readFileSync(copilotInstrPath, 'utf-8');
|
|
223
|
+
if (existing.includes('vibeflow') && !force) {
|
|
224
|
+
log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(vibeflow snippet exists, skipped)')}`);
|
|
225
|
+
} else {
|
|
226
|
+
const snippetSource = await downloadFile(edition.baseUrl, 'copilot-instructions.md');
|
|
227
|
+
const snippet = extractCopilotInstructionsSnippet(snippetSource);
|
|
228
|
+
if (snippet) {
|
|
229
|
+
const updated = existing.trimEnd() + '\n\n' + snippet + '\n';
|
|
230
|
+
writeFileSync(copilotInstrPath, updated, 'utf-8');
|
|
231
|
+
log(pc.green('+'), `.github/copilot-instructions.md ${pc.dim('(appended vibeflow snippet)')}`);
|
|
232
|
+
}
|
|
155
233
|
}
|
|
234
|
+
} else {
|
|
235
|
+
log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(not found, skipping — instructions auto-loaded)')}`);
|
|
156
236
|
}
|
|
157
|
-
}
|
|
158
|
-
log(pc.
|
|
237
|
+
} catch (err) {
|
|
238
|
+
log(pc.red('x'), `.github/copilot-instructions.md — ${err.message}`);
|
|
159
239
|
}
|
|
160
|
-
} catch (err) {
|
|
161
|
-
log(pc.red('x'), `.github/copilot-instructions.md — ${err.message}`);
|
|
162
240
|
}
|
|
163
241
|
|
|
164
242
|
// Summary
|
|
@@ -169,7 +247,7 @@ async function main() {
|
|
|
169
247
|
log(pc.yellow('!'), pc.bold('All files already exist. Nothing to do.'));
|
|
170
248
|
}
|
|
171
249
|
console.log('');
|
|
172
|
-
log(pc.cyan('→'),
|
|
250
|
+
log(pc.cyan('→'), edition.doneMessage);
|
|
173
251
|
console.log('');
|
|
174
252
|
}
|
|
175
253
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "setup-vibeflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.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",
|