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.
Files changed (40) hide show
  1. package/README.md +100 -0
  2. package/dist/detector.d.ts +16 -0
  3. package/dist/detector.js +103 -0
  4. package/dist/index.d.ts +8 -0
  5. package/dist/index.js +239 -0
  6. package/dist/installer.d.ts +30 -0
  7. package/dist/installer.js +224 -0
  8. package/dist/setup.d.ts +17 -0
  9. package/dist/setup.js +161 -0
  10. package/dist/types.d.ts +88 -0
  11. package/dist/types.js +4 -0
  12. package/dist/ui.d.ts +11 -0
  13. package/dist/ui.js +47 -0
  14. package/package.json +57 -0
  15. package/stacks/_shared/agents/claude-md-compactor.md +44 -0
  16. package/stacks/_shared/agents/commit-manager.md +65 -0
  17. package/stacks/_shared/agents/documenter.md +82 -0
  18. package/stacks/_shared/agents/domain-updater.md +51 -0
  19. package/stacks/_shared/agents/research-web.md +60 -0
  20. package/stacks/_shared/agents/tester.md +61 -0
  21. package/stacks/_shared/commands/feature.md +13 -0
  22. package/stacks/_shared/commands/fix.md +9 -0
  23. package/stacks/_shared/commands/validate.md +10 -0
  24. package/stacks/_shared/config/domain-mapping.json +41 -0
  25. package/stacks/_shared/config/security-rules.json +31 -0
  26. package/stacks/_shared/hooks/stop-validator.ts +171 -0
  27. package/stacks/_shared/hooks/user-prompt-submit.ts +77 -0
  28. package/stacks/_shared/skills/debugging-patterns/SKILL.md +39 -0
  29. package/stacks/_shared/skills/docker-patterns/SKILL.md +47 -0
  30. package/stacks/_shared/skills/git-workflow/SKILL.md +35 -0
  31. package/stacks/nodejs/stack.json +87 -0
  32. package/stacks/php/config/quality-gates.json +23 -0
  33. package/stacks/php/skills/composer-workflow/SKILL.md +78 -0
  34. package/stacks/php/skills/php-patterns/SKILL.md +119 -0
  35. package/stacks/php/skills/phpstan-analysis/SKILL.md +68 -0
  36. package/stacks/php/skills/phpunit-testing/SKILL.md +122 -0
  37. package/stacks/php/skills/security-scan-php/SKILL.md +80 -0
  38. package/stacks/php/stack.json +95 -0
  39. package/templates/CLAUDE-default.md +54 -0
  40. package/templates/CLAUDE-php.md +88 -0
