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.
Files changed (2) hide show
  1. package/index.js +110 -31
  2. 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 FILES = [
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 = `${BASE_URL}/${srcPath}`;
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('— Copilot Edition')}`);
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 markerFile = join(cwd, '.github/prompts/vibeflow-analyze.prompt.md');
83
- if (existsSync(markerFile) && !force) {
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 FILES) {
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('AGENTS.md');
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
- const copilotInstrPath = join(cwd, '.github/copilot-instructions.md');
142
- try {
143
- if (existsSync(copilotInstrPath)) {
144
- const existing = readFileSync(copilotInstrPath, 'utf-8');
145
- if (existing.includes('vibeflow') && !force) {
146
- log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(vibeflow snippet exists, skipped)')}`);
147
- } else {
148
- const snippetSource = await downloadFile('copilot-instructions.md');
149
- const snippet = extractCopilotInstructionsSnippet(snippetSource);
150
- if (snippet) {
151
- const updated = existing.trimEnd() + '\n\n' + snippet + '\n';
152
- writeFileSync(copilotInstrPath, updated, 'utf-8');
153
- log(pc.green('+'), `.github/copilot-instructions.md ${pc.dim('(appended vibeflow snippet)')}`);
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
- } else {
157
- log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(not found, skipping — instructions auto-loaded)')}`);
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('→'), `Run ${pc.bold('/vibeflow-analyze')} in Copilot Chat to get started.`);
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.1.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",