stackkit-cli 0.1.0 → 0.1.2

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/dist/commands/add.js +1 -1
  2. package/dist/commands/add.js.map +1 -1
  3. package/dist/commands/init.js +1 -1
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/commands/list.js +2 -2
  6. package/dist/commands/list.js.map +1 -1
  7. package/modules/auth/nextauth/files/app-router/api/auth/[...nextauth]/route.ts +6 -0
  8. package/modules/auth/nextauth/files/lib/auth.ts +82 -0
  9. package/modules/auth/nextauth/files/pages-router/api/auth/[...nextauth].ts +4 -0
  10. package/modules/auth/nextauth/module.json +50 -0
  11. package/package.json +7 -1
  12. package/templates/next-prisma-postgres-shadcn/.env.example +5 -0
  13. package/templates/next-prisma-postgres-shadcn/.eslintrc.json +7 -0
  14. package/templates/next-prisma-postgres-shadcn/.prettierrc +8 -0
  15. package/templates/next-prisma-postgres-shadcn/README.md +79 -0
  16. package/templates/next-prisma-postgres-shadcn/app/api/health/route.ts +25 -0
  17. package/templates/next-prisma-postgres-shadcn/app/globals.css +1 -0
  18. package/templates/next-prisma-postgres-shadcn/app/layout.tsx +22 -0
  19. package/templates/next-prisma-postgres-shadcn/app/page.tsx +29 -0
  20. package/templates/next-prisma-postgres-shadcn/lib/db.ts +14 -0
  21. package/templates/next-prisma-postgres-shadcn/lib/env.ts +15 -0
  22. package/templates/next-prisma-postgres-shadcn/next.config.ts +7 -0
  23. package/templates/next-prisma-postgres-shadcn/package.json +32 -0
  24. package/templates/next-prisma-postgres-shadcn/prisma/schema.prisma +20 -0
  25. package/templates/next-prisma-postgres-shadcn/public/.gitkeep +1 -0
  26. package/templates/next-prisma-postgres-shadcn/template.json +18 -0
  27. package/templates/next-prisma-postgres-shadcn/tsconfig.json +32 -0
  28. package/src/commands/add.ts +0 -261
  29. package/src/commands/init.ts +0 -182
  30. package/src/commands/list.ts +0 -124
  31. package/src/index.ts +0 -53
  32. package/src/types/index.ts +0 -71
  33. package/src/utils/code-inject.ts +0 -85
  34. package/src/utils/detect.ts +0 -89
  35. package/src/utils/env-editor.ts +0 -127
  36. package/src/utils/files.ts +0 -59
  37. package/src/utils/json-editor.ts +0 -64
  38. package/src/utils/logger.ts +0 -62
  39. package/src/utils/package-manager.ts +0 -85
  40. package/tsconfig.json +0 -9