@@ -0,0 +1,224 @@
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 { execSync } from 'child_process';
8
+ import { platform } from 'os';
9
+ import * as semver from 'semver';
10
+ import ora from 'ora';
11
+ import * as ui from './ui.js';
12
+ const OS = platform();
13
+ /**
14
+ * Get installed version of a tool
15
+ */
16
+ function getVersion(command, versionFlag, regex) {
17
+ try {
18
+ const output = execSync(`${command} ${versionFlag} 2>&1`, {
19
+ encoding: 'utf8',
20
+ timeout: 10000,
21
+ }).trim();
22
+ const match = output.match(new RegExp(regex));
23
+ return match ? match[1] : null;
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ /**
30
+ * Check if Homebrew is installed (macOS)
31
+ */
32
+ function hasHomebrew() {
33
+ try {
34
+ execSync('which brew', { encoding: 'utf8', stdio: 'pipe' });
35
+ return true;
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }
41
+ /**
42
+ * Install Homebrew on macOS
43
+ */
44
+ function installHomebrew() {
45
+ const spinner = ora('Installing Homebrew...').start();
46
+ try {
47
+ execSync('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: 'inherit', timeout: 300000 });
48
+ spinner.succeed('Homebrew installed');
49
+ return true;
50
+ }
51
+ catch {
52
+ spinner.fail('Failed to install Homebrew');
53
+ return false;
54
+ }
55
+ }
56
+ /**
57
+ * Install a dependency using the appropriate system command
58
+ */
59
+ function installDependency(req) {
60
+ const cmd = OS === 'darwin' ? req.installCommand.macos : req.installCommand.linux;
61
+ if (!cmd)
62
+ return false;
63
+ const spinner = ora(`Installing ${req.name}...`).start();
64
+ try {
65
+ execSync(cmd, { stdio: 'pipe', timeout: 300000 });
66
+ spinner.succeed(`${req.name} installed`);
67
+ return true;
68
+ }
69
+ catch (err) {
70
+ spinner.fail(`Failed to install ${req.name}`);
71
+ return false;
72
+ }
73
+ }
74
+ /**
75
+ * Validate all requirements for a stack
76
+ */
77
+ export function validateRequirements(requirements) {
78
+ const results = [];
79
+ for (const req of requirements) {
80
+ const version = getVersion(req.command, req.versionFlag, req.versionRegex);
81
+ const installed = version !== null;
82
+ let meetsMinimum = false;
83
+ if (installed && version) {
84
+ try {
85
+ const cleaned = semver.coerce(version);
86
+ const minCleaned = semver.coerce(req.minVersion);
87
+ if (cleaned && minCleaned) {
88
+ meetsMinimum = semver.gte(cleaned, minCleaned);
89
+ }
90
+ }
91
+ catch {
92
+ meetsMinimum = false;
93
+ }
94
+ }
95
+ results.push({
96
+ name: req.name,
97
+ installed,
98
+ version,
99
+ meetsMinimum,
100
+ minVersion: req.minVersion,
101
+ });
102
+ }
103
+ return results;
104
+ }
105
+ /**
106
+ * Auto-install missing or outdated requirements
107
+ */
108
+ export async function autoInstall(requirements) {
109
+ ui.header('🔍 Validating Requirements');
110
+ // Ensure Homebrew on macOS
111
+ if (OS === 'darwin' && !hasHomebrew()) {
112
+ ui.warn('Homebrew not found. Installing...');
113
+ if (!installHomebrew()) {
114
+ ui.error('Cannot proceed without Homebrew on macOS');
115
+ return false;
116
+ }
117
+ }
118
+ const results = validateRequirements(requirements);
119
+ let allGood = true;
120
+ for (const result of results) {
121
+ if (result.installed && result.meetsMinimum) {
122
+ ui.success(`${result.name} ${result.version} (>= ${result.minVersion})`);
123
+ }
124
+ else if (result.installed && !result.meetsMinimum) {
125
+ ui.warn(`${result.name} ${result.version} is below minimum ${result.minVersion}`);
126
+ const req = requirements.find((r) => r.name === result.name);
127
+ if (!installDependency(req)) {
128
+ allGood = false;
129
+ }
130
+ }
131
+ else {
132
+ ui.warn(`${result.name} not found`);
133
+ const req = requirements.find((r) => r.name === result.name);
134
+ if (!installDependency(req)) {
135
+ allGood = false;
136
+ }
137
+ }
138
+ }
139
+ // Re-validate after installation
140
+ if (!allGood) {
141
+ console.log('');
142
+ ui.info('Re-validating after installation...');
143
+ const recheck = validateRequirements(requirements);
144
+ allGood = recheck.every((r) => r.installed && r.meetsMinimum);
145
+ if (!allGood) {
146
+ const failing = recheck.filter((r) => !r.installed || !r.meetsMinimum);
147
+ for (const f of failing) {
148
+ ui.error(`${f.name}: ${f.installed ? `v${f.version} < ${f.minVersion}` : 'not found'}`);
149
+ }
150
+ }
151
+ }
152
+ return allGood;
153
+ }
154
+ /**
155
+ * Install Composer using PHP 8.3+
156
+ */
157
+ export async function installComposer() {
158
+ // Check if composer exists
159
+ const composerVersion = getVersion('composer', '--version', '(\\d+\\.\\d+\\.\\d+)');
160
+ if (composerVersion) {
161
+ ui.success(`Composer ${composerVersion} already installed`);
162
+ return true;
163
+ }
164
+ ui.warn('Composer not found. Installing via PHP...');
165
+ // Verify PHP is available first
166
+ const phpVersion = getVersion('php', '-v', 'PHP\\s+(\\d+\\.\\d+\\.\\d+)');
167
+ if (!phpVersion) {
168
+ ui.error('PHP not found. Install PHP first.');
169
+ return false;
170
+ }
171
+ const spinner = ora('Installing Composer...').start();
172
+ try {
173
+ // Official Composer install method
174
+ const commands = [
175
+ 'php -r "copy(\'https://getcomposer.org/installer\', \'composer-setup.php\');"',
176
+ 'php composer-setup.php',
177
+ 'php -r "unlink(\'composer-setup.php\');"',
178
+ ];
179
+ if (OS === 'darwin') {
180
+ commands.push('sudo mv composer.phar /usr/local/bin/composer');
181
+ }
182
+ else {
183
+ commands.push('sudo mv composer.phar /usr/local/bin/composer');
184
+ }
185
+ for (const cmd of commands) {
186
+ execSync(cmd, { stdio: 'pipe', timeout: 60000 });
187
+ }
188
+ spinner.succeed('Composer installed globally');
189
+ return true;
190
+ }
191
+ catch {
192
+ spinner.fail('Failed to install Composer');
193
+ ui.info('Manual install: https://getcomposer.org/download/');
194
+ return false;
195
+ }
196
+ }
197
+ /**
198
+ * Install Claude Code if not present
199
+ */
200
+ export function installClaudeCode() {
201
+ try {
202
+ execSync('which claude', { stdio: 'pipe' });
203
+ const version = getVersion('claude', '--version', '(\\d+\\.\\d+\\.\\d+)');
204
+ ui.success(`Claude Code ${version || 'installed'}`);
205
+ return true;
206
+ }
207
+ catch {
208
+ ui.warn('Claude Code not found. Installing...');
209
+ const spinner = ora('Installing Claude Code...').start();
210
+ try {
211
+ execSync('npm install -g @anthropic-ai/claude-code', {
212
+ stdio: 'pipe',
213
+ timeout: 120000,
214
+ });
215
+ spinner.succeed('Claude Code installed');
216
+ return true;
217
+ }
218
+ catch {
219
+ spinner.fail('Failed to install Claude Code');
220
+ ui.info('Manual install: npm install -g @anthropic-ai/claude-code');
221
+ return false;
222
+ }
223
+ }
224
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Start Vibing Stacks — Setup Engine
3
+ *
4
+ * Copies and configures stack-specific files into the project.
5
+ */
6
+ import type { ProjectConfig, StackConfig } from './types.js';
7
+ /**
8
+ * Load a stack configuration from stacks/{id}/stack.json
9
+ */
10
+ export declare function loadStackConfig(stackId: string): StackConfig | null;
11
+ /**
12
+ * Setup the project with the selected configuration
13
+ */
14
+ export declare function setupProject(projectDir: string, config: ProjectConfig, options?: {
15
+ force?: boolean;
16
+ noClaude?: boolean;
17
+ }): Promise<boolean>;
package/dist/setup.js ADDED
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Start Vibing Stacks — Setup Engine
3
+ *
4
+ * Copies and configures stack-specific files into the project.
5
+ */
6
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
7
+ import { join, dirname, resolve } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import ora from 'ora';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ const PACKAGE_ROOT = resolve(__dirname, '..');
13
+ /**
14
+ * Load a stack configuration from stacks/{id}/stack.json
15
+ */
16
+ export function loadStackConfig(stackId) {
17
+ const stackPath = join(PACKAGE_ROOT, 'stacks', stackId, 'stack.json');
18
+ if (!existsSync(stackPath))
19
+ return null;
20
+ try {
21
+ const raw = readFileSync(stackPath, 'utf8');
22
+ return JSON.parse(raw);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ /**
29
+ * Copy directory recursively, preserving structure
30
+ */
31
+ function copyDirRecursive(src, dest, overwrite = false) {
32
+ if (!existsSync(src))
33
+ return 0;
34
+ let count = 0;
35
+ mkdirSync(dest, { recursive: true });
36
+ const entries = readdirSync(src);
37
+ for (const entry of entries) {
38
+ const srcPath = join(src, entry);
39
+ const destPath = join(dest, entry);
40
+ const stat = statSync(srcPath);
41
+ if (stat.isDirectory()) {
42
+ count += copyDirRecursive(srcPath, destPath, overwrite);
43
+ }
44
+ else {
45
+ if (!existsSync(destPath) || overwrite) {
46
+ const content = readFileSync(srcPath, 'utf8');
47
+ mkdirSync(dirname(destPath), { recursive: true });
48
+ writeFileSync(destPath, content);
49
+ count++;
50
+ }
51
+ }
52
+ }
53
+ return count;
54
+ }
55
+ /**
56
+ * Setup the project with the selected configuration
57
+ */
58
+ export async function setupProject(projectDir, config, options = {}) {
59
+ const spinner = ora('Setting up project...').start();
60
+ const claudeDir = join(projectDir, '.claude');
61
+ try {
62
+ // 1. Create .claude directory structure
63
+ mkdirSync(join(claudeDir, 'agents'), { recursive: true });
64
+ mkdirSync(join(claudeDir, 'skills'), { recursive: true });
65
+ mkdirSync(join(claudeDir, 'hooks'), { recursive: true });
66
+ mkdirSync(join(claudeDir, 'config'), { recursive: true });
67
+ mkdirSync(join(claudeDir, 'commands'), { recursive: true });
68
+ mkdirSync(join(claudeDir, 'skills', 'codebase-knowledge', 'domains'), { recursive: true });
69
+ spinner.text = 'Directory structure created';
70
+ // 2. Copy shared agents (universal)
71
+ const sharedAgentsDir = join(PACKAGE_ROOT, 'stacks', '_shared', 'agents');
72
+ const agentCount = copyDirRecursive(sharedAgentsDir, join(claudeDir, 'agents'), options.force);
73
+ spinner.text = `Copied ${agentCount} universal agents`;
74
+ // 3. Copy shared skills
75
+ const sharedSkillsDir = join(PACKAGE_ROOT, 'stacks', '_shared', 'skills');
76
+ const sharedSkillCount = copyDirRecursive(sharedSkillsDir, join(claudeDir, 'skills'), options.force);
77
+ // 4. Copy shared hooks
78
+ const sharedHooksDir = join(PACKAGE_ROOT, 'stacks', '_shared', 'hooks');
79
+ const hookCount = copyDirRecursive(sharedHooksDir, join(claudeDir, 'hooks'), options.force);
80
+ // 5. Copy shared config
81
+ const sharedConfigDir = join(PACKAGE_ROOT, 'stacks', '_shared', 'config');
82
+ copyDirRecursive(sharedConfigDir, join(claudeDir, 'config'), options.force);
83
+ // 6. Copy stack-specific skills
84
+ const stackSkillsDir = join(PACKAGE_ROOT, 'stacks', config.stack, 'skills');
85
+ const stackSkillCount = copyDirRecursive(stackSkillsDir, join(claudeDir, 'skills'), options.force);
86
+ // 7. Copy stack-specific config
87
+ const stackConfigDir = join(PACKAGE_ROOT, 'stacks', config.stack, 'config');
88
+ copyDirRecursive(stackConfigDir, join(claudeDir, 'config'), options.force);
89
+ // 8. Copy frontend-specific skills if applicable
90
+ if (config.frontend && config.frontend !== 'none') {
91
+ const frontendDir = join(PACKAGE_ROOT, 'stacks', 'frontend', config.frontend);
92
+ if (existsSync(frontendDir)) {
93
+ const feSkillCount = copyDirRecursive(join(frontendDir, 'skills'), join(claudeDir, 'skills'), options.force);
94
+ spinner.text = `Loaded ${feSkillCount} frontend skills`;
95
+ }
96
+ }
97
+ // 9. Write active-project.json
98
+ writeFileSync(join(claudeDir, 'config', 'active-project.json'), JSON.stringify(config, null, 2));
99
+ // 10. Write/merge CLAUDE.md from template
100
+ const claudeMdTemplate = join(PACKAGE_ROOT, 'templates', `CLAUDE-${config.stack}.md`);
101
+ const claudeMdFallback = join(PACKAGE_ROOT, 'templates', 'CLAUDE-default.md');
102
+ const templatePath = existsSync(claudeMdTemplate) ? claudeMdTemplate : claudeMdFallback;
103
+ const claudeMdDest = join(projectDir, 'CLAUDE.md');
104
+ if (!existsSync(claudeMdDest) || options.force) {
105
+ let template = readFileSync(templatePath, 'utf8');
106
+ // Replace placeholders
107
+ template = template
108
+ .replace(/\{\{PROJECT_NAME\}\}/g, config.name)
109
+ .replace(/\{\{STACK\}\}/g, config.stack.toUpperCase())
110
+ .replace(/\{\{FRAMEWORK\}\}/g, config.framework)
111
+ .replace(/\{\{DATABASE\}\}/g, config.database)
112
+ .replace(/\{\{DATE\}\}/g, new Date().toISOString().split('T')[0]);
113
+ writeFileSync(claudeMdDest, template);
114
+ }
115
+ else if (existsSync(claudeMdDest)) {
116
+ // Backup existing CLAUDE.md as template for smart merge
117
+ const existing = readFileSync(claudeMdDest, 'utf8');
118
+ if (existsSync(templatePath)) {
119
+ writeFileSync(join(claudeDir, 'CLAUDE.template.md'), readFileSync(templatePath, 'utf8'));
120
+ }
121
+ }
122
+ // 11. Handle .cursorrules integration
123
+ if (config.cursorRules) {
124
+ const cursorRulesPath = join(projectDir, '.cursorrules');
125
+ if (existsSync(cursorRulesPath)) {
126
+ const cursorContent = readFileSync(cursorRulesPath, 'utf8');
127
+ const cursorIntegrationPath = join(claudeDir, 'config', 'cursor-rules-imported.md');
128
+ writeFileSync(cursorIntegrationPath, `# Imported from .cursorrules\n\n${cursorContent}`);
129
+ spinner.text = 'Imported .cursorrules into Claude config';
130
+ }
131
+ }
132
+ // 12. Copy commands
133
+ const sharedCommandsDir = join(PACKAGE_ROOT, 'stacks', '_shared', 'commands');
134
+ if (existsSync(sharedCommandsDir)) {
135
+ copyDirRecursive(sharedCommandsDir, join(claudeDir, 'commands'), options.force);
136
+ }
137
+ // 13. Write settings.json for Claude Code
138
+ const settings = {
139
+ permissions: {
140
+ allow: [
141
+ 'Bash(*)',
142
+ 'Read(*)',
143
+ 'Write(*)',
144
+ 'Edit(*)',
145
+ 'Grep(*)',
146
+ 'Glob(*)',
147
+ 'WebSearch(*)',
148
+ 'WebFetch(*)',
149
+ ],
150
+ deny: [],
151
+ },
152
+ };
153
+ writeFileSync(join(claudeDir, 'settings.json'), JSON.stringify(settings, null, '\t'));
154
+ spinner.succeed(`Setup complete: ${agentCount} agents, ${sharedSkillCount + stackSkillCount} skills, ${hookCount} hooks`);
155
+ return true;
156
+ }
157
+ catch (err) {
158
+ spinner.fail(`Setup failed: ${err}`);
159
+ return false;
160
+ }
161
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Start Vibing Stacks — Type Definitions
3
+ */
4
+ export interface StackConfig {
5
+ id: string;
6
+ name: string;
7
+ icon: string;
8
+ runtime: string;
9
+ minVersion: string;
10
+ packageManager: string;
11
+ extensions: string[];
12
+ testExtensions: string[];
13
+ detectFiles: string[];
14
+ commands: Record<string, string | null>;
15
+ qualityGates: QualityGate[];
16
+ frameworks: FrameworkOption[];
17
+ databases: DatabaseOption[];
18
+ frontendOptions: FrontendOption[];
19
+ deployTargets: DeployTarget[];
20
+ skills: string[];
21
+ requirements: Requirement[];
22
+ }
23
+ export interface QualityGate {
24
+ name: string;
25
+ command: string;
26
+ required: boolean;
27
+ order: number;
28
+ }
29
+ export interface FrameworkOption {
30
+ id: string;
31
+ name: string;
32
+ icon: string;
33
+ detectFiles?: string[];
34
+ extra?: Record<string, unknown>;
35
+ }
36
+ export interface DatabaseOption {
37
+ id: string;
38
+ name: string;
39
+ icon: string;
40
+ }
41
+ export interface FrontendOption {
42
+ id: string;
43
+ name: string;
44
+ icon: string;
45
+ }
46
+ export interface DeployTarget {
47
+ id: string;
48
+ name: string;
49
+ icon: string;
50
+ }
51
+ export interface Requirement {
52
+ name: string;
53
+ command: string;
54
+ versionFlag: string;
55
+ minVersion: string;
56
+ installCommand: {
57
+ macos: string;
58
+ linux: string;
59
+ };
60
+ versionRegex: string;
61
+ }
62
+ export interface ProjectConfig {
63
+ name: string;
64
+ stack: string;
65
+ framework: string;
66
+ database: string;
67
+ frontend: string;
68
+ deploy: string;
69
+ path: string;
70
+ createdAt: string;
71
+ skills: string[];
72
+ qualityGates: string;
73
+ cursorRules: boolean;
74
+ domains: Record<string, {
75
+ patterns: string[];
76
+ }>;
77
+ }
78
+ export interface DetectionResult {
79
+ files: string[];
80
+ stacks: {
81
+ id: string;
82
+ confidence: number;
83
+ reason: string;
84
+ }[];
85
+ hasCursorRules: boolean;
86
+ hasClaudeMd: boolean;
87
+ hasGit: boolean;
88
+ }
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Start Vibing Stacks — Type Definitions
3
+ */
4
+ export {};
package/dist/ui.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Start Vibing Stacks — Terminal UI
3
+ */
4
+ export declare const LOGO: string;
5
+ export declare function header(text: string): void;
6
+ export declare function success(text: string): void;
7
+ export declare function warn(text: string): void;
8
+ export declare function error(text: string): void;
9
+ export declare function info(text: string): void;
10
+ export declare function step(n: number, total: number, text: string): void;
11
+ export declare function configSummary(config: Record<string, string>): void;
package/dist/ui.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Start Vibing Stacks — Terminal UI
3
+ */
4
+ import chalk from 'chalk';
5
+ export const LOGO = `
6
+ ${chalk.red(' /\\ /\\')}
7
+ ${chalk.red(' / \\\\')} ${chalk.white('██╗ ██╗')}${chalk.red(' / \\\\')}
8
+ ${chalk.red(' / \\\\')} ${chalk.white('████╗ ████║')}${chalk.red(' / \\\\')}
9
+ ${chalk.red(' / /\\ \\\\')}${chalk.white('██╔═██╔═██║')}${chalk.red(' / /\\ \\\\')}
10
+ ${chalk.red(' / / \\ \\\\')}${chalk.white('██║ ██║ ██║')}${chalk.red(' / / \\ \\\\')}
11
+ ${chalk.red('/_/ \\__\\\\')}${chalk.white('╚═╝ ╚═╝ ╚═╝')}${chalk.red(' /_/ \\__\\\\')}
12
+
13
+ ${chalk.bold(' START VIBING STACKS')}${chalk.dim(' · Multi-stack AI workflow · v1.0.0')}
14
+ `;
15
+ export function header(text) {
16
+ console.log('');
17
+ console.log(chalk.cyan(' ┌' + '─'.repeat(48) + '┐'));
18
+ console.log(chalk.cyan(' │') + ' ' + chalk.bold(text).padEnd(54) + chalk.cyan('│'));
19
+ console.log(chalk.cyan(' └' + '─'.repeat(48) + '┘'));
20
+ }
21
+ export function success(text) {
22
+ console.log(chalk.green(' ✅ ') + text);
23
+ }
24
+ export function warn(text) {
25
+ console.log(chalk.yellow(' ⚠️ ') + text);
26
+ }
27
+ export function error(text) {
28
+ console.log(chalk.red(' ❌ ') + text);
29
+ }
30
+ export function info(text) {
31
+ console.log(chalk.blue(' ℹ️ ') + text);
32
+ }
33
+ export function step(n, total, text) {
34
+ console.log(chalk.dim(` [${n}/${total}]`) + ' ' + text);
35
+ }
36
+ export function configSummary(config) {
37
+ console.log('');
38
+ console.log(chalk.cyan(' ╔' + '═'.repeat(48) + '╗'));
39
+ console.log(chalk.cyan(' ║') + chalk.bold(' 📋 Project Configuration').padEnd(55) + chalk.cyan('║'));
40
+ console.log(chalk.cyan(' ╠' + '═'.repeat(48) + '╣'));
41
+ for (const [key, value] of Object.entries(config)) {
42
+ const line = ` ${chalk.dim(key + ':')} ${value}`;
43
+ console.log(chalk.cyan(' ║') + line.padEnd(69) + chalk.cyan('║'));
44
+ }
45
+ console.log(chalk.cyan(' ╚' + '═'.repeat(48) + '╝'));
46
+ console.log('');
47
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "start-vibing-stacks",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered multi-stack dev workflow for Claude Code. Supports PHP, Node.js, Python and more.",
5
+ "type": "module",
6
+ "bin": {
7
+ "start-vibing-stacks": "dist/index.js",
8
+ "svs": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "npx -p typescript tsc",
12
+ "dev": "tsx src/index.ts",
13
+ "start": "node dist/index.js",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "claude-code",
18
+ "ai",
19
+ "coding",
20
+ "agents",
21
+ "workflow",
22
+ "php",
23
+ "nodejs",
24
+ "typescript",
25
+ "vibing",
26
+ "cursor",
27
+ "multi-stack"
28
+ ],
29
+ "author": "FantasyLake",
30
+ "license": "MIT",
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "files": [
35
+ "dist/",
36
+ "stacks/",
37
+ "templates/",
38
+ "README.md"
39
+ ],
40
+ "dependencies": {
41
+ "chalk": "^5.3.0",
42
+ "inquirer": "^9.2.0",
43
+ "ora": "^7.0.0",
44
+ "semver": "^7.6.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/inquirer": "^9.0.9",
48
+ "@types/node": "^20.19.35",
49
+ "@types/semver": "^7.7.1",
50
+ "tsx": "^4.7.0",
51
+ "typescript": "^5.9.3"
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "https://github.com/f1sc4ll-ai/start-vibing-stacks.git"
56
+ }
57
+ }
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: claude-md-compactor
3
+ description: "AUTOMATICALLY invoke when CLAUDE.md exceeds 40k chars. Compacts while preserving critical knowledge."
4
+ model: sonnet
5
+ tools: Read, Write, Edit, Bash, Grep
6
+ ---
7
+
8
+ # Claude MD Compactor Agent
9
+
10
+ Compact CLAUDE.md when it exceeds 40,000 characters.
11
+
12
+ ## Target Sizes
13
+
14
+ | Section | Max Size |
15
+ |---------|----------|
16
+ | # Title | 1 line |
17
+ | ## Last Change | 200 chars |
18
+ | ## Overview | 300 chars |
19
+ | ## Stack | 500 chars (table) |
20
+ | ## Architecture | 800 chars (tree) |
21
+ | ## Critical Rules | 2000 chars (bullets) |
22
+ | ## FORBIDDEN | 1000 chars (table) |
23
+
24
+ ## Must Remove
25
+
26
+ - Verbose explanations → bullet points
27
+ - Code examples > 5 lines → file references
28
+ - Old "Last Change" entries → git has history
29
+ - Duplicate information
30
+ - Commented-out sections
31
+
32
+ ## Must Keep
33
+
34
+ - Project title, overview, stack table
35
+ - Architecture tree
36
+ - Critical rules (bullets)
37
+ - FORBIDDEN actions table
38
+ - Quality gate commands
39
+
40
+ ## After Compaction
41
+
42
+ ```bash
43
+ wc -m CLAUDE.md # Must be < 40000
44
+ ```