buildflow-dev 1.0.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/LICENSE +21 -0
- package/README.md +266 -0
- package/bin/buildflow.js +80 -0
- package/package.json +60 -0
- package/src/commands/audit.js +230 -0
- package/src/commands/init.js +239 -0
- package/src/commands/install.js +537 -0
- package/src/commands/status.js +62 -0
- package/src/commands/update.js +35 -0
- package/src/index.js +5 -0
- package/src/utils/welcome.js +83 -0
- package/templates/CLAUDE.md +75 -0
- package/templates/commands/audit.md +119 -0
- package/templates/commands/back.md +59 -0
- package/templates/commands/build.md +61 -0
- package/templates/commands/check.md +62 -0
- package/templates/commands/explain.md +53 -0
- package/templates/commands/help.md +84 -0
- package/templates/commands/modify.md +65 -0
- package/templates/commands/onboard.md +78 -0
- package/templates/commands/plan.md +60 -0
- package/templates/commands/refactor.md +58 -0
- package/templates/commands/ship.md +97 -0
- package/templates/commands/start.md +39 -0
- package/templates/commands/status.md +50 -0
- package/templates/commands/think.md +49 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import ora from 'ora'
|
|
3
|
+
import { prompt } from 'enquirer'
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs'
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
import { execSync } from 'child_process'
|
|
7
|
+
import { run as runInstall } from './install.js'
|
|
8
|
+
|
|
9
|
+
function detectProjectInfo() {
|
|
10
|
+
const cwd = process.cwd()
|
|
11
|
+
const info = {
|
|
12
|
+
appName: 'my-project',
|
|
13
|
+
projectType: 'greenfield',
|
|
14
|
+
framework: 'none',
|
|
15
|
+
hasGit: existsSync(join(cwd, '.git')),
|
|
16
|
+
hasTests: false,
|
|
17
|
+
hasSrc: existsSync(join(cwd, 'src')),
|
|
18
|
+
language: 'unknown',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const pkgPath = join(cwd, 'package.json')
|
|
22
|
+
if (existsSync(pkgPath)) {
|
|
23
|
+
try {
|
|
24
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
25
|
+
info.appName = pkg.name || cwd.split('/').pop()
|
|
26
|
+
info.language = 'javascript'
|
|
27
|
+
info.projectType = 'existing'
|
|
28
|
+
|
|
29
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
30
|
+
if (deps?.next) info.framework = 'Next.js'
|
|
31
|
+
else if (deps?.react) info.framework = 'React'
|
|
32
|
+
else if (deps?.vue) info.framework = 'Vue'
|
|
33
|
+
else if (deps?.svelte) info.framework = 'Svelte'
|
|
34
|
+
else if (deps?.express) info.framework = 'Express'
|
|
35
|
+
else if (deps?.fastify) info.framework = 'Fastify'
|
|
36
|
+
else if (deps?.nestjs) info.framework = 'NestJS'
|
|
37
|
+
else info.framework = 'Node.js'
|
|
38
|
+
|
|
39
|
+
info.hasTests = !!(deps?.jest || deps?.vitest || deps?.mocha || deps?.['@playwright/test'])
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (existsSync(join(cwd, 'requirements.txt')) || existsSync(join(cwd, 'pyproject.toml'))) {
|
|
44
|
+
info.language = 'python'
|
|
45
|
+
info.projectType = 'existing'
|
|
46
|
+
try {
|
|
47
|
+
const req = readFileSync(join(cwd, 'requirements.txt'), 'utf8').toLowerCase()
|
|
48
|
+
if (req.includes('django')) info.framework = 'Django'
|
|
49
|
+
else if (req.includes('fastapi')) info.framework = 'FastAPI'
|
|
50
|
+
else if (req.includes('flask')) info.framework = 'Flask'
|
|
51
|
+
else info.framework = 'Python'
|
|
52
|
+
} catch {}
|
|
53
|
+
info.hasTests = existsSync(join(cwd, 'tests')) || existsSync(join(cwd, 'test'))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (existsSync(join(cwd, 'Cargo.toml'))) {
|
|
57
|
+
info.language = 'rust'
|
|
58
|
+
info.framework = 'Rust'
|
|
59
|
+
info.projectType = 'existing'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (existsSync(join(cwd, 'go.mod'))) {
|
|
63
|
+
info.language = 'go'
|
|
64
|
+
info.framework = 'Go'
|
|
65
|
+
info.projectType = 'existing'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!existsSync(join(cwd, 'src')) && !existsSync(pkgPath) && !existsSync(join(cwd, 'requirements.txt'))) {
|
|
69
|
+
info.projectType = 'greenfield'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return info
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function scaffoldBuildflow(appName, projectInfo) {
|
|
76
|
+
const base = join(process.cwd(), '.buildflow')
|
|
77
|
+
|
|
78
|
+
const dirs = [
|
|
79
|
+
'core', 'you', 'memory', 'phases',
|
|
80
|
+
'learnings', 'research', 'codebase',
|
|
81
|
+
'security/reports', 'security/rules',
|
|
82
|
+
'security/suppressions',
|
|
83
|
+
]
|
|
84
|
+
for (const d of dirs) mkdirSync(join(base, d), { recursive: true })
|
|
85
|
+
|
|
86
|
+
const today = new Date().toISOString().split('T')[0]
|
|
87
|
+
|
|
88
|
+
writeFileSync(join(base, 'core', 'vision.md'),
|
|
89
|
+
projectInfo.projectType === 'existing'
|
|
90
|
+
? `# Project Vision: ${appName}\n\n## Type\nExisting ${projectInfo.framework} project\n\n## Goals\n[Fill during /buildflow-start]\n\n---\nInitialized: ${today}\n`
|
|
91
|
+
: `# Project Vision: ${appName}\n\n## What I'm Building\n[Fill during /buildflow-start]\n\n---\nInitialized: ${today}\n`
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
writeFileSync(join(base, 'core', 'state.md'),
|
|
95
|
+
`# State\n\nProject: ${appName}\nType: ${projectInfo.projectType}\nFramework: ${projectInfo.framework}\nPhase: 0\nStatus: Initialized\nBuildFlow: 3.0\nDate: ${today}\n`
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
writeFileSync(join(base, 'you', 'preferences.md'),
|
|
99
|
+
`# Preferences\n\nexperience: junior\nproject_type: ${projectInfo.projectType}\nframework: ${projectInfo.framework}\n\nlearning:\n show_explanations: true\n confidence_calibration: true\n source_citations: true\n\nsafety:\n enable_undo: true\n restore_points: true\n\nmemory:\n type: light\n retention_days: 30\n\nparallel:\n enabled: true\n max_researchers: 3\n\nsecurity:\n pre_ship_gate: true\n auto_suggest_on_sensitive: true\n`
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
writeFileSync(join(base, 'memory', 'light.md'),
|
|
103
|
+
`# Light Memory\n\napp: ${appName}\ntype: ${projectInfo.projectType}\nframework: ${projectInfo.framework}\nphase: 0\nlast_session: ${today}\nbuildflow: 3.0\nonboarded: ${projectInfo.projectType === 'greenfield' ? 'n/a' : 'false'}\n\n## Style Fingerprint\n[Auto-populated after first build]\n\n## Recent Decisions\n[Auto-populated]\n`
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
writeFileSync(join(base, 'learnings', 'glossary.md'),
|
|
107
|
+
`# Glossary\n\n## context-rot\nAI quality degrades as conversation grows. Avoided by fresh agents.\n\n## confidence-calibration\nAsking 1-5 before locking decisions. Triggers explanations when low.\n\n## cartographer\nAgent that maps existing codebases for other agents to use.\n\n## surgeon\nAgent that makes precise modifications to existing code.\n\n## security-auditor\nAgent that runs OWASP Top 10 checks before shipping.\n`
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
writeFileSync(join(base, 'learnings', 'decisions.md'),
|
|
111
|
+
`# Decision Log\n\n## ${today} — Initial Setup\nDecision: Use BuildFlow v3.0\nType: ${projectInfo.projectType} (${projectInfo.framework})\nConfidence: 5/5\n`
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
writeFileSync(join(base, 'security', 'DEBT.md'),
|
|
115
|
+
`# Security Debt\n\nTrack deferred security issues.\n\n## Active\n[None]\n`
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return base
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function patchGitignore() {
|
|
122
|
+
const gitignorePath = join(process.cwd(), '.gitignore')
|
|
123
|
+
const entry = '\n# BuildFlow security reports (may contain sensitive findings)\n.buildflow/security/reports/\n'
|
|
124
|
+
|
|
125
|
+
if (existsSync(gitignorePath)) {
|
|
126
|
+
const existing = readFileSync(gitignorePath, 'utf8')
|
|
127
|
+
if (!existing.includes('.buildflow/security/reports')) {
|
|
128
|
+
writeFileSync(gitignorePath, existing + entry)
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
writeFileSync(gitignorePath, entry)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function ensureGit() {
|
|
136
|
+
if (!existsSync(join(process.cwd(), '.git'))) {
|
|
137
|
+
try {
|
|
138
|
+
execSync('git init -q', { cwd: process.cwd() })
|
|
139
|
+
return true
|
|
140
|
+
} catch {
|
|
141
|
+
return false
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return false
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function run(opts = {}) {
|
|
148
|
+
console.log('\n' + chalk.bold.white(' BuildFlow v3.0 — Project Setup') + '\n')
|
|
149
|
+
|
|
150
|
+
const spinner = ora('Analyzing project...').start()
|
|
151
|
+
const projectInfo = detectProjectInfo()
|
|
152
|
+
await new Promise(r => setTimeout(r, 500))
|
|
153
|
+
spinner.stop()
|
|
154
|
+
|
|
155
|
+
if (projectInfo.projectType === 'existing') {
|
|
156
|
+
console.log(chalk.green(` ✓ Detected: ${projectInfo.framework} project`))
|
|
157
|
+
console.log(chalk.dim(` Language: ${projectInfo.language}`))
|
|
158
|
+
console.log(chalk.dim(` Tests: ${projectInfo.hasTests ? 'Yes' : 'Not found'}`))
|
|
159
|
+
console.log(chalk.dim(` Git: ${projectInfo.hasGit ? 'Initialized' : 'Not found'}`))
|
|
160
|
+
} else {
|
|
161
|
+
console.log(chalk.cyan(' Starting fresh (greenfield project)'))
|
|
162
|
+
}
|
|
163
|
+
console.log('')
|
|
164
|
+
|
|
165
|
+
let appName = projectInfo.appName
|
|
166
|
+
|
|
167
|
+
if (!opts.yes) {
|
|
168
|
+
const { confirmedName } = await prompt({
|
|
169
|
+
type: 'input',
|
|
170
|
+
name: 'confirmedName',
|
|
171
|
+
message: 'App name:',
|
|
172
|
+
initial: appName,
|
|
173
|
+
})
|
|
174
|
+
appName = confirmedName || appName
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let projectType = projectInfo.projectType
|
|
178
|
+
if (!opts.yes && !opts.greenfield && !opts.existing) {
|
|
179
|
+
const { type } = await prompt({
|
|
180
|
+
type: 'select',
|
|
181
|
+
name: 'type',
|
|
182
|
+
message: 'Project mode:',
|
|
183
|
+
choices: [
|
|
184
|
+
{
|
|
185
|
+
name: 'existing',
|
|
186
|
+
message: 'Existing codebase — Add BuildFlow to current code',
|
|
187
|
+
hint: 'Enables /buildflow-onboard, /buildflow-modify, /buildflow-refactor',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'greenfield',
|
|
191
|
+
message: 'Greenfield — Starting from scratch',
|
|
192
|
+
hint: 'Enables /buildflow-start, full new project workflow',
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
initial: projectType === 'existing' ? 0 : 1,
|
|
196
|
+
})
|
|
197
|
+
projectType = type
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let wantSecurity = true
|
|
201
|
+
if (!opts.yes) {
|
|
202
|
+
const { security } = await prompt({
|
|
203
|
+
type: 'confirm',
|
|
204
|
+
name: 'security',
|
|
205
|
+
message: 'Enable security layer? (Recommended — OWASP Top 10 + pre-ship gate)',
|
|
206
|
+
initial: true,
|
|
207
|
+
})
|
|
208
|
+
wantSecurity = security
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const sp2 = ora('Setting up .buildflow/ folder...').start()
|
|
212
|
+
scaffoldBuildflow(appName, { ...projectInfo, projectType })
|
|
213
|
+
patchGitignore()
|
|
214
|
+
ensureGit()
|
|
215
|
+
await new Promise(r => setTimeout(r, 300))
|
|
216
|
+
sp2.succeed(chalk.green(' ✓ .buildflow/ scaffold created'))
|
|
217
|
+
|
|
218
|
+
console.log('')
|
|
219
|
+
await runInstall({ ...opts })
|
|
220
|
+
|
|
221
|
+
console.log(chalk.bold.green('\n ✓ BuildFlow initialized!\n'))
|
|
222
|
+
|
|
223
|
+
if (projectType === 'existing') {
|
|
224
|
+
console.log(chalk.white(' Start here:'))
|
|
225
|
+
console.log(chalk.cyan(' /buildflow-onboard') + chalk.dim(' ← analyze your codebase (one-time)'))
|
|
226
|
+
console.log(chalk.cyan(' /buildflow-modify') + chalk.dim(' ← change existing code safely'))
|
|
227
|
+
} else {
|
|
228
|
+
console.log(chalk.white(' Start here:'))
|
|
229
|
+
console.log(chalk.cyan(' /buildflow-start') + chalk.dim(' ← begin your project'))
|
|
230
|
+
console.log(chalk.cyan(' /buildflow-think') + chalk.dim(' ← research and discuss'))
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (wantSecurity) {
|
|
234
|
+
console.log(chalk.dim('\n Security: Pre-ship gate enabled (/buildflow-ship auto-runs audit)'))
|
|
235
|
+
console.log(chalk.dim(' Manual audit: /buildflow-audit'))
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
console.log('')
|
|
239
|
+
}
|