create-loadout 1.0.1 → 1.0.4
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 +76 -9
- package/dist/claude-md.js +504 -333
- package/dist/cli.js +14 -81
- package/dist/create-next.js +1 -1
- package/dist/engine.d.ts +9 -0
- package/dist/engine.js +84 -0
- package/dist/env.js +12 -25
- package/dist/generate-readme.js +123 -120
- package/dist/index.js +156 -1
- package/dist/integrations/index.d.ts +1 -0
- package/dist/integrations/index.js +1 -1
- package/dist/integrations/stripe.js +0 -14
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +165 -0
- package/dist/metadata.d.ts +18 -0
- package/dist/metadata.js +28 -0
- package/dist/prompts.js +3 -6
- package/dist/templates/firecrawl.js +1 -1
- package/dist/templates/neon-drizzle.js +329 -327
- package/dist/templates/stripe.d.ts +0 -3
- package/dist/templates/stripe.js +0 -130
- package/dist/validate.d.ts +14 -0
- package/dist/validate.js +66 -0
- package/package.json +10 -5
package/dist/cli.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
3
|
import path from 'path';
|
|
5
4
|
import { getProjectConfig, getAddIntegrationConfig } from './prompts.js';
|
|
6
|
-
import {
|
|
7
|
-
import { setupShadcn } from './setup-shadcn.js';
|
|
8
|
-
import { installIntegrations } from './integrations/index.js';
|
|
9
|
-
import { generateClaudeMd, appendClaudeMd } from './claude-md.js';
|
|
10
|
-
import { generateEnvFiles, appendEnvFiles } from './env.js';
|
|
11
|
-
import { generateConfig, appendConfig } from './config.js';
|
|
12
|
-
import { generateReadme, generateGitignore } from './generate-readme.js';
|
|
13
|
-
import { generateInstrumentationClient, generateInstrumentation, } from './instrumentation.js';
|
|
14
|
-
import { zustandTemplates } from './templates/zustand.js';
|
|
15
|
-
import { generateLandingPage } from './landing-page.js';
|
|
5
|
+
import { createProject, addIntegrations } from './engine.js';
|
|
16
6
|
import { isExistingProject, getInstalledIntegrations, getAvailableIntegrations, } from './detect.js';
|
|
7
|
+
function oraReporter() {
|
|
8
|
+
const spinner = ora();
|
|
9
|
+
const callback = (step) => {
|
|
10
|
+
spinner.start(step);
|
|
11
|
+
};
|
|
12
|
+
return { spinner, callback };
|
|
13
|
+
}
|
|
17
14
|
export async function main() {
|
|
18
15
|
console.log();
|
|
19
16
|
console.log(chalk.bold.cyan(' create-loadout'));
|
|
@@ -37,36 +34,8 @@ export async function main() {
|
|
|
37
34
|
async function newProjectFlow() {
|
|
38
35
|
const config = await getProjectConfig();
|
|
39
36
|
console.log();
|
|
40
|
-
const spinner
|
|
41
|
-
const
|
|
42
|
-
spinner.succeed('Next.js app created');
|
|
43
|
-
spinner.start('Setting up shadcn/ui...');
|
|
44
|
-
await setupShadcn(projectPath);
|
|
45
|
-
spinner.succeed('shadcn/ui configured');
|
|
46
|
-
await extendUtils(projectPath);
|
|
47
|
-
spinner.start('Installing base packages...');
|
|
48
|
-
const { execa } = await import('execa');
|
|
49
|
-
await execa('npm', ['install', 'zod@^3.24', 'zustand@^5', 'luxon@^3'], { cwd: projectPath });
|
|
50
|
-
await execa('npm', ['install', '-D', '@types/luxon'], { cwd: projectPath });
|
|
51
|
-
spinner.succeed('Base packages installed (zod, zustand, luxon)');
|
|
52
|
-
await fs.mkdir(path.join(projectPath, 'lib/stores'), { recursive: true });
|
|
53
|
-
await fs.writeFile(path.join(projectPath, 'lib/stores/counter.store.ts'), zustandTemplates.exampleStore);
|
|
54
|
-
if (config.integrations.length > 0) {
|
|
55
|
-
spinner.start(`Setting up ${config.integrations.length} integration(s)...`);
|
|
56
|
-
await installIntegrations(projectPath, config);
|
|
57
|
-
spinner.succeed('Integrations configured');
|
|
58
|
-
}
|
|
59
|
-
await generateInstrumentationClient(projectPath, config);
|
|
60
|
-
await generateInstrumentation(projectPath, config);
|
|
61
|
-
spinner.start('Generating config and environment files...');
|
|
62
|
-
await generateConfig(projectPath, config);
|
|
63
|
-
await generateEnvFiles(projectPath, config);
|
|
64
|
-
spinner.succeed('Config and environment files created');
|
|
65
|
-
spinner.start('Generating project files...');
|
|
66
|
-
await generateLandingPage(projectPath, config);
|
|
67
|
-
await generateGitignore(projectPath);
|
|
68
|
-
await generateReadme(projectPath, config);
|
|
69
|
-
await generateClaudeMd(projectPath, config);
|
|
37
|
+
const { spinner, callback } = oraReporter();
|
|
38
|
+
const result = await createProject(config, callback);
|
|
70
39
|
spinner.succeed('Project files created');
|
|
71
40
|
console.log();
|
|
72
41
|
console.log(chalk.green.bold(' Success!') + ' Created ' + chalk.cyan(config.name));
|
|
@@ -80,7 +49,7 @@ async function newProjectFlow() {
|
|
|
80
49
|
}
|
|
81
50
|
console.log(chalk.bold(' Next steps:'));
|
|
82
51
|
console.log(chalk.gray(` 1. cd ${config.name}`));
|
|
83
|
-
console.log(chalk.gray(' 2. Configure .env
|
|
52
|
+
console.log(chalk.gray(' 2. Configure .env with your API keys'));
|
|
84
53
|
console.log(chalk.gray(' 3. npm run dev'));
|
|
85
54
|
console.log();
|
|
86
55
|
if (config.integrations.includes('neon-drizzle')) {
|
|
@@ -117,21 +86,14 @@ async function addIntegrationFlow(projectPath) {
|
|
|
117
86
|
return;
|
|
118
87
|
}
|
|
119
88
|
console.log();
|
|
120
|
-
const spinner = ora(`Installing ${addConfig.integrations.length} integration(s)...`).start();
|
|
121
89
|
const config = {
|
|
122
90
|
name: path.basename(projectPath),
|
|
123
91
|
integrations: addConfig.integrations,
|
|
124
92
|
aiProvider: addConfig.aiProvider,
|
|
125
93
|
};
|
|
126
|
-
|
|
94
|
+
const { spinner, callback } = oraReporter();
|
|
95
|
+
const result = await addIntegrations(projectPath, config, callback);
|
|
127
96
|
spinner.succeed('Integrations installed');
|
|
128
|
-
spinner.start('Updating config and environment files...');
|
|
129
|
-
await appendConfig(projectPath, addConfig.integrations, addConfig.aiProvider);
|
|
130
|
-
await appendEnvFiles(projectPath, addConfig.integrations, addConfig.aiProvider);
|
|
131
|
-
spinner.succeed('Config and environment files updated');
|
|
132
|
-
spinner.start('Updating CLAUDE.md...');
|
|
133
|
-
await appendClaudeMd(projectPath, addConfig.integrations);
|
|
134
|
-
spinner.succeed('CLAUDE.md updated');
|
|
135
97
|
console.log();
|
|
136
98
|
console.log(chalk.green.bold(' Success!') + ' Added integrations:');
|
|
137
99
|
addConfig.integrations.forEach((integration) => {
|
|
@@ -139,7 +101,7 @@ async function addIntegrationFlow(projectPath) {
|
|
|
139
101
|
});
|
|
140
102
|
console.log();
|
|
141
103
|
console.log(chalk.bold(' Next steps:'));
|
|
142
|
-
console.log(chalk.gray(' 1. Update .env
|
|
104
|
+
console.log(chalk.gray(' 1. Update .env with new API keys'));
|
|
143
105
|
console.log(chalk.gray(' 2. npm run dev'));
|
|
144
106
|
console.log();
|
|
145
107
|
if (addConfig.integrations.includes('neon-drizzle')) {
|
|
@@ -155,32 +117,3 @@ async function addIntegrationFlow(projectPath) {
|
|
|
155
117
|
console.log();
|
|
156
118
|
}
|
|
157
119
|
}
|
|
158
|
-
async function extendUtils(projectPath) {
|
|
159
|
-
const utilsPath = path.join(projectPath, 'lib/utils.ts');
|
|
160
|
-
const existingContent = await fs.readFile(utilsPath, 'utf-8');
|
|
161
|
-
const additionalUtils = `
|
|
162
|
-
import { DateTime } from 'luxon';
|
|
163
|
-
|
|
164
|
-
export function formatDate(date: Date | string, format = 'LLL d, yyyy'): string {
|
|
165
|
-
const dt = typeof date === 'string' ? DateTime.fromISO(date) : DateTime.fromJSDate(date);
|
|
166
|
-
return dt.toFormat(format);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function formatRelative(date: Date | string): string {
|
|
170
|
-
const dt = typeof date === 'string' ? DateTime.fromISO(date) : DateTime.fromJSDate(date);
|
|
171
|
-
return dt.toRelative() ?? dt.toFormat('LLL d, yyyy');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function debounce<P extends unknown[], R>(
|
|
175
|
-
func: (...args: P) => R,
|
|
176
|
-
wait: number
|
|
177
|
-
): (...args: P) => void {
|
|
178
|
-
let timeout: ReturnType<typeof setTimeout>;
|
|
179
|
-
return (...args: P) => {
|
|
180
|
-
clearTimeout(timeout);
|
|
181
|
-
timeout = setTimeout(() => func(...args), wait);
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
`;
|
|
185
|
-
await fs.writeFile(utilsPath, existingContent + additionalUtils);
|
|
186
|
-
}
|
package/dist/create-next.js
CHANGED
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProjectConfig, IntegrationId } from './types.js';
|
|
2
|
+
export type ProgressCallback = (step: string) => void;
|
|
3
|
+
export interface EngineResult {
|
|
4
|
+
projectPath: string;
|
|
5
|
+
integrations: IntegrationId[];
|
|
6
|
+
envVarsNeeded: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function createProject(config: ProjectConfig, onProgress?: ProgressCallback): Promise<EngineResult>;
|
|
9
|
+
export declare function addIntegrations(projectPath: string, config: ProjectConfig, onProgress?: ProgressCallback): Promise<EngineResult>;
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { createNextApp } from './create-next.js';
|
|
4
|
+
import { setupShadcn } from './setup-shadcn.js';
|
|
5
|
+
import { installIntegrations, getEnvVars } from './integrations/index.js';
|
|
6
|
+
import { generateClaudeMd, appendClaudeMd } from './claude-md.js';
|
|
7
|
+
import { generateEnvFiles, appendEnvFiles } from './env.js';
|
|
8
|
+
import { generateConfig, appendConfig } from './config.js';
|
|
9
|
+
import { generateReadme, generateGitignore } from './generate-readme.js';
|
|
10
|
+
import { generateInstrumentationClient, generateInstrumentation, } from './instrumentation.js';
|
|
11
|
+
import { zustandTemplates } from './templates/zustand.js';
|
|
12
|
+
import { generateLandingPage } from './landing-page.js';
|
|
13
|
+
export async function createProject(config, onProgress) {
|
|
14
|
+
onProgress?.('Creating Next.js app...');
|
|
15
|
+
const projectPath = await createNextApp(config.name);
|
|
16
|
+
onProgress?.('Setting up shadcn/ui...');
|
|
17
|
+
await setupShadcn(projectPath);
|
|
18
|
+
await extendUtils(projectPath);
|
|
19
|
+
onProgress?.('Installing base packages...');
|
|
20
|
+
const { execa } = await import('execa');
|
|
21
|
+
await execa('npm', ['install', 'zod', 'zustand', 'luxon'], { cwd: projectPath });
|
|
22
|
+
await execa('npm', ['install', '-D', '@types/luxon'], { cwd: projectPath });
|
|
23
|
+
await fs.mkdir(path.join(projectPath, 'lib/stores'), { recursive: true });
|
|
24
|
+
await fs.writeFile(path.join(projectPath, 'lib/stores/counter.store.ts'), zustandTemplates.exampleStore);
|
|
25
|
+
if (config.integrations.length > 0) {
|
|
26
|
+
onProgress?.(`Setting up ${config.integrations.length} integration(s)...`);
|
|
27
|
+
await installIntegrations(projectPath, config);
|
|
28
|
+
}
|
|
29
|
+
await generateInstrumentationClient(projectPath, config);
|
|
30
|
+
await generateInstrumentation(projectPath, config);
|
|
31
|
+
onProgress?.('Generating config and environment files...');
|
|
32
|
+
await generateConfig(projectPath, config);
|
|
33
|
+
await generateEnvFiles(projectPath, config);
|
|
34
|
+
onProgress?.('Generating project files...');
|
|
35
|
+
await generateLandingPage(projectPath, config);
|
|
36
|
+
await generateGitignore(projectPath);
|
|
37
|
+
await generateReadme(projectPath, config);
|
|
38
|
+
await generateClaudeMd(projectPath, config);
|
|
39
|
+
const envVarsNeeded = collectEnvVars(config);
|
|
40
|
+
return { projectPath, integrations: config.integrations, envVarsNeeded };
|
|
41
|
+
}
|
|
42
|
+
export async function addIntegrations(projectPath, config, onProgress) {
|
|
43
|
+
onProgress?.(`Installing ${config.integrations.length} integration(s)...`);
|
|
44
|
+
await installIntegrations(projectPath, config);
|
|
45
|
+
onProgress?.('Updating config and environment files...');
|
|
46
|
+
await appendConfig(projectPath, config.integrations, config.aiProvider);
|
|
47
|
+
await appendEnvFiles(projectPath, config.integrations, config.aiProvider);
|
|
48
|
+
onProgress?.('Updating CLAUDE.md...');
|
|
49
|
+
await appendClaudeMd(projectPath, config.integrations);
|
|
50
|
+
const envVarsNeeded = collectEnvVars(config);
|
|
51
|
+
return { projectPath, integrations: config.integrations, envVarsNeeded };
|
|
52
|
+
}
|
|
53
|
+
async function extendUtils(projectPath) {
|
|
54
|
+
const utilsPath = path.join(projectPath, 'lib/utils.ts');
|
|
55
|
+
const existingContent = await fs.readFile(utilsPath, 'utf-8');
|
|
56
|
+
const additionalUtils = `
|
|
57
|
+
import { DateTime } from 'luxon';
|
|
58
|
+
|
|
59
|
+
export function formatDate(date: Date | string, format = 'LLL d, yyyy'): string {
|
|
60
|
+
const dt = typeof date === 'string' ? DateTime.fromISO(date) : DateTime.fromJSDate(date);
|
|
61
|
+
return dt.toFormat(format);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function formatRelative(date: Date | string): string {
|
|
65
|
+
const dt = typeof date === 'string' ? DateTime.fromISO(date) : DateTime.fromJSDate(date);
|
|
66
|
+
return dt.toRelative() ?? dt.toFormat('LLL d, yyyy');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function debounce<P extends unknown[], R>(
|
|
70
|
+
func: (...args: P) => R,
|
|
71
|
+
wait: number
|
|
72
|
+
): (...args: P) => void {
|
|
73
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
74
|
+
return (...args: P) => {
|
|
75
|
+
clearTimeout(timeout);
|
|
76
|
+
timeout = setTimeout(() => func(...args), wait);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
await fs.writeFile(utilsPath, existingContent + additionalUtils);
|
|
81
|
+
}
|
|
82
|
+
function collectEnvVars(config) {
|
|
83
|
+
return getEnvVars(config).map((v) => v.key);
|
|
84
|
+
}
|
package/dist/env.js
CHANGED
|
@@ -138,37 +138,24 @@ export async function generateEnvFiles(projectPath, config) {
|
|
|
138
138
|
envExample += '\n';
|
|
139
139
|
}
|
|
140
140
|
await fs.writeFile(path.join(projectPath, '.env.example'), envExample.trim() + '\n');
|
|
141
|
-
// Generate .env
|
|
142
|
-
let
|
|
141
|
+
// Generate .env with empty values
|
|
142
|
+
let env = '';
|
|
143
143
|
for (const id of selectedIds) {
|
|
144
144
|
const section = getEnvSection(id, config.aiProvider);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
await fs.writeFile(path.join(projectPath, '.env.local'), envLocal.trim() + '\n');
|
|
149
|
-
// Update .gitignore to include .env.local
|
|
150
|
-
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
151
|
-
try {
|
|
152
|
-
let gitignore = await fs.readFile(gitignorePath, 'utf-8');
|
|
153
|
-
if (!gitignore.includes('.env.local')) {
|
|
154
|
-
gitignore += '\n# Environment variables\n.env.local\n.env*.local\n';
|
|
155
|
-
await fs.writeFile(gitignorePath, gitignore);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
// .gitignore doesn't exist, create it
|
|
160
|
-
await fs.writeFile(gitignorePath, '# Environment variables\n.env.local\n.env*.local\n');
|
|
145
|
+
env += generateEnvSection(section, false);
|
|
146
|
+
env += '\n';
|
|
161
147
|
}
|
|
148
|
+
await fs.writeFile(path.join(projectPath, '.env'), env.trim() + '\n');
|
|
162
149
|
}
|
|
163
150
|
export async function appendEnvFiles(projectPath, integrations, aiProvider) {
|
|
164
151
|
const envExamplePath = path.join(projectPath, '.env.example');
|
|
165
|
-
const
|
|
152
|
+
const envPath = path.join(projectPath, '.env');
|
|
166
153
|
let envExampleContent = '';
|
|
167
|
-
let
|
|
154
|
+
let envContent = '';
|
|
168
155
|
for (const id of integrations) {
|
|
169
156
|
const section = getEnvSection(id, aiProvider);
|
|
170
157
|
envExampleContent += '\n' + generateEnvSection(section, true);
|
|
171
|
-
|
|
158
|
+
envContent += '\n' + generateEnvSection(section, false);
|
|
172
159
|
}
|
|
173
160
|
if (envExampleContent) {
|
|
174
161
|
try {
|
|
@@ -179,13 +166,13 @@ export async function appendEnvFiles(projectPath, integrations, aiProvider) {
|
|
|
179
166
|
await fs.writeFile(envExamplePath, envExampleContent.trim() + '\n');
|
|
180
167
|
}
|
|
181
168
|
}
|
|
182
|
-
if (
|
|
169
|
+
if (envContent) {
|
|
183
170
|
try {
|
|
184
|
-
const existing = await fs.readFile(
|
|
185
|
-
await fs.writeFile(
|
|
171
|
+
const existing = await fs.readFile(envPath, 'utf-8');
|
|
172
|
+
await fs.writeFile(envPath, existing.trimEnd() + '\n' + envContent.trim() + '\n');
|
|
186
173
|
}
|
|
187
174
|
catch {
|
|
188
|
-
await fs.writeFile(
|
|
175
|
+
await fs.writeFile(envPath, envContent.trim() + '\n');
|
|
189
176
|
}
|
|
190
177
|
}
|
|
191
178
|
}
|
package/dist/generate-readme.js
CHANGED
|
@@ -14,36 +14,36 @@ const integrationNames = {
|
|
|
14
14
|
sentry: 'Sentry',
|
|
15
15
|
};
|
|
16
16
|
export async function generateReadme(projectPath, config) {
|
|
17
|
-
let content = `# ${config.name}
|
|
18
|
-
|
|
19
|
-
A Next.js application scaffolded with [create-loadout](https://github.com/your-org/create-loadout).
|
|
20
|
-
|
|
21
|
-
## Getting Started
|
|
22
|
-
|
|
23
|
-
1. Install dependencies:
|
|
24
|
-
\`\`\`bash
|
|
25
|
-
npm install
|
|
26
|
-
\`\`\`
|
|
27
|
-
|
|
28
|
-
2. Copy the environment file and configure your API keys:
|
|
29
|
-
\`\`\`bash
|
|
30
|
-
cp .env.example .env
|
|
31
|
-
\`\`\`
|
|
32
|
-
|
|
33
|
-
3. Start the development server:
|
|
34
|
-
\`\`\`bash
|
|
35
|
-
npm run dev
|
|
36
|
-
\`\`\`
|
|
37
|
-
|
|
38
|
-
4. Open [http://localhost:3000](http://localhost:3000) in your browser.
|
|
39
|
-
|
|
40
|
-
## Tech Stack
|
|
41
|
-
|
|
42
|
-
- [Next.js](https://nextjs.org/) - React framework
|
|
43
|
-
- [TypeScript](https://www.typescriptlang.org/) - Type safety
|
|
44
|
-
- [Tailwind CSS](https://tailwindcss.com/) - Styling
|
|
45
|
-
- [shadcn/ui](https://ui.shadcn.com/) - UI components
|
|
46
|
-
- [Zod](https://zod.dev/) - Schema validation
|
|
17
|
+
let content = `# ${config.name}
|
|
18
|
+
|
|
19
|
+
A Next.js application scaffolded with [create-loadout](https://github.com/your-org/create-loadout).
|
|
20
|
+
|
|
21
|
+
## Getting Started
|
|
22
|
+
|
|
23
|
+
1. Install dependencies:
|
|
24
|
+
\`\`\`bash
|
|
25
|
+
npm install
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
2. Copy the environment file and configure your API keys:
|
|
29
|
+
\`\`\`bash
|
|
30
|
+
cp .env.example .env
|
|
31
|
+
\`\`\`
|
|
32
|
+
|
|
33
|
+
3. Start the development server:
|
|
34
|
+
\`\`\`bash
|
|
35
|
+
npm run dev
|
|
36
|
+
\`\`\`
|
|
37
|
+
|
|
38
|
+
4. Open [http://localhost:3000](http://localhost:3000) in your browser.
|
|
39
|
+
|
|
40
|
+
## Tech Stack
|
|
41
|
+
|
|
42
|
+
- [Next.js](https://nextjs.org/) - React framework
|
|
43
|
+
- [TypeScript](https://www.typescriptlang.org/) - Type safety
|
|
44
|
+
- [Tailwind CSS](https://tailwindcss.com/) - Styling
|
|
45
|
+
- [shadcn/ui](https://ui.shadcn.com/) - UI components
|
|
46
|
+
- [Zod](https://zod.dev/) - Schema validation
|
|
47
47
|
`;
|
|
48
48
|
if (config.integrations.length > 0) {
|
|
49
49
|
content += `\n### Integrations\n\n`;
|
|
@@ -51,111 +51,114 @@ A Next.js application scaffolded with [create-loadout](https://github.com/your-o
|
|
|
51
51
|
content += `- ${integrationNames[id]}\n`;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
content += `
|
|
55
|
-
## Scripts
|
|
56
|
-
|
|
57
|
-
\`\`\`bash
|
|
58
|
-
npm run dev # Start development server
|
|
59
|
-
npm run build # Build for production
|
|
60
|
-
npm run start # Start production server
|
|
61
|
-
npm run lint # Run ESLint
|
|
62
|
-
\`\`\`
|
|
54
|
+
content += `
|
|
55
|
+
## Scripts
|
|
56
|
+
|
|
57
|
+
\`\`\`bash
|
|
58
|
+
npm run dev # Start development server
|
|
59
|
+
npm run build # Build for production
|
|
60
|
+
npm run start # Start production server
|
|
61
|
+
npm run lint # Run ESLint
|
|
62
|
+
\`\`\`
|
|
63
63
|
`;
|
|
64
64
|
if (config.integrations.includes('neon-drizzle')) {
|
|
65
|
-
content += `
|
|
66
|
-
### Database
|
|
67
|
-
|
|
68
|
-
\`\`\`bash
|
|
69
|
-
npm run db:generate # Generate migrations
|
|
70
|
-
npm run db:migrate # Run migrations
|
|
71
|
-
npm run db:studio # Open Drizzle Studio
|
|
72
|
-
\`\`\`
|
|
65
|
+
content += `
|
|
66
|
+
### Database
|
|
67
|
+
|
|
68
|
+
\`\`\`bash
|
|
69
|
+
npm run db:generate # Generate migrations
|
|
70
|
+
npm run db:migrate # Run migrations
|
|
71
|
+
npm run db:studio # Open Drizzle Studio
|
|
72
|
+
\`\`\`
|
|
73
73
|
`;
|
|
74
74
|
}
|
|
75
75
|
if (config.integrations.includes('inngest')) {
|
|
76
|
-
content += `
|
|
77
|
-
### Background Jobs
|
|
78
|
-
|
|
79
|
-
\`\`\`bash
|
|
80
|
-
npm run inngest:dev # Start Inngest dev server
|
|
81
|
-
\`\`\`
|
|
76
|
+
content += `
|
|
77
|
+
### Background Jobs
|
|
78
|
+
|
|
79
|
+
\`\`\`bash
|
|
80
|
+
npm run inngest:dev # Start Inngest dev server
|
|
81
|
+
\`\`\`
|
|
82
82
|
`;
|
|
83
83
|
}
|
|
84
|
-
content += `
|
|
85
|
-
## Project Structure
|
|
86
|
-
|
|
87
|
-
\`\`\`
|
|
88
|
-
├── app/ # Next.js App Router
|
|
89
|
-
├── components/ # React components
|
|
90
|
-
├── lib/ # Utilities and clients
|
|
91
|
-
├── services/ # Business logic
|
|
84
|
+
content += `
|
|
85
|
+
## Project Structure
|
|
86
|
+
|
|
87
|
+
\`\`\`
|
|
88
|
+
├── app/ # Next.js App Router
|
|
89
|
+
├── components/ # React components
|
|
90
|
+
├── lib/ # Utilities and clients
|
|
91
|
+
├── services/ # Business logic
|
|
92
92
|
`;
|
|
93
93
|
if (config.integrations.includes('resend') || config.integrations.includes('postmark')) {
|
|
94
94
|
content += `├── emails/ # Email templates\n`;
|
|
95
95
|
}
|
|
96
|
-
content += `└── public/ # Static assets
|
|
97
|
-
\`\`\`
|
|
98
|
-
|
|
99
|
-
## Environment Variables
|
|
100
|
-
|
|
101
|
-
See \`.env.example\` for all required environment variables.
|
|
102
|
-
|
|
103
|
-
## Learn More
|
|
104
|
-
|
|
105
|
-
- [Next.js Documentation](https://nextjs.org/docs)
|
|
106
|
-
- [CLAUDE.md](./CLAUDE.md) - AI assistant context file
|
|
96
|
+
content += `└── public/ # Static assets
|
|
97
|
+
\`\`\`
|
|
98
|
+
|
|
99
|
+
## Environment Variables
|
|
100
|
+
|
|
101
|
+
See \`.env.example\` for all required environment variables.
|
|
102
|
+
|
|
103
|
+
## Learn More
|
|
104
|
+
|
|
105
|
+
- [Next.js Documentation](https://nextjs.org/docs)
|
|
106
|
+
- [CLAUDE.md](./CLAUDE.md) - AI assistant context file
|
|
107
107
|
`;
|
|
108
108
|
await fs.writeFile(path.join(projectPath, 'README.md'), content);
|
|
109
109
|
}
|
|
110
110
|
export async function generateGitignore(projectPath) {
|
|
111
|
-
const content = `# Dependencies
|
|
112
|
-
node_modules/
|
|
113
|
-
.pnp/
|
|
114
|
-
.pnp.js
|
|
115
|
-
|
|
116
|
-
# Build
|
|
117
|
-
.next/
|
|
118
|
-
out/
|
|
119
|
-
build/
|
|
120
|
-
dist/
|
|
121
|
-
|
|
122
|
-
# Environment
|
|
123
|
-
.env
|
|
124
|
-
.env.local
|
|
125
|
-
.env.development.local
|
|
126
|
-
.env.test.local
|
|
127
|
-
.env.production.local
|
|
128
|
-
|
|
129
|
-
# Testing
|
|
130
|
-
coverage/
|
|
131
|
-
|
|
132
|
-
# IDE
|
|
133
|
-
.vscode/
|
|
134
|
-
.idea/
|
|
135
|
-
*.swp
|
|
136
|
-
*.swo
|
|
137
|
-
|
|
138
|
-
#
|
|
139
|
-
.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
.
|
|
149
|
-
|
|
150
|
-
#
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
#
|
|
158
|
-
|
|
111
|
+
const content = `# Dependencies
|
|
112
|
+
node_modules/
|
|
113
|
+
.pnp/
|
|
114
|
+
.pnp.js
|
|
115
|
+
|
|
116
|
+
# Build
|
|
117
|
+
.next/
|
|
118
|
+
out/
|
|
119
|
+
build/
|
|
120
|
+
dist/
|
|
121
|
+
|
|
122
|
+
# Environment
|
|
123
|
+
.env
|
|
124
|
+
.env.local
|
|
125
|
+
.env.development.local
|
|
126
|
+
.env.test.local
|
|
127
|
+
.env.production.local
|
|
128
|
+
|
|
129
|
+
# Testing
|
|
130
|
+
coverage/
|
|
131
|
+
|
|
132
|
+
# IDE
|
|
133
|
+
.vscode/
|
|
134
|
+
.idea/
|
|
135
|
+
*.swp
|
|
136
|
+
*.swo
|
|
137
|
+
|
|
138
|
+
# Claude Code
|
|
139
|
+
.claude/
|
|
140
|
+
|
|
141
|
+
# OS
|
|
142
|
+
.DS_Store
|
|
143
|
+
Thumbs.db
|
|
144
|
+
|
|
145
|
+
# Debug
|
|
146
|
+
npm-debug.log*
|
|
147
|
+
yarn-debug.log*
|
|
148
|
+
yarn-error.log*
|
|
149
|
+
|
|
150
|
+
# Vercel
|
|
151
|
+
.vercel
|
|
152
|
+
|
|
153
|
+
# TypeScript
|
|
154
|
+
*.tsbuildinfo
|
|
155
|
+
next-env.d.ts
|
|
156
|
+
|
|
157
|
+
# Drizzle
|
|
158
|
+
drizzle/
|
|
159
|
+
|
|
160
|
+
# Sentry
|
|
161
|
+
.sentryclirc
|
|
159
162
|
`;
|
|
160
163
|
await fs.writeFile(path.join(projectPath, '.gitignore'), content);
|
|
161
164
|
}
|