setup-vibeflow 0.1.0 → 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 +110 -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,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
|
|
@@ -79,8 +155,9 @@ async function main() {
|
|
|
79
155
|
}
|
|
80
156
|
|
|
81
157
|
// Check if already installed
|
|
82
|
-
const
|
|
83
|
-
|
|
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) {
|
|
84
161
|
log(pc.yellow('!'), 'Vibeflow already installed. Use --force to reinstall.');
|
|
85
162
|
console.log('');
|
|
86
163
|
process.exit(0);
|
|
@@ -90,7 +167,7 @@ async function main() {
|
|
|
90
167
|
let created = 0;
|
|
91
168
|
let skipped = 0;
|
|
92
169
|
|
|
93
|
-
for (const file of
|
|
170
|
+
for (const file of edition.files) {
|
|
94
171
|
const destPath = join(cwd, file.dest);
|
|
95
172
|
const destDir = join(destPath, '..');
|
|
96
173
|
|
|
@@ -101,7 +178,7 @@ async function main() {
|
|
|
101
178
|
}
|
|
102
179
|
|
|
103
180
|
try {
|
|
104
|
-
const content = await downloadFile(file.src);
|
|
181
|
+
const content = await downloadFile(edition.baseUrl, file.src);
|
|
105
182
|
ensureDir(destDir);
|
|
106
183
|
writeFileSync(destPath, content, 'utf-8');
|
|
107
184
|
log(pc.green('+'), file.dest);
|
|
@@ -117,7 +194,7 @@ async function main() {
|
|
|
117
194
|
// Handle AGENTS.md
|
|
118
195
|
const agentsPath = join(cwd, 'AGENTS.md');
|
|
119
196
|
try {
|
|
120
|
-
const agentsSource = await downloadFile(
|
|
197
|
+
const agentsSource = await downloadFile(edition.baseUrl, edition.agentsSrc);
|
|
121
198
|
const appendContent = extractAgentsAppendContent(agentsSource);
|
|
122
199
|
|
|
123
200
|
if (existsSync(agentsPath)) {
|
|
@@ -137,27 +214,29 @@ async function main() {
|
|
|
137
214
|
log(pc.red('x'), `AGENTS.md — ${err.message}`);
|
|
138
215
|
}
|
|
139
216
|
|
|
140
|
-
// Handle copilot-instructions.md
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
+
}
|
|
154
233
|
}
|
|
234
|
+
} else {
|
|
235
|
+
log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(not found, skipping — instructions auto-loaded)')}`);
|
|
155
236
|
}
|
|
156
|
-
}
|
|
157
|
-
log(pc.
|
|
237
|
+
} catch (err) {
|
|
238
|
+
log(pc.red('x'), `.github/copilot-instructions.md — ${err.message}`);
|
|
158
239
|
}
|
|
159
|
-
} catch (err) {
|
|
160
|
-
log(pc.red('x'), `.github/copilot-instructions.md — ${err.message}`);
|
|
161
240
|
}
|
|
162
241
|
|
|
163
242
|
// Summary
|
|
@@ -168,7 +247,7 @@ async function main() {
|
|
|
168
247
|
log(pc.yellow('!'), pc.bold('All files already exist. Nothing to do.'));
|
|
169
248
|
}
|
|
170
249
|
console.log('');
|
|
171
|
-
log(pc.cyan('→'),
|
|
250
|
+
log(pc.cyan('→'), edition.doneMessage);
|
|
172
251
|
console.log('');
|
|
173
252
|
}
|
|
174
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",
|