setup-vibeflow 0.1.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 +180 -0
- package/package.json +29 -0
package/index.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
|
|
7
|
+
// --- Config ---
|
|
8
|
+
|
|
9
|
+
const REPO = 'pe-menezes/vibeflow';
|
|
10
|
+
const BRANCH = 'main';
|
|
11
|
+
const BASE_URL = `https://raw.githubusercontent.com/${REPO}/${BRANCH}/copilot`;
|
|
12
|
+
|
|
13
|
+
const FILES = [
|
|
14
|
+
{ src: 'github/prompts/vibeflow-analyze.prompt.md', dest: '.github/prompts/vibeflow-analyze.prompt.md' },
|
|
15
|
+
{ src: 'github/prompts/vibeflow-audit.prompt.md', dest: '.github/prompts/vibeflow-audit.prompt.md' },
|
|
16
|
+
{ src: 'github/prompts/vibeflow-discover.prompt.md', dest: '.github/prompts/vibeflow-discover.prompt.md' },
|
|
17
|
+
{ src: 'github/prompts/vibeflow-gen-spec.prompt.md', dest: '.github/prompts/vibeflow-gen-spec.prompt.md' },
|
|
18
|
+
{ src: 'github/prompts/vibeflow-prompt-pack.prompt.md', dest: '.github/prompts/vibeflow-prompt-pack.prompt.md' },
|
|
19
|
+
{ src: 'github/prompts/vibeflow-quick.prompt.md', dest: '.github/prompts/vibeflow-quick.prompt.md' },
|
|
20
|
+
{ src: 'github/prompts/vibeflow-stats.prompt.md', dest: '.github/prompts/vibeflow-stats.prompt.md' },
|
|
21
|
+
{ src: 'github/prompts/vibeflow-teach.prompt.md', dest: '.github/prompts/vibeflow-teach.prompt.md' },
|
|
22
|
+
{ src: 'github/agents/vibeflow-architect.agent.md', dest: '.github/agents/vibeflow-architect.agent.md' },
|
|
23
|
+
{ src: 'github/skills/vibeflow-spec-driven-dev/SKILL.md', dest: '.github/skills/vibeflow-spec-driven-dev/SKILL.md' },
|
|
24
|
+
{ src: 'github/instructions/vibeflow/vibeflow.instructions.md', dest: '.github/instructions/vibeflow/vibeflow.instructions.md' },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const DUPLICATE_MARKER = 'vibeflow-architect';
|
|
28
|
+
|
|
29
|
+
// --- Helpers ---
|
|
30
|
+
|
|
31
|
+
function log(icon, msg) {
|
|
32
|
+
console.log(` ${icon} ${msg}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function ensureDir(dirPath) {
|
|
36
|
+
if (!existsSync(dirPath)) {
|
|
37
|
+
mkdirSync(dirPath, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function downloadFile(srcPath) {
|
|
42
|
+
const url = `${BASE_URL}/${srcPath}`;
|
|
43
|
+
const res = await fetch(url);
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
return res.text();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function extractAgentsAppendContent(fullContent) {
|
|
51
|
+
// Remove the instruction note at the top (everything before and including the first ---)
|
|
52
|
+
const separatorIndex = fullContent.indexOf('\n---\n');
|
|
53
|
+
if (separatorIndex === -1) return fullContent;
|
|
54
|
+
return fullContent.slice(separatorIndex + '\n---\n'.length);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function extractCopilotInstructionsSnippet(fullContent) {
|
|
58
|
+
// Extract the markdown block between ```markdown and ```
|
|
59
|
+
const match = fullContent.match(/```markdown\n([\s\S]*?)```/);
|
|
60
|
+
if (!match) return null;
|
|
61
|
+
return match[1].trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Main ---
|
|
65
|
+
|
|
66
|
+
async function main() {
|
|
67
|
+
const force = process.argv.includes('--force');
|
|
68
|
+
const cwd = process.cwd();
|
|
69
|
+
|
|
70
|
+
console.log('');
|
|
71
|
+
console.log(` ${pc.bold(pc.cyan('Vibeflow'))} ${pc.dim('— Copilot Edition')}`);
|
|
72
|
+
console.log('');
|
|
73
|
+
|
|
74
|
+
// Check Node.js version
|
|
75
|
+
const nodeVersion = parseInt(process.versions.node.split('.')[0]);
|
|
76
|
+
if (nodeVersion < 18) {
|
|
77
|
+
log(pc.red('x'), `Node.js 18+ required (you have ${process.versions.node})`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check if already installed
|
|
82
|
+
const markerFile = join(cwd, '.github/prompts/vibeflow-analyze.prompt.md');
|
|
83
|
+
if (existsSync(markerFile) && !force) {
|
|
84
|
+
log(pc.yellow('!'), 'Vibeflow already installed. Use --force to reinstall.');
|
|
85
|
+
console.log('');
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Download and install files
|
|
90
|
+
let created = 0;
|
|
91
|
+
let skipped = 0;
|
|
92
|
+
|
|
93
|
+
for (const file of FILES) {
|
|
94
|
+
const destPath = join(cwd, file.dest);
|
|
95
|
+
const destDir = join(destPath, '..');
|
|
96
|
+
|
|
97
|
+
if (existsSync(destPath) && !force) {
|
|
98
|
+
log(pc.dim('-'), `${pc.dim(file.dest)} ${pc.dim('(exists, skipped)')}`);
|
|
99
|
+
skipped++;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const content = await downloadFile(file.src);
|
|
105
|
+
ensureDir(destDir);
|
|
106
|
+
writeFileSync(destPath, content, 'utf-8');
|
|
107
|
+
log(pc.green('+'), file.dest);
|
|
108
|
+
created++;
|
|
109
|
+
} catch (err) {
|
|
110
|
+
log(pc.red('x'), `${file.dest} — ${err.message}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log('');
|
|
116
|
+
|
|
117
|
+
// Handle AGENTS.md
|
|
118
|
+
const agentsPath = join(cwd, 'AGENTS.md');
|
|
119
|
+
try {
|
|
120
|
+
const agentsSource = await downloadFile('AGENTS.md');
|
|
121
|
+
const appendContent = extractAgentsAppendContent(agentsSource);
|
|
122
|
+
|
|
123
|
+
if (existsSync(agentsPath)) {
|
|
124
|
+
const existing = readFileSync(agentsPath, 'utf-8');
|
|
125
|
+
if (existing.includes(DUPLICATE_MARKER) && !force) {
|
|
126
|
+
log(pc.dim('-'), `${pc.dim('AGENTS.md')} ${pc.dim('(vibeflow block exists, skipped)')}`);
|
|
127
|
+
} else {
|
|
128
|
+
const updated = existing.trimEnd() + '\n\n' + appendContent;
|
|
129
|
+
writeFileSync(agentsPath, updated, 'utf-8');
|
|
130
|
+
log(pc.green('+'), `AGENTS.md ${pc.dim('(appended vibeflow block)')}`);
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
writeFileSync(agentsPath, appendContent, 'utf-8');
|
|
134
|
+
log(pc.green('+'), `AGENTS.md ${pc.dim('(created)')}`);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
log(pc.red('x'), `AGENTS.md — ${err.message}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
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)')}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
log(pc.dim('-'), `${pc.dim('.github/copilot-instructions.md')} ${pc.dim('(not found, skipping — instructions auto-loaded)')}`);
|
|
158
|
+
}
|
|
159
|
+
} catch (err) {
|
|
160
|
+
log(pc.red('x'), `.github/copilot-instructions.md — ${err.message}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Summary
|
|
164
|
+
console.log('');
|
|
165
|
+
if (created > 0) {
|
|
166
|
+
log(pc.green('✓'), pc.bold(`Done! ${created} files installed.`));
|
|
167
|
+
} else if (skipped > 0) {
|
|
168
|
+
log(pc.yellow('!'), pc.bold('All files already exist. Nothing to do.'));
|
|
169
|
+
}
|
|
170
|
+
console.log('');
|
|
171
|
+
log(pc.cyan('→'), `Run ${pc.bold('/vibeflow-analyze')} in Copilot Chat to get started.`);
|
|
172
|
+
console.log('');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
main().catch((err) => {
|
|
176
|
+
console.error('');
|
|
177
|
+
console.error(` ${pc.red('Error:')} ${err.message}`);
|
|
178
|
+
console.error('');
|
|
179
|
+
process.exit(1);
|
|
180
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "setup-vibeflow",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install Vibeflow (spec-driven development) in your project",
|
|
5
|
+
"bin": {
|
|
6
|
+
"setup-vibeflow": "./index.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"vibeflow",
|
|
14
|
+
"copilot",
|
|
15
|
+
"github-copilot",
|
|
16
|
+
"spec-driven",
|
|
17
|
+
"prompts",
|
|
18
|
+
"agents"
|
|
19
|
+
],
|
|
20
|
+
"author": "pe-menezes",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/pe-menezes/vibeflow"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"picocolors": "^1.1.0"
|
|
28
|
+
}
|
|
29
|
+
}
|