start-vibing-stacks 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/README.md +100 -0
- package/dist/detector.d.ts +16 -0
- package/dist/detector.js +103 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +239 -0
- package/dist/installer.d.ts +30 -0
- package/dist/installer.js +224 -0
- package/dist/setup.d.ts +17 -0
- package/dist/setup.js +161 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.js +4 -0
- package/dist/ui.d.ts +11 -0
- package/dist/ui.js +47 -0
- package/package.json +57 -0
- package/stacks/_shared/agents/claude-md-compactor.md +44 -0
- package/stacks/_shared/agents/commit-manager.md +65 -0
- package/stacks/_shared/agents/documenter.md +82 -0
- package/stacks/_shared/agents/domain-updater.md +51 -0
- package/stacks/_shared/agents/research-web.md +60 -0
- package/stacks/_shared/agents/tester.md +61 -0
- package/stacks/_shared/commands/feature.md +13 -0
- package/stacks/_shared/commands/fix.md +9 -0
- package/stacks/_shared/commands/validate.md +10 -0
- package/stacks/_shared/config/domain-mapping.json +41 -0
- package/stacks/_shared/config/security-rules.json +31 -0
- package/stacks/_shared/hooks/stop-validator.ts +171 -0
- package/stacks/_shared/hooks/user-prompt-submit.ts +77 -0
- package/stacks/_shared/skills/debugging-patterns/SKILL.md +39 -0
- package/stacks/_shared/skills/docker-patterns/SKILL.md +47 -0
- package/stacks/_shared/skills/git-workflow/SKILL.md +35 -0
- package/stacks/nodejs/stack.json +87 -0
- package/stacks/php/config/quality-gates.json +23 -0
- package/stacks/php/skills/composer-workflow/SKILL.md +78 -0
- package/stacks/php/skills/php-patterns/SKILL.md +119 -0
- package/stacks/php/skills/phpstan-analysis/SKILL.md +68 -0
- package/stacks/php/skills/phpunit-testing/SKILL.md +122 -0
- package/stacks/php/skills/security-scan-php/SKILL.md +80 -0
- package/stacks/php/stack.json +95 -0
- package/templates/CLAUDE-default.md +54 -0
- package/templates/CLAUDE-php.md +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# 🎸 Start Vibing Stacks
|
|
2
|
+
|
|
3
|
+
**Multi-stack AI-powered development workflow for Claude Code.**
|
|
4
|
+
|
|
5
|
+
One command to set up agents, skills, hooks, and quality gates — tailored to your stack.
|
|
6
|
+
|
|
7
|
+
## 🚀 Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx start-vibing-stacks
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install globally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g start-vibing-stacks
|
|
17
|
+
svs # shortcut
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## ✨ Features
|
|
21
|
+
|
|
22
|
+
- **🔍 Auto-detection** — Scans your project files to suggest the right stack
|
|
23
|
+
- **🐘 PHP 8.3+** — PHPStan, PHPUnit, Composer, Laravel/Octane, Symfony, Vanilla
|
|
24
|
+
- **📦 Node.js/TS** — Vitest, TypeScript, Bun, Next.js, Express
|
|
25
|
+
- **🎯 Multi-framework** — Choose your framework, database, frontend, deploy target
|
|
26
|
+
- **🤖 6 Universal Agents** — research, documenter, domain-updater, commit-manager, tester, compactor
|
|
27
|
+
- **🛡️ Quality Gates** — Stack-specific validation before every commit
|
|
28
|
+
- **🔒 Security Skills** — OWASP checks adapted per language
|
|
29
|
+
- **📝 .cursorrules support** — Imports existing Cursor IDE rules
|
|
30
|
+
- **⚡ Auto-install** — Validates and installs missing deps (Homebrew on macOS)
|
|
31
|
+
|
|
32
|
+
## 📋 Supported Stacks
|
|
33
|
+
|
|
34
|
+
| Stack | Status | Frameworks |
|
|
35
|
+
|-------|--------|------------|
|
|
36
|
+
| 🐘 PHP 8.3+ | ✅ Ready | Laravel, Laravel+Octane, Symfony, CodeIgniter, Vanilla |
|
|
37
|
+
| 📦 Node.js/TS | ✅ Ready | Next.js, Nuxt, Astro, Express, Fastify |
|
|
38
|
+
| 🐍 Python | 🔜 Soon | Django, FastAPI, Flask |
|
|
39
|
+
| 🦀 Rust | 🔜 Soon | Actix, Axum |
|
|
40
|
+
| 🐹 Go | 🔜 Soon | Gin, Echo |
|
|
41
|
+
|
|
42
|
+
## 🏗️ What It Creates
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
.claude/
|
|
46
|
+
├── agents/ # 6 universal agents (stack-aware)
|
|
47
|
+
├── skills/ # Stack-specific + shared skills
|
|
48
|
+
├── hooks/ # stop-validator + prompt-inject
|
|
49
|
+
├── config/ # Project config, quality gates, security rules
|
|
50
|
+
├── commands/ # /feature, /fix, /validate
|
|
51
|
+
└── settings.json # Claude Code permissions
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 🔧 Options
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx start-vibing-stacks [options]
|
|
58
|
+
|
|
59
|
+
--force Overwrite existing configuration
|
|
60
|
+
--no-claude Skip Claude Code installation
|
|
61
|
+
--no-install Skip dependency installation
|
|
62
|
+
--help, -h Show help
|
|
63
|
+
--version, -v Show version
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 🐘 PHP Requirements
|
|
67
|
+
|
|
68
|
+
When selecting the PHP stack, the tool validates and auto-installs:
|
|
69
|
+
|
|
70
|
+
- **PHP >= 8.3** (via `brew install php@8.3` on macOS)
|
|
71
|
+
- **Composer >= 2.0** (auto-installed using PHP if missing)
|
|
72
|
+
- **Node.js >= 18** (for frontend tooling)
|
|
73
|
+
|
|
74
|
+
### Laravel + Octane (RoadRunner)
|
|
75
|
+
|
|
76
|
+
Select "Laravel + Octane (RoadRunner)" in the framework menu for:
|
|
77
|
+
- RoadRunner server configuration
|
|
78
|
+
- Octane-specific skills and patterns
|
|
79
|
+
- High-performance deployment guides
|
|
80
|
+
|
|
81
|
+
## 📝 Cursor IDE Support
|
|
82
|
+
|
|
83
|
+
If `.cursorrules` is detected in your project, the rules are automatically imported into the Claude agent configuration. Both AI tools work with the same context.
|
|
84
|
+
|
|
85
|
+
## 🔄 How It Works
|
|
86
|
+
|
|
87
|
+
1. **Detect** — Scans project for `composer.json`, `package.json`, etc.
|
|
88
|
+
2. **Select** — You choose stack, framework, database, frontend, deploy
|
|
89
|
+
3. **Validate** — Checks system requirements, installs missing tools
|
|
90
|
+
4. **Configure** — Copies agents, skills, hooks tailored to your choices
|
|
91
|
+
5. **Launch** — Starts Claude Code with everything pre-configured
|
|
92
|
+
|
|
93
|
+
## 📄 License
|
|
94
|
+
|
|
95
|
+
MIT
|
|
96
|
+
|
|
97
|
+
## 🏠 Credits
|
|
98
|
+
|
|
99
|
+
Inspired by [start-vibing](https://www.npmjs.com/package/start-vibing).
|
|
100
|
+
Built by [FantasyLake](https://github.com/f1sc4ll-ai).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start Vibing Stacks — Project Detector
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects project stack by scanning for known files.
|
|
5
|
+
* Also detects .cursorrules, CLAUDE.md, and git presence.
|
|
6
|
+
*/
|
|
7
|
+
import type { DetectionResult } from './types.js';
|
|
8
|
+
export declare function detectProject(projectDir: string): DetectionResult;
|
|
9
|
+
/**
|
|
10
|
+
* Detect framework within a PHP project
|
|
11
|
+
*/
|
|
12
|
+
export declare function detectPhpFramework(projectDir: string): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Detect framework within a Node.js project
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectNodeFramework(projectDir: string): string | null;
|
package/dist/detector.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start Vibing Stacks — Project Detector
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects project stack by scanning for known files.
|
|
5
|
+
* Also detects .cursorrules, CLAUDE.md, and git presence.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readdirSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
const STACK_SIGNATURES = [
|
|
10
|
+
// PHP
|
|
11
|
+
{ id: 'php', files: ['composer.json'], weight: 90, reason: 'composer.json detected' },
|
|
12
|
+
{ id: 'php', files: ['index.php'], weight: 60, reason: 'index.php detected' },
|
|
13
|
+
{ id: 'php', files: ['artisan'], weight: 95, reason: 'Laravel artisan detected' },
|
|
14
|
+
{ id: 'php', files: ['symfony.lock'], weight: 95, reason: 'Symfony lock detected' },
|
|
15
|
+
{ id: 'php', files: ['public/index.php'], weight: 70, reason: 'public/index.php detected' },
|
|
16
|
+
{ id: 'php', files: ['.php-version'], weight: 80, reason: '.php-version detected' },
|
|
17
|
+
// Node.js / TypeScript
|
|
18
|
+
{ id: 'nodejs', files: ['package.json'], weight: 80, reason: 'package.json detected' },
|
|
19
|
+
{ id: 'nodejs', files: ['tsconfig.json'], weight: 85, reason: 'tsconfig.json detected' },
|
|
20
|
+
{ id: 'nodejs', files: ['bun.lockb'], weight: 90, reason: 'Bun lockfile detected' },
|
|
21
|
+
{ id: 'nodejs', files: ['next.config.js'], weight: 95, reason: 'Next.js config detected' },
|
|
22
|
+
{ id: 'nodejs', files: ['next.config.ts'], weight: 95, reason: 'Next.js TS config detected' },
|
|
23
|
+
{ id: 'nodejs', files: ['next.config.mjs'], weight: 95, reason: 'Next.js config detected' },
|
|
24
|
+
// Python
|
|
25
|
+
{ id: 'python', files: ['requirements.txt'], weight: 80, reason: 'requirements.txt detected' },
|
|
26
|
+
{ id: 'python', files: ['pyproject.toml'], weight: 90, reason: 'pyproject.toml detected' },
|
|
27
|
+
{ id: 'python', files: ['Pipfile'], weight: 85, reason: 'Pipfile detected' },
|
|
28
|
+
{ id: 'python', files: ['setup.py'], weight: 75, reason: 'setup.py detected' },
|
|
29
|
+
// Rust
|
|
30
|
+
{ id: 'rust', files: ['Cargo.toml'], weight: 95, reason: 'Cargo.toml detected' },
|
|
31
|
+
// Go
|
|
32
|
+
{ id: 'go', files: ['go.mod'], weight: 95, reason: 'go.mod detected' },
|
|
33
|
+
];
|
|
34
|
+
export function detectProject(projectDir) {
|
|
35
|
+
const result = {
|
|
36
|
+
files: [],
|
|
37
|
+
stacks: [],
|
|
38
|
+
hasCursorRules: false,
|
|
39
|
+
hasClaudeMd: false,
|
|
40
|
+
hasGit: false,
|
|
41
|
+
};
|
|
42
|
+
// Scan top-level files
|
|
43
|
+
try {
|
|
44
|
+
result.files = readdirSync(projectDir);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
// Check for Cursor IDE rules
|
|
50
|
+
result.hasCursorRules =
|
|
51
|
+
existsSync(join(projectDir, '.cursorrules')) ||
|
|
52
|
+
existsSync(join(projectDir, '.cursor', 'rules'));
|
|
53
|
+
// Check for existing CLAUDE.md
|
|
54
|
+
result.hasClaudeMd = existsSync(join(projectDir, 'CLAUDE.md'));
|
|
55
|
+
// Check for git
|
|
56
|
+
result.hasGit = existsSync(join(projectDir, '.git'));
|
|
57
|
+
// Score each stack
|
|
58
|
+
const stackScores = new Map();
|
|
59
|
+
for (const sig of STACK_SIGNATURES) {
|
|
60
|
+
const allExist = sig.files.every((f) => existsSync(join(projectDir, f)));
|
|
61
|
+
if (allExist) {
|
|
62
|
+
const existing = stackScores.get(sig.id) || { confidence: 0, reasons: [] };
|
|
63
|
+
existing.confidence = Math.min(100, existing.confidence + sig.weight);
|
|
64
|
+
existing.reasons.push(sig.reason);
|
|
65
|
+
stackScores.set(sig.id, existing);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Convert to sorted array
|
|
69
|
+
result.stacks = Array.from(stackScores.entries())
|
|
70
|
+
.map(([id, data]) => ({
|
|
71
|
+
id,
|
|
72
|
+
confidence: Math.min(100, data.confidence),
|
|
73
|
+
reason: data.reasons.join(', '),
|
|
74
|
+
}))
|
|
75
|
+
.sort((a, b) => b.confidence - a.confidence);
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Detect framework within a PHP project
|
|
80
|
+
*/
|
|
81
|
+
export function detectPhpFramework(projectDir) {
|
|
82
|
+
if (existsSync(join(projectDir, 'artisan')))
|
|
83
|
+
return 'laravel';
|
|
84
|
+
if (existsSync(join(projectDir, 'symfony.lock')))
|
|
85
|
+
return 'symfony';
|
|
86
|
+
if (existsSync(join(projectDir, 'spark')))
|
|
87
|
+
return 'codeigniter';
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Detect framework within a Node.js project
|
|
92
|
+
*/
|
|
93
|
+
export function detectNodeFramework(projectDir) {
|
|
94
|
+
if (existsSync(join(projectDir, 'next.config.js')) ||
|
|
95
|
+
existsSync(join(projectDir, 'next.config.ts')) ||
|
|
96
|
+
existsSync(join(projectDir, 'next.config.mjs')))
|
|
97
|
+
return 'nextjs';
|
|
98
|
+
if (existsSync(join(projectDir, 'nuxt.config.ts')))
|
|
99
|
+
return 'nuxt';
|
|
100
|
+
if (existsSync(join(projectDir, 'astro.config.mjs')))
|
|
101
|
+
return 'astro';
|
|
102
|
+
return null;
|
|
103
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Start Vibing Stacks — CLI Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Multi-stack AI-powered development workflow for Claude Code.
|
|
6
|
+
* Detects project stack, validates requirements, and configures agents.
|
|
7
|
+
*/
|
|
8
|
+
import { basename } from 'path';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import * as ui from './ui.js';
|
|
12
|
+
import { detectProject, detectPhpFramework, detectNodeFramework } from './detector.js';
|
|
13
|
+
import { autoInstall, installComposer, installClaudeCode } from './installer.js';
|
|
14
|
+
import { loadStackConfig, setupProject } from './setup.js';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// CLI Arguments
|
|
17
|
+
// =============================================================================
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const FLAGS = {
|
|
20
|
+
force: args.includes('--force'),
|
|
21
|
+
noClaude: args.includes('--no-claude'),
|
|
22
|
+
noInstall: args.includes('--no-install'),
|
|
23
|
+
help: args.includes('--help') || args.includes('-h'),
|
|
24
|
+
version: args.includes('--version') || args.includes('-v'),
|
|
25
|
+
};
|
|
26
|
+
if (FLAGS.version) {
|
|
27
|
+
console.log('1.0.0');
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
if (FLAGS.help) {
|
|
31
|
+
console.log(ui.LOGO);
|
|
32
|
+
console.log(`
|
|
33
|
+
${chalk.bold('Usage:')}
|
|
34
|
+
npx start-vibing-stacks [options]
|
|
35
|
+
|
|
36
|
+
${chalk.bold('Options:')}
|
|
37
|
+
--force Overwrite existing configuration
|
|
38
|
+
--no-claude Skip Claude Code installation
|
|
39
|
+
--no-install Skip dependency installation
|
|
40
|
+
--help, -h Show this help
|
|
41
|
+
--version, -v Show version
|
|
42
|
+
|
|
43
|
+
${chalk.bold('Supported Stacks:')}
|
|
44
|
+
🐘 PHP 8.3+ Laravel, Symfony, CodeIgniter, Vanilla
|
|
45
|
+
📦 Node.js/TS Next.js, Nuxt, Express, Fastify
|
|
46
|
+
🐍 Python Django, FastAPI, Flask (coming soon)
|
|
47
|
+
🦀 Rust (coming soon)
|
|
48
|
+
🐹 Go (coming soon)
|
|
49
|
+
`);
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
const AVAILABLE_STACKS = [
|
|
53
|
+
{ id: 'php', name: 'PHP 8.3+', icon: '🐘', available: true },
|
|
54
|
+
{ id: 'nodejs', name: 'Node.js / TypeScript', icon: '📦', available: true },
|
|
55
|
+
{ id: 'python', name: 'Python', icon: '🐍', available: false },
|
|
56
|
+
{ id: 'rust', name: 'Rust', icon: '🦀', available: false },
|
|
57
|
+
{ id: 'go', name: 'Go', icon: '🐹', available: false },
|
|
58
|
+
];
|
|
59
|
+
// =============================================================================
|
|
60
|
+
// Main Flow
|
|
61
|
+
// =============================================================================
|
|
62
|
+
async function main() {
|
|
63
|
+
console.log(ui.LOGO);
|
|
64
|
+
const projectDir = process.cwd();
|
|
65
|
+
const projectName = basename(projectDir);
|
|
66
|
+
// ─── Step 1: Detect Project ─────────────────────────────────────────────
|
|
67
|
+
ui.header('🔍 Scanning project directory...');
|
|
68
|
+
const detection = detectProject(projectDir);
|
|
69
|
+
if (detection.hasCursorRules) {
|
|
70
|
+
ui.info('.cursorrules detected — will import into Claude config');
|
|
71
|
+
}
|
|
72
|
+
if (detection.hasClaudeMd) {
|
|
73
|
+
ui.info('Existing CLAUDE.md found — will merge with template');
|
|
74
|
+
}
|
|
75
|
+
if (!detection.hasGit) {
|
|
76
|
+
ui.warn('No .git found — recommend initializing git first');
|
|
77
|
+
}
|
|
78
|
+
if (detection.stacks.length > 0) {
|
|
79
|
+
const topStack = detection.stacks[0];
|
|
80
|
+
console.log('');
|
|
81
|
+
ui.success(`Detected: ${topStack.id.toUpperCase()} (${topStack.confidence}% confidence)`);
|
|
82
|
+
ui.info(`Reason: ${topStack.reason}`);
|
|
83
|
+
}
|
|
84
|
+
// ─── Step 2: Select Stack ───────────────────────────────────────────────
|
|
85
|
+
console.log('');
|
|
86
|
+
const { stackId } = await inquirer.prompt([
|
|
87
|
+
{
|
|
88
|
+
type: 'list',
|
|
89
|
+
name: 'stackId',
|
|
90
|
+
message: 'Select your primary stack:',
|
|
91
|
+
default: detection.stacks.length > 0 ? detection.stacks[0].id : undefined,
|
|
92
|
+
choices: AVAILABLE_STACKS.map((s) => ({
|
|
93
|
+
name: `${s.icon} ${s.name}${!s.available ? chalk.dim(' (coming soon)') : ''}`,
|
|
94
|
+
value: s.id,
|
|
95
|
+
disabled: !s.available ? 'Coming soon' : false,
|
|
96
|
+
})),
|
|
97
|
+
},
|
|
98
|
+
]);
|
|
99
|
+
const stackConfig = loadStackConfig(stackId);
|
|
100
|
+
if (!stackConfig) {
|
|
101
|
+
ui.error(`Stack config not found for: ${stackId}`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
// ─── Step 3: Select Framework ──────────────────────────────────────────
|
|
105
|
+
const detectedFramework = stackId === 'php'
|
|
106
|
+
? detectPhpFramework(projectDir)
|
|
107
|
+
: stackId === 'nodejs'
|
|
108
|
+
? detectNodeFramework(projectDir)
|
|
109
|
+
: null;
|
|
110
|
+
const { framework } = await inquirer.prompt([
|
|
111
|
+
{
|
|
112
|
+
type: 'list',
|
|
113
|
+
name: 'framework',
|
|
114
|
+
message: 'Select framework:',
|
|
115
|
+
default: detectedFramework || undefined,
|
|
116
|
+
choices: stackConfig.frameworks.map((f) => ({
|
|
117
|
+
name: `${f.icon} ${f.name}`,
|
|
118
|
+
value: f.id,
|
|
119
|
+
})),
|
|
120
|
+
},
|
|
121
|
+
]);
|
|
122
|
+
// ─── Step 4: Select Database ───────────────────────────────────────────
|
|
123
|
+
const { database } = await inquirer.prompt([
|
|
124
|
+
{
|
|
125
|
+
type: 'list',
|
|
126
|
+
name: 'database',
|
|
127
|
+
message: 'Select database:',
|
|
128
|
+
choices: stackConfig.databases.map((d) => ({
|
|
129
|
+
name: `${d.icon} ${d.name}`,
|
|
130
|
+
value: d.id,
|
|
131
|
+
})),
|
|
132
|
+
},
|
|
133
|
+
]);
|
|
134
|
+
// ─── Step 5: Frontend ──────────────────────────────────────────────────
|
|
135
|
+
const { frontend } = await inquirer.prompt([
|
|
136
|
+
{
|
|
137
|
+
type: 'list',
|
|
138
|
+
name: 'frontend',
|
|
139
|
+
message: 'Frontend included?',
|
|
140
|
+
choices: stackConfig.frontendOptions.map((f) => ({
|
|
141
|
+
name: `${f.icon} ${f.name}`,
|
|
142
|
+
value: f.id,
|
|
143
|
+
})),
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
// ─── Step 6: Deploy Target ─────────────────────────────────────────────
|
|
147
|
+
const { deploy } = await inquirer.prompt([
|
|
148
|
+
{
|
|
149
|
+
type: 'list',
|
|
150
|
+
name: 'deploy',
|
|
151
|
+
message: 'Deployment target?',
|
|
152
|
+
choices: stackConfig.deployTargets.map((d) => ({
|
|
153
|
+
name: `${d.icon} ${d.name}`,
|
|
154
|
+
value: d.id,
|
|
155
|
+
})),
|
|
156
|
+
},
|
|
157
|
+
]);
|
|
158
|
+
// ─── Step 7: Show Summary & Confirm ────────────────────────────────────
|
|
159
|
+
const config = {
|
|
160
|
+
name: projectName,
|
|
161
|
+
stack: stackId,
|
|
162
|
+
framework,
|
|
163
|
+
database,
|
|
164
|
+
frontend,
|
|
165
|
+
deploy,
|
|
166
|
+
path: projectDir,
|
|
167
|
+
createdAt: new Date().toISOString(),
|
|
168
|
+
skills: [...stackConfig.skills],
|
|
169
|
+
qualityGates: `stacks/${stackId}/config/quality-gates.json`,
|
|
170
|
+
cursorRules: detection.hasCursorRules,
|
|
171
|
+
domains: {},
|
|
172
|
+
};
|
|
173
|
+
ui.configSummary({
|
|
174
|
+
'Stack': `${stackConfig.icon} ${stackConfig.name} (${stackConfig.runtime})`,
|
|
175
|
+
'Framework': framework,
|
|
176
|
+
'Database': database,
|
|
177
|
+
'Frontend': frontend,
|
|
178
|
+
'Deploy': deploy,
|
|
179
|
+
'Agents': '6 universal',
|
|
180
|
+
'Skills': `${stackConfig.skills.length} stack + shared`,
|
|
181
|
+
'Hooks': 'stop-validator + prompt-inject',
|
|
182
|
+
'Gates': stackConfig.qualityGates.map((g) => g.name).join(' → '),
|
|
183
|
+
});
|
|
184
|
+
const { confirmed } = await inquirer.prompt([
|
|
185
|
+
{
|
|
186
|
+
type: 'confirm',
|
|
187
|
+
name: 'confirmed',
|
|
188
|
+
message: 'Confirm configuration?',
|
|
189
|
+
default: true,
|
|
190
|
+
},
|
|
191
|
+
]);
|
|
192
|
+
if (!confirmed) {
|
|
193
|
+
ui.info('Setup cancelled.');
|
|
194
|
+
process.exit(0);
|
|
195
|
+
}
|
|
196
|
+
// ─── Step 8: Validate & Install Requirements ──────────────────────────
|
|
197
|
+
if (!FLAGS.noInstall) {
|
|
198
|
+
const reqOk = await autoInstall(stackConfig.requirements);
|
|
199
|
+
if (!reqOk) {
|
|
200
|
+
ui.error('Some requirements could not be installed. Fix manually and retry.');
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
// PHP-specific: install Composer
|
|
204
|
+
if (stackId === 'php') {
|
|
205
|
+
const composerOk = await installComposer();
|
|
206
|
+
if (!composerOk) {
|
|
207
|
+
ui.warn('Composer installation failed — you may need to install it manually');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ─── Step 9: Setup Project ─────────────────────────────────────────────
|
|
212
|
+
ui.header('⚡ Configuring project...');
|
|
213
|
+
const setupOk = await setupProject(projectDir, config, {
|
|
214
|
+
force: FLAGS.force,
|
|
215
|
+
noClaude: FLAGS.noClaude,
|
|
216
|
+
});
|
|
217
|
+
if (!setupOk) {
|
|
218
|
+
ui.error('Setup failed.');
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
// ─── Step 10: Install Claude Code ──────────────────────────────────────
|
|
222
|
+
if (!FLAGS.noClaude) {
|
|
223
|
+
console.log('');
|
|
224
|
+
installClaudeCode();
|
|
225
|
+
}
|
|
226
|
+
// ─── Done ──────────────────────────────────────────────────────────────
|
|
227
|
+
console.log('');
|
|
228
|
+
console.log(chalk.green.bold(' 🎸 Ready to vibe!'));
|
|
229
|
+
console.log('');
|
|
230
|
+
if (!FLAGS.noClaude) {
|
|
231
|
+
console.log(chalk.dim(' Launching Claude Code...'));
|
|
232
|
+
console.log(chalk.dim(' Run: claude --dangerously-skip-permissions'));
|
|
233
|
+
}
|
|
234
|
+
console.log('');
|
|
235
|
+
}
|
|
236
|
+
main().catch((err) => {
|
|
237
|
+
ui.error(`Unexpected error: ${err}`);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start Vibing Stacks — Dependency Installer & Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates system requirements and auto-installs missing dependencies.
|
|
5
|
+
* macOS-first with Homebrew, with Linux fallbacks.
|
|
6
|
+
*/
|
|
7
|
+
import type { Requirement } from './types.js';
|
|
8
|
+
export interface ValidationResult {
|
|
9
|
+
name: string;
|
|
10
|
+
installed: boolean;
|
|
11
|
+
version: string | null;
|
|
12
|
+
meetsMinimum: boolean;
|
|
13
|
+
minVersion: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate all requirements for a stack
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateRequirements(requirements: Requirement[]): ValidationResult[];
|
|
19
|
+
/**
|
|
20
|
+
* Auto-install missing or outdated requirements
|
|
21
|
+
*/
|
|
22
|
+
export declare function autoInstall(requirements: Requirement[]): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Install Composer using PHP 8.3+
|
|
25
|
+
*/
|
|
26
|
+
export declare function installComposer(): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Install Claude Code if not present
|
|
29
|
+
*/
|
|
30
|
+
export declare function installClaudeCode(): boolean;
|