@@ -1,261 +0,0 @@
1
- import chalk from 'chalk';
2
- import fs from 'fs-extra';
3
- import inquirer from 'inquirer';
4
- import path from 'path';
5
- import { CreateFilePatch, ModuleMetadata } from '../types';
6
- import { detectProjectInfo, getLibPath, getRouterBasePath } from '../utils/detect';
7
- import { addEnvVariables } from '../utils/env-editor';
8
- import { createFile, fileExists } from '../utils/files';
9
- import { logger } from '../utils/logger';
10
- import { addDependencies } from '../utils/package-manager';
11
-
12
- interface AddOptions {
13
- provider?: string;
14
- force?: boolean;
15
- dryRun?: boolean;
16
- install?: boolean;
17
- }
18
-
19
- export async function addCommand(module: string, options: AddOptions): Promise<void> {
20
- try {
21
- const projectRoot = process.cwd();
22
-
23
- // Detect project info
24
- const spinner = logger.startSpinner('Detecting project...');
25
- const projectInfo = await detectProjectInfo(projectRoot);
26
- spinner.succeed(
27
- `Detected ${projectInfo.framework} (${projectInfo.router} router, ${projectInfo.language})`
28
- );
29
-
30
- // Load module metadata
31
- const modulesDir = path.join(__dirname, '..', '..', '..', '..', 'modules');
32
- const moduleMetadata = await loadModuleMetadata(modulesDir, module, options.provider);
33
-
34
- if (!moduleMetadata) {
35
- logger.error(`Module "${module}" not found`);
36
- process.exit(1);
37
- }
38
-
39
- // Check if framework is supported
40
- if (!moduleMetadata.supportedFrameworks.includes(projectInfo.framework)) {
41
- logger.error(
42
- `Module "${module}" does not support ${projectInfo.framework}. Supported: ${moduleMetadata.supportedFrameworks.join(', ')}`
43
- );
44
- process.exit(1);
45
- }
46
-
47
- // Check for conflicts
48
- if (module === 'auth' && projectInfo.hasAuth && !options.force) {
49
- logger.warn('Auth library already detected in this project');
50
- const { proceed } = await inquirer.prompt([
51
- {
52
- type: 'confirm',
53
- name: 'proceed',
54
- message: 'Continue anyway? (use --force to skip this prompt)',
55
- default: false,
56
- },
57
- ]);
58
-
59
- if (!proceed) {
60
- logger.info('Cancelled');
61
- process.exit(0);
62
- }
63
- }
64
-
65
- if (options.dryRun) {
66
- logger.warn('Dry run mode - no changes will be made');
67
- logger.newLine();
68
- }
69
-
70
- // Apply module patches
71
- await applyModulePatches(projectRoot, projectInfo, moduleMetadata, modulesDir, module, options);
72
-
73
- // Add dependencies
74
- if (Object.keys(moduleMetadata.dependencies).length > 0 && options.install !== false) {
75
- const deps = Object.entries(moduleMetadata.dependencies).map(
76
- ([name, version]) => `${name}@${version}`
77
- );
78
-
79
- if (!options.dryRun) {
80
- await addDependencies(projectRoot, projectInfo.packageManager, deps, false);
81
- } else {
82
- logger.info(`Would add dependencies: ${deps.join(', ')}`);
83
- }
84
- }
85
-
86
- // Add dev dependencies
87
- if (
88
- moduleMetadata.devDependencies &&
89
- Object.keys(moduleMetadata.devDependencies).length > 0 &&
90
- options.install !== false
91
- ) {
92
- const devDeps = Object.entries(moduleMetadata.devDependencies).map(
93
- ([name, version]) => `${name}@${version}`
94
- );
95
-
96
- if (!options.dryRun) {
97
- await addDependencies(projectRoot, projectInfo.packageManager, devDeps, true);
98
- } else {
99
- logger.info(`Would add dev dependencies: ${devDeps.join(', ')}`);
100
- }
101
- }
102
-
103
- // Add environment variables
104
- if (moduleMetadata.envVars.length > 0) {
105
- if (!options.dryRun) {
106
- await addEnvVariables(projectRoot, moduleMetadata.envVars, { force: options.force });
107
- } else {
108
- logger.log(` ${chalk.dim('~')} .env.example`);
109
- }
110
- }
111
-
112
- logger.newLine();
113
- logger.success(`Added ${chalk.bold(moduleMetadata.displayName)}`);
114
- logger.newLine();
115
-
116
- // Print next steps
117
- if (moduleMetadata.envVars.some((v) => v.required)) {
118
- logger.log('Next: Fill in environment variables in .env');
119
- }
120
- logger.newLine();
121
- } catch (error) {
122
- logger.error(`Failed to add module: ${(error as Error).message}`);
123
- if (error instanceof Error && error.stack) {
124
- logger.log(chalk.gray(error.stack));
125
- }
126
- process.exit(1);
127
- }
128
- }
129
-
130
- async function loadModuleMetadata(
131
- modulesDir: string,
132
- moduleName: string,
133
- provider?: string
134
- ): Promise<ModuleMetadata | null> {
135
- if (!(await fs.pathExists(modulesDir))) {
136
- return null;
137
- }
138
-
139
- // Try to find module in any category
140
- const categories = await fs.readdir(modulesDir);
141
-
142
- for (const category of categories) {
143
- const categoryPath = path.join(modulesDir, category);
144
- const stat = await fs.stat(categoryPath);
145
-
146
- if (!stat.isDirectory()) continue;
147
-
148
- // Get all modules in this category
149
- const moduleDirs = await fs.readdir(categoryPath);
150
-
151
- for (const moduleDir of moduleDirs) {
152
- const modulePath = path.join(categoryPath, moduleDir);
153
- const moduleStat = await fs.stat(modulePath);
154
-
155
- if (!moduleStat.isDirectory()) continue;
156
-
157
- const metadataPath = path.join(modulePath, 'module.json');
158
-
159
- if (await fs.pathExists(metadataPath)) {
160
- const metadata = await fs.readJSON(metadataPath);
161
-
162
- // Match by module name or provider
163
- if (metadata.name === moduleName || (provider && moduleDir === provider)) {
164
- return metadata;
165
- }
166
- }
167
- }
168
- }
169
-
170
- return null;
171
- }
172
-
173
- async function applyModulePatches(
174
- projectRoot: string,
175
- projectInfo: any,
176
- moduleMetadata: ModuleMetadata,
177
- modulesDir: string,
178
- moduleName: string,
179
- options: AddOptions
180
- ): Promise<void> {
181
- const moduleBasePath = await findModulePath(modulesDir, moduleName, options.provider);
182
-
183
- if (!moduleBasePath) {
184
- throw new Error('Module files not found');
185
- }
186
-
187
- for (const patch of moduleMetadata.patches) {
188
- if (patch.type === 'create-file') {
189
- const filePatch = patch as CreateFilePatch;
190
-
191
- // Check conditions
192
- if (filePatch.condition) {
193
- if (filePatch.condition.router && filePatch.condition.router !== projectInfo.router) {
194
- continue; // Skip this patch
195
- }
196
- if (filePatch.condition.language && filePatch.condition.language !== projectInfo.language) {
197
- continue; // Skip this patch
198
- }
199
- }
200
-
201
- const sourceFile = path.join(moduleBasePath, 'files', filePatch.source);
202
- let destFile = path.join(projectRoot, filePatch.destination);
203
-
204
- // Replace placeholders in destination
205
- destFile = destFile
206
- .replace('{{router}}', getRouterBasePath(projectInfo))
207
- .replace('{{lib}}', getLibPath(projectInfo));
208
-
209
- if (!options.dryRun) {
210
- if (await fileExists(sourceFile)) {
211
- const content = await fs.readFile(sourceFile, 'utf-8');
212
- await createFile(destFile, content, { force: options.force });
213
- const relativePath = path.relative(projectRoot, destFile);
214
- logger.log(` ${chalk.green('+')} ${relativePath}`);
215
- } else {
216
- logger.warn(`Source file not found: ${filePatch.source}`);
217
- }
218
- } else {
219
- const relativePath = path.relative(projectRoot, destFile);
220
- logger.log(` ${chalk.dim('+')} ${relativePath}`);
221
- }
222
- }
223
- }
224
- }
225
-
226
- async function findModulePath(
227
- modulesDir: string,
228
- moduleName: string,
229
- provider?: string
230
- ): Promise<string | null> {
231
- const categories = await fs.readdir(modulesDir);
232
-
233
- for (const category of categories) {
234
- const categoryPath = path.join(modulesDir, category);
235
- const stat = await fs.stat(categoryPath);
236
-
237
- if (!stat.isDirectory()) continue;
238
-
239
- const moduleDirs = await fs.readdir(categoryPath);
240
-
241
- for (const moduleDir of moduleDirs) {
242
- const modulePath = path.join(categoryPath, moduleDir);
243
- const moduleStat = await fs.stat(modulePath);
244
-
245
- if (!moduleStat.isDirectory()) continue;
246
-
247
- const metadataPath = path.join(modulePath, 'module.json');
248
-
249
- if (await fs.pathExists(metadataPath)) {
250
- const metadata = await fs.readJSON(metadataPath);
251
-
252
- // Match by module name or provider
253
- if (metadata.name === moduleName || (provider && moduleDir === provider)) {
254
- return modulePath;
255
- }
256
- }
257
- }
258
- }
259
-
260
- return null;
261
- }
@@ -1,182 +0,0 @@
1
- import chalk from 'chalk';
2
- import fs from 'fs-extra';
3
- import inquirer from 'inquirer';
4
- import path from 'path';
5
- import validateNpmPackageName from 'validate-npm-package-name';
6
- import { TemplateMetadata } from '../types';
7
- import { copyTemplate } from '../utils/files';
8
- import { logger } from '../utils/logger';
9
- import { initGit, installDependencies, PackageManager } from '../utils/package-manager';
10
-
11
- interface InitOptions {
12
- template?: string;
13
- pm?: PackageManager;
14
- install?: boolean;
15
- git?: boolean;
16
- yes?: boolean;
17
- }
18
-
19
- export async function initCommand(
20
- projectName: string | undefined,
21
- options: InitOptions
22
- ): Promise<void> {
23
- try {
24
- // Validate package manager option
25
- if (options.pm && !['npm', 'yarn', 'pnpm'].includes(options.pm)) {
26
- logger.error(`Invalid package manager: ${options.pm}. Use npm, yarn, or pnpm.`);
27
- process.exit(1);
28
- }
29
-
30
- // Get available templates
31
- const templatesDir = path.join(__dirname, '..', '..', '..', '..', 'templates');
32
- const templates = await getAvailableTemplates(templatesDir);
33
-
34
- if (templates.length === 0) {
35
- logger.error('No templates found');
36
- process.exit(1);
37
- }
38
-
39
- // Prompt for project details if not using --yes
40
- let answers: {
41
- projectName: string;
42
- template: string;
43
- packageManager: PackageManager;
44
- install: boolean;
45
- git: boolean;
46
- };
47
-
48
- if (options.yes) {
49
- answers = {
50
- projectName: projectName || 'my-app',
51
- template: options.template || templates[0].name,
52
- packageManager: options.pm || 'pnpm',
53
- install: options.install !== false,
54
- git: options.git !== false,
55
- };
56
- } else {
57
- const prompted = await inquirer.prompt([
58
- {
59
- type: 'input',
60
- name: 'projectName',
61
- message: 'Project name:',
62
- default: projectName || 'my-app',
63
- when: !projectName,
64
- validate: (input: string) => {
65
- const validation = validateNpmPackageName(input);
66
- if (!validation.validForNewPackages) {
67
- return validation.errors?.[0] || 'Invalid package name';
68
- }
69
- return true;
70
- },
71
- },
72
- {
73
- type: 'list',
74
- name: 'template',
75
- message: 'Select a template:',
76
- choices: templates.map((t) => ({
77
- name: `${t.displayName} - ${t.description}`,
78
- value: t.name,
79
- })),
80
- when: !options.template,
81
- },
82
- {
83
- type: 'list',
84
- name: 'packageManager',
85
- message: 'Select a package manager:',
86
- choices: ['pnpm', 'npm', 'yarn'],
87
- default: 'pnpm',
88
- when: !options.pm,
89
- },
90
- {
91
- type: 'confirm',
92
- name: 'install',
93
- message: 'Install dependencies?',
94
- default: true,
95
- when: options.install !== false,
96
- },
97
- {
98
- type: 'confirm',
99
- name: 'git',
100
- message: 'Initialize git repository?',
101
- default: true,
102
- when: options.git !== false,
103
- },
104
- ]);
105
-
106
- answers = {
107
- projectName: projectName || prompted.projectName,
108
- template: options.template || prompted.template,
109
- packageManager: options.pm || prompted.packageManager,
110
- install: options.install !== false && (prompted.install ?? true),
111
- git: options.git !== false && (prompted.git ?? true),
112
- };
113
- }
114
-
115
- const targetDir = path.join(process.cwd(), answers.projectName);
116
-
117
- // Check if directory exists
118
- if (await fs.pathExists(targetDir)) {
119
- logger.error(`Directory "${answers.projectName}" already exists`);
120
- logger.info('Please choose a different name or remove the existing directory.');
121
- process.exit(1);
122
- }
123
-
124
- // Validate template exists
125
- const selectedTemplate = templates.find((t) => t.name === answers.template);
126
- if (!selectedTemplate) {
127
- logger.error(`Template "${answers.template}" not found`);
128
- process.exit(1);
129
- }
130
-
131
- logger.newLine();
132
-
133
- // Copy template
134
- const templatePath = path.join(templatesDir, answers.template);
135
- await copyTemplate(templatePath, targetDir, answers.projectName);
136
-
137
- // Install dependencies
138
- if (answers.install) {
139
- await installDependencies(targetDir, answers.packageManager);
140
- }
141
-
142
- // Initialize git
143
- if (answers.git) {
144
- await initGit(targetDir);
145
- }
146
-
147
- logger.newLine();
148
- logger.success(`Created ${chalk.bold(answers.projectName)}`);
149
- logger.newLine();
150
- logger.log(`Next steps:`);
151
- logger.log(` ${chalk.cyan('cd')} ${answers.projectName}`);
152
- if (!answers.install) {
153
- logger.log(` ${chalk.cyan(answers.packageManager)} install`);
154
- }
155
- logger.log(
156
- ` ${chalk.cyan(answers.packageManager)} ${answers.packageManager === 'npm' ? 'run ' : ''}dev`
157
- );
158
- logger.newLine();
159
- } catch (error) {
160
- logger.error(`Failed to create project: ${(error as Error).message}`);
161
- process.exit(1);
162
- }
163
- }
164
-
165
- async function getAvailableTemplates(templatesDir: string): Promise<TemplateMetadata[]> {
166
- if (!(await fs.pathExists(templatesDir))) {
167
- return [];
168
- }
169
-
170
- const templateDirs = await fs.readdir(templatesDir);
171
- const templates: TemplateMetadata[] = [];
172
-
173
- for (const dir of templateDirs) {
174
- const metadataPath = path.join(templatesDir, dir, 'template.json');
175
- if (await fs.pathExists(metadataPath)) {
176
- const metadata = await fs.readJSON(metadataPath);
177
- templates.push(metadata);
178
- }
179
- }
180
-
181
- return templates;
182
- }
@@ -1,124 +0,0 @@
1
- import chalk from 'chalk';
2
- import fs from 'fs-extra';
3
- import path from 'path';
4
- import { ModuleMetadata, TemplateMetadata } from '../types';
5
- import { logger } from '../utils/logger';
6
-
7
- interface ListOptions {
8
- templates?: boolean;
9
- modules?: boolean;
10
- }
11
-
12
- export async function listCommand(options: ListOptions): Promise<void> {
13
- const showTemplates = !options.modules || options.templates;
14
- const showModules = !options.templates || options.modules;
15
-
16
- try {
17
- // List templates
18
- if (showTemplates) {
19
- const templatesDir = path.join(__dirname, '..', '..', '..', '..', 'templates');
20
- const templates = await getAvailableTemplates(templatesDir);
21
-
22
- logger.log(chalk.bold('📦 Templates'));
23
- logger.newLine();
24
-
25
- if (templates.length === 0) {
26
- logger.warn(' No templates found');
27
- } else {
28
- for (const template of templates) {
29
- logger.log(chalk.bold(` ${template.displayName}`));
30
- logger.log(chalk.gray(` ${template.description}`));
31
- logger.log(chalk.blue(` Command: stackkit init --template ${template.name}`));
32
- logger.log(chalk.gray(` Features: ${template.features.join(', ')}`));
33
- logger.newLine();
34
- }
35
- }
36
- }
37
-
38
- // List modules
39
- if (showModules) {
40
- const modulesDir = path.join(__dirname, '..', '..', '..', '..', 'modules');
41
- const modules = await getAvailableModules(modulesDir);
42
-
43
- logger.log(chalk.bold('🔧 Modules'));
44
- logger.newLine();
45
-
46
- if (modules.length === 0) {
47
- logger.warn(' No modules found');
48
- } else {
49
- // Group by category
50
- const grouped = modules.reduce(
51
- (acc, mod) => {
52
- if (!acc[mod.category]) {
53
- acc[mod.category] = [];
54
- }
55
- acc[mod.category].push(mod);
56
- return acc;
57
- },
58
- {} as Record<string, ModuleMetadata[]>
59
- );
60
-
61
- for (const [category, mods] of Object.entries(grouped)) {
62
- logger.log(chalk.yellow(` ${category.toUpperCase()}:`));
63
- for (const mod of mods) {
64
- logger.log(chalk.bold(` ${mod.displayName}`));
65
- logger.log(chalk.gray(` ${mod.description}`));
66
- logger.log(chalk.blue(` Command: stackkit add ${mod.name}`));
67
- logger.log(chalk.gray(` Supports: ${mod.supportedFrameworks.join(', ')}`));
68
- logger.newLine();
69
- }
70
- }
71
- }
72
- }
73
- } catch (error) {
74
- logger.error(`Failed to list resources: ${(error as Error).message}`);
75
- process.exit(1);
76
- }
77
- }
78
-
79
- async function getAvailableTemplates(templatesDir: string): Promise<TemplateMetadata[]> {
80
- if (!(await fs.pathExists(templatesDir))) {
81
- return [];
82
- }
83
-
84
- const templateDirs = await fs.readdir(templatesDir);
85
- const templates: TemplateMetadata[] = [];
86
-
87
- for (const dir of templateDirs) {
88
- const metadataPath = path.join(templatesDir, dir, 'template.json');
89
- if (await fs.pathExists(metadataPath)) {
90
- const metadata = await fs.readJSON(metadataPath);
91
- templates.push(metadata);
92
- }
93
- }
94
-
95
- return templates;
96
- }
97
-
98
- async function getAvailableModules(modulesDir: string): Promise<ModuleMetadata[]> {
99
- if (!(await fs.pathExists(modulesDir))) {
100
- return [];
101
- }
102
-
103
- const modules: ModuleMetadata[] = [];
104
- const categories = await fs.readdir(modulesDir);
105
-
106
- for (const category of categories) {
107
- const categoryPath = path.join(modulesDir, category);
108
- const stat = await fs.stat(categoryPath);
109
-
110
- if (!stat.isDirectory()) continue;
111
-
112
- const moduleDirs = await fs.readdir(categoryPath);
113
-
114
- for (const moduleDir of moduleDirs) {
115
- const metadataPath = path.join(categoryPath, moduleDir, 'module.json');
116
- if (await fs.pathExists(metadataPath)) {
117
- const metadata = await fs.readJSON(metadataPath);
118
- modules.push(metadata);
119
- }
120
- }
121
- }
122
-
123
- return modules;
124
- }
package/src/index.ts DELETED
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env node
2
- import chalk from 'chalk';
3
- import { Command } from 'commander';
4
- import { addCommand } from './commands/add';
5
- import { initCommand } from './commands/init';
6
- import { listCommand } from './commands/list';
7
-
8
- const program = new Command();
9
-
10
- program
11
- .name('stackkit')
12
- .description('Production-ready project generator and module CLI')
13
- .version('0.1.0');
14
-
15
- // Init command
16
- program
17
- .command('init [project-name]')
18
- .description('Create a new project from a template')
19
- .option('-t, --template <template>', 'Template to use')
20
- .option('--pm <pm>', 'Package manager to use (npm, yarn, pnpm)')
21
- .option('--no-install', 'Skip installing dependencies')
22
- .option('--no-git', 'Skip git initialization')
23
- .option('-y, --yes', 'Skip prompts and use defaults')
24
- .action(initCommand);
25
-
26
- // List command
27
- program
28
- .command('list')
29
- .description('List available templates and modules')
30
- .option('-t, --templates', 'List only templates')
31
- .option('-m, --modules', 'List only modules')
32
- .action(listCommand);
33
-
34
- // Add command
35
- program
36
- .command('add <module>')
37
- .description('Add a module to your existing project')
38
- .option('--provider <provider>', 'Specific provider/variant to use')
39
- .option('--force', 'Overwrite existing files')
40
- .option('--dry-run', 'Show what would be changed without making changes')
41
- .option('--no-install', 'Skip installing dependencies')
42
- .action(addCommand);
43
-
44
- // Error handling
45
- program.on('command:*', () => {
46
- console.error(
47
- chalk.red(`\nInvalid command: ${program.args.join(' ')}\n`)
48
- );
49
- console.log(chalk.yellow('Run stackkit --help for a list of available commands.\n'));
50
- process.exit(1);
51
- });
52
-
53
- program.parse();
@@ -1,71 +0,0 @@
1
- export interface TemplateMetadata {
2
- name: string;
3
- displayName: string;
4
- description: string;
5
- tags: string[];
6
- defaultPackageManager: 'pnpm' | 'npm' | 'yarn';
7
- features: string[];
8
- }
9
-
10
- export interface ModuleMetadata {
11
- name: string;
12
- displayName: string;
13
- description: string;
14
- category: 'auth' | 'database' | 'ui' | 'other';
15
- supportedFrameworks: string[];
16
- dependencies: Record<string, string>;
17
- devDependencies?: Record<string, string>;
18
- envVars: EnvVar[];
19
- patches: ModulePatch[];
20
- }
21
-
22
- export interface EnvVar {
23
- key: string;
24
- value?: string;
25
- description: string;
26
- required: boolean;
27
- }
28
-
29
- export interface ModulePatch {
30
- type: 'create-file' | 'modify-json' | 'append-env' | 'inject-code';
31
- description: string;
32
- [key: string]: any;
33
- }
34
-
35
- export interface CreateFilePatch extends ModulePatch {
36
- type: 'create-file';
37
- source: string;
38
- destination: string;
39
- condition?: {
40
- router?: 'app' | 'pages';
41
- language?: 'ts' | 'js';
42
- };
43
- }
44
-
45
- export interface ModifyJsonPatch extends ModulePatch {
46
- type: 'modify-json';
47
- file: string;
48
- operations: {
49
- path: string;
50
- value: any;
51
- merge?: boolean;
52
- }[];
53
- }
54
-
55
- export interface ProjectInfo {
56
- framework: 'nextjs' | 'unknown';
57
- router: 'app' | 'pages' | 'unknown';
58
- language: 'ts' | 'js';
59
- packageManager: 'npm' | 'yarn' | 'pnpm';
60
- hasAuth: boolean;
61
- hasPrisma: boolean;
62
- rootDir: string;
63
- }
64
-
65
- export interface CLIOptions {
66
- force?: boolean;
67
- dryRun?: boolean;
68
- yes?: boolean;
69
- noInstall?: boolean;
70
- pm?: 'npm' | 'yarn' | 'pnpm';
71
- }