forgestack-os-cli 0.1.0 → 0.1.1

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.
@@ -1,64 +0,0 @@
1
- import path from 'path';
2
- import fs from 'fs-extra';
3
- import { StackConfig } from '../types';
4
- import { logger } from '../utils/logger';
5
- import { generateFrontend } from './frontend';
6
- import { generateBackend } from './backend';
7
- import { generateDatabase } from './database';
8
- import { generateAuth } from './auth';
9
- import { generateDocker } from './docker';
10
- import { generateCommon } from './common';
11
-
12
- export async function generateProject(config: StackConfig, targetDir: string) {
13
- const spinner = logger.spinner('Creating project structure...');
14
-
15
- try {
16
- // Create project directory
17
- await fs.ensureDir(targetDir);
18
-
19
- // Create subdirectories
20
- const frontendDir = path.join(targetDir, 'frontend');
21
- const backendDir = path.join(targetDir, 'backend');
22
-
23
- await fs.ensureDir(frontendDir);
24
- await fs.ensureDir(backendDir);
25
-
26
- spinner.succeed('Project structure created');
27
-
28
- // Generate common files (root package.json, README, .gitignore, etc.)
29
- const commonSpinner = logger.spinner('Generating common files...');
30
- await generateCommon(config, targetDir);
31
- commonSpinner.succeed('Common files generated');
32
-
33
- // Generate frontend
34
- const frontendSpinner = logger.spinner(`Generating ${config.frontend} frontend...`);
35
- await generateFrontend(config, frontendDir);
36
- frontendSpinner.succeed('Frontend generated');
37
-
38
- // Generate backend
39
- const backendSpinner = logger.spinner(`Generating ${config.backend} backend...`);
40
- await generateBackend(config, backendDir);
41
- backendSpinner.succeed('Backend generated');
42
-
43
- // Generate database setup
44
- const dbSpinner = logger.spinner(`Setting up ${config.database} database...`);
45
- await generateDatabase(config, backendDir);
46
- dbSpinner.succeed('Database setup complete');
47
-
48
- // Generate auth integration
49
- const authSpinner = logger.spinner(`Integrating ${config.auth} authentication...`);
50
- await generateAuth(config, frontendDir, backendDir);
51
- authSpinner.succeed('Authentication integrated');
52
-
53
- // Generate Docker configuration if requested
54
- if (config.docker) {
55
- const dockerSpinner = logger.spinner('Generating Docker configuration...');
56
- await generateDocker(config, targetDir);
57
- dockerSpinner.succeed('Docker configuration generated');
58
- }
59
-
60
- } catch (error) {
61
- spinner.fail('Failed to generate project');
62
- throw error;
63
- }
64
- }
package/src/index.ts DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from 'commander';
4
-
5
- import { createCommand } from './commands/create';
6
-
7
- const program = new Command();
8
-
9
- program
10
- .name('forgestack')
11
- .description('ForgeStack OS - One platform. Any stack. Production-ready.')
12
- .version('0.1.0');
13
-
14
- program
15
- .command('create <project-name>')
16
- .description('Create a new full-stack SaaS application')
17
- .action(createCommand)
18
- .option('--frontend <framework>', 'Frontend framework')
19
- .option('--backend <framework>', 'Backend framework')
20
- .option('--auth <provider>', 'Auth provider')
21
- .option('--database <db>', 'Database')
22
- .option('--api <style>', 'API style')
23
- .option('--docker', 'Include Docker configuration')
24
- .option('--no-docker', 'Skip Docker configuration')
25
- .option('--multi-tenant', 'Enable multi-tenancy');
26
-
27
- program.parse();
package/src/types.ts DELETED
@@ -1,16 +0,0 @@
1
- export interface StackConfig {
2
- projectName: string;
3
- frontend: 'react-vite' | 'nextjs' | 'vue-vite' | 'sveltekit';
4
- backend: 'express' | 'fastify' | 'nestjs' | 'bun-elysia' | 'go-fiber';
5
- auth: 'jwt' | 'clerk' | 'supabase' | 'authjs' | 'firebase';
6
- database: 'postgresql' | 'mongodb' | 'mysql' | 'sqlite' | 'supabase-db';
7
- apiStyle: 'rest' | 'graphql' | 'trpc';
8
- docker: boolean;
9
- multiTenant: boolean;
10
- }
11
-
12
- export interface ValidationResult {
13
- valid: boolean;
14
- errors: string[];
15
- warnings: string[];
16
- }
@@ -1,31 +0,0 @@
1
- import chalk from 'chalk';
2
- import ora, { Ora } from 'ora';
3
-
4
- export const logger = {
5
- info: (message: string) => {
6
- console.log(chalk.blue('ℹ'), message);
7
- },
8
-
9
- success: (message: string) => {
10
- console.log(chalk.green('✔'), message);
11
- },
12
-
13
- error: (message: string) => {
14
- console.log(chalk.red('✖'), message);
15
- },
16
-
17
- warning: (message: string) => {
18
- console.log(chalk.yellow('⚠'), message);
19
- },
20
-
21
- title: (message: string) => {
22
- console.log(chalk.bold.cyan(`\n${message}\n`));
23
- },
24
-
25
- spinner: (text: string): Ora => {
26
- return ora({
27
- text,
28
- color: 'cyan',
29
- }).start();
30
- },
31
- };
@@ -1,105 +0,0 @@
1
- import inquirer from 'inquirer';
2
- import { StackConfig } from '../types';
3
-
4
- export async function promptForStack(projectName: string, options: any = {}): Promise<StackConfig> {
5
- console.log('\n');
6
-
7
- // If options are provided, merge them with defaults and return
8
- // This allows non-interactive mode
9
- if (options.frontend || options.backend || options.auth || options.database) {
10
- return {
11
- projectName,
12
- frontend: options.frontend || 'react-vite',
13
- backend: options.backend || 'express',
14
- auth: options.auth || 'jwt',
15
- database: options.database || 'postgresql',
16
- apiStyle: options.api // 'api' option maps to 'apiStyle' in config
17
- ? (options.api === 'trpc' ? 'trpc' : options.api === 'graphql' ? 'graphql' : 'rest')
18
- : 'rest',
19
- docker: options.docker !== false, // Default to true unless --no-docker
20
- multiTenant: !!options.multiTenant,
21
- } as StackConfig;
22
- }
23
-
24
- const answers = await inquirer.prompt([
25
- {
26
- type: 'list',
27
- name: 'frontend',
28
- message: 'Choose your frontend framework:',
29
- choices: [
30
- { name: 'React + Vite (Recommended)', value: 'react-vite' },
31
- { name: 'Next.js (App Router)', value: 'nextjs' },
32
- { name: 'Vue + Vite', value: 'vue-vite' },
33
- { name: 'SvelteKit', value: 'sveltekit' },
34
- ],
35
- default: 'react-vite',
36
- },
37
- {
38
- type: 'list',
39
- name: 'backend',
40
- message: 'Choose your backend framework:',
41
- choices: [
42
- { name: 'Node.js + Express (Recommended)', value: 'express' },
43
- { name: 'Node.js + Fastify', value: 'fastify' },
44
- { name: 'NestJS', value: 'nestjs' },
45
- { name: 'Bun + Elysia', value: 'bun-elysia' },
46
- { name: 'Go + Fiber (Experimental)', value: 'go-fiber' },
47
- ],
48
- default: 'express',
49
- },
50
- {
51
- type: 'list',
52
- name: 'auth',
53
- message: 'Choose your authentication provider:',
54
- choices: [
55
- { name: 'Built-in JWT Auth (Free)', value: 'jwt' },
56
- { name: 'Clerk', value: 'clerk' },
57
- { name: 'Supabase Auth', value: 'supabase' },
58
- { name: 'Auth.js (NextAuth)', value: 'authjs' },
59
- { name: 'Firebase Auth', value: 'firebase' },
60
- ],
61
- default: 'jwt',
62
- },
63
- {
64
- type: 'list',
65
- name: 'database',
66
- message: 'Choose your database:',
67
- choices: [
68
- { name: 'PostgreSQL + Prisma (Recommended)', value: 'postgresql' },
69
- { name: 'MongoDB + Mongoose', value: 'mongodb' },
70
- { name: 'MySQL + Prisma', value: 'mysql' },
71
- { name: 'SQLite (Local)', value: 'sqlite' },
72
- { name: 'Supabase DB', value: 'supabase-db' },
73
- ],
74
- default: 'postgresql',
75
- },
76
- {
77
- type: 'list',
78
- name: 'apiStyle',
79
- message: 'Choose your API style:',
80
- choices: [
81
- { name: 'REST (Recommended)', value: 'rest' },
82
- { name: 'GraphQL', value: 'graphql' },
83
- { name: 'tRPC (Type-safe)', value: 'trpc' },
84
- ],
85
- default: 'rest',
86
- },
87
- {
88
- type: 'confirm',
89
- name: 'docker',
90
- message: 'Include Docker configuration?',
91
- default: true,
92
- },
93
- {
94
- type: 'confirm',
95
- name: 'multiTenant',
96
- message: 'Enable multi-tenancy support?',
97
- default: false,
98
- },
99
- ]);
100
-
101
- return {
102
- projectName,
103
- ...answers,
104
- };
105
- }
@@ -1,50 +0,0 @@
1
- import { StackConfig, ValidationResult } from '../types';
2
- import validateNpmPackageName from 'validate-npm-package-name';
3
-
4
- export function validateStackConfig(config: StackConfig): ValidationResult {
5
- const errors: string[] = [];
6
- const warnings: string[] = [];
7
-
8
- // Validate project name
9
- const nameValidation = validateNpmPackageName(config.projectName);
10
- if (!nameValidation.validForNewPackages) {
11
- errors.push(`Invalid project name: ${nameValidation.errors?.join(', ')}`);
12
- }
13
-
14
- // tRPC requires TypeScript backend
15
- if (config.apiStyle === 'trpc') {
16
- if (config.backend === 'go-fiber') {
17
- errors.push('tRPC is not compatible with Go backend. Please choose a TypeScript backend.');
18
- }
19
- }
20
-
21
- // GraphQL compatibility
22
- if (config.apiStyle === 'graphql') {
23
- if (config.backend === 'bun-elysia' || config.backend === 'go-fiber') {
24
- warnings.push('GraphQL support for this backend is experimental.');
25
- }
26
- }
27
-
28
- // Supabase auth requires Supabase DB
29
- if (config.auth === 'supabase' && config.database !== 'supabase-db') {
30
- warnings.push('Supabase Auth works best with Supabase DB. Consider using Supabase DB for full integration.');
31
- }
32
-
33
- // Go backend is experimental
34
- if (config.backend === 'go-fiber') {
35
- warnings.push('Go + Fiber backend is experimental and may have limited features.');
36
- }
37
-
38
- // Multi-tenancy warnings
39
- if (config.multiTenant) {
40
- if (config.database === 'sqlite') {
41
- warnings.push('SQLite with multi-tenancy is not recommended for production use.');
42
- }
43
- }
44
-
45
- return {
46
- valid: errors.length === 0,
47
- errors,
48
- warnings,
49
- };
50
- }
@@ -1,69 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { validateStackConfig } from '../src/utils/validators';
3
-
4
- describe('Stack Validation', () => {
5
- it('should validate compatible stacks', () => {
6
- const config = {
7
- projectName: 'test-app',
8
- frontend: 'react-vite' as const,
9
- backend: 'express' as const,
10
- auth: 'jwt' as const,
11
- database: 'postgresql' as const,
12
- apiStyle: 'rest' as const,
13
- docker: true,
14
- multiTenant: false,
15
- };
16
-
17
- const result = validateStackConfig(config);
18
- expect(result.valid).toBe(true);
19
- });
20
-
21
- it('should reject Next.js with Express (incompatible)', () => {
22
- const config = {
23
- projectName: 'test-app',
24
- frontend: 'nextjs' as const,
25
- backend: 'express' as const,
26
- auth: 'jwt' as const,
27
- database: 'postgresql' as const,
28
- apiStyle: 'rest' as const,
29
- docker: true,
30
- multiTenant: false,
31
- };
32
-
33
- const result = validateStackConfig(config);
34
- expect(result.valid).toBe(false);
35
- expect(result.errors).toContain('Next.js works best with NestJS backend');
36
- });
37
-
38
- it('should validate GraphQL API style', () => {
39
- const config = {
40
- projectName: 'test-app',
41
- frontend: 'react-vite' as const,
42
- backend: 'express' as const,
43
- auth: 'jwt' as const,
44
- database: 'postgresql' as const,
45
- apiStyle: 'graphql' as const,
46
- docker: true,
47
- multiTenant: false,
48
- };
49
-
50
- const result = validateStackConfig(config);
51
- expect(result.valid).toBe(true);
52
- });
53
-
54
- it('should validate tRPC API style', () => {
55
- const config = {
56
- projectName: 'test-app',
57
- frontend: 'nextjs' as const,
58
- backend: 'nestjs' as const,
59
- auth: 'clerk' as const,
60
- database: 'postgresql' as const,
61
- apiStyle: 'trpc' as const,
62
- docker: true,
63
- multiTenant: true,
64
- };
65
-
66
- const result = validateStackConfig(config);
67
- expect(result.valid).toBe(true);
68
- });
69
- });
package/tsc_output.txt DELETED
Binary file
package/tsconfig.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./src",
6
- "types": [
7
- "node",
8
- "vitest/globals"
9
- ],
10
- "noUnusedLocals": false,
11
- "noUnusedParameters": false
12
- },
13
- "include": [
14
- "src/**/*"
15
- ],
16
- "exclude": [
17
- "node_modules",
18
- "dist",
19
- "**/*.test.ts"
20
- ]
21
- }