easybuild-nox 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.
@@ -0,0 +1,188 @@
1
+ const { Command } = require('commander');
2
+ const { spawn } = require('child_process');
3
+ const path = require('path');
4
+ const fs = require('fs-extra');
5
+ const logger = require('../utils/logger');
6
+ const ProjectDetector = require('../utils/detector');
7
+ const ConfigLoader = require('../utils/config');
8
+ const sharedModules = require('../utils/modules');
9
+ const globalConfig = require('../utils/globalConfig');
10
+
11
+ const devCommand = new Command('dev')
12
+ .description('Start development server with hot reload')
13
+ .option('-p, --port <port>', 'Port number', '3000')
14
+ .option('-h, --host <host>', 'Host address', 'localhost')
15
+ .option('--open', 'Open browser', true)
16
+ .option('--no-shared', 'Disable shared modules for this run')
17
+ .action(async (options) => {
18
+ logger.header('⚡ Starting Development Server');
19
+
20
+ const detector = new ProjectDetector();
21
+ const config = new ConfigLoader();
22
+
23
+ try {
24
+ const projectInfo = await detector.detect();
25
+ const configData = await config.load();
26
+
27
+ logger.info(`Framework: ${projectInfo.framework?.name || 'Unknown'}`);
28
+ logger.info(`Type: ${projectInfo.type || 'Unknown'}`);
29
+ logger.info(`Port: ${options.port}`);
30
+
31
+ // Use shared modules by default (unless --no-shared is passed)
32
+ if (options.shared !== false) {
33
+ await sharedModules.init();
34
+ const configData = await globalConfig.load();
35
+ const useShared = configData.sharedModules?.enabled !== false;
36
+
37
+ if (useShared) {
38
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
39
+ if (await fs.pathExists(packageJsonPath)) {
40
+ logger.dim('Using shared modules...');
41
+ await sharedModules.installFromPackageJson(packageJsonPath);
42
+ await setupNodePath();
43
+ }
44
+ }
45
+ }
46
+
47
+ // Set environment
48
+ process.env.NODE_ENV = 'development';
49
+ process.env.PORT = options.port;
50
+ process.env.HOST = options.host;
51
+
52
+ await startDevServer(projectInfo, configData, options);
53
+ } catch (error) {
54
+ logger.error(`Failed to start dev server: ${error.message}`);
55
+ process.exit(1);
56
+ }
57
+ });
58
+
59
+ async function startDevServer(projectInfo, config, options) {
60
+ const pkg = await fs.readJson(path.join(process.cwd(), 'package.json'));
61
+ const scripts = pkg.scripts || {};
62
+
63
+ let command = null;
64
+ let args = [];
65
+
66
+ if (projectInfo.framework) {
67
+ const devCommands = {
68
+ // Backend
69
+ express: { command: 'nodemon', args: ['src/index.js'] },
70
+ fastify: { command: 'nodemon', args: ['src/index.js'] },
71
+ koa: { command: 'nodemon', args: ['src/index.js'] },
72
+ hapi: { command: 'nodemon', args: ['src/index.js'] },
73
+ nestjs: { command: 'npm', args: ['run', 'start:dev'] },
74
+ adonis: { command: 'npm', args: ['run', 'dev'] },
75
+ strapi: { command: 'npm', args: ['run', 'develop'] },
76
+ hono: { command: 'npm', args: ['run', 'dev'] },
77
+ trpc: { command: 'npm', args: ['run', 'dev'] },
78
+ graphql: { command: 'npm', args: ['run', 'dev'] },
79
+ socketio: { command: 'npm', args: ['run', 'dev'] },
80
+
81
+ // Frontend
82
+ react: { command: 'npm', args: ['start'] },
83
+ vue: { command: 'npm', args: ['run', 'serve'] },
84
+ angular: { command: 'ng', args: ['serve'] },
85
+ svelte: { command: 'npm', args: ['run', 'dev'] },
86
+ solid: { command: 'npm', args: ['run', 'dev'] },
87
+ preact: { command: 'npm', args: ['run', 'dev'] },
88
+ lit: { command: 'npm', args: ['run', 'dev'] },
89
+ alpine: { command: 'npm', args: ['run', 'dev'] },
90
+ htmx: { command: 'npm', args: ['run', 'dev'] },
91
+
92
+ // Full-stack
93
+ nextjs: { command: 'npm', args: ['run', 'dev'] },
94
+ nuxt: { command: 'npm', args: ['run', 'dev'] },
95
+ remix: { command: 'npm', args: ['run', 'dev'] },
96
+ gatsby: { command: 'npm', args: ['run', 'develop'] },
97
+ astro: { command: 'npm', args: ['run', 'dev'] },
98
+ sveltekit: { command: 'npm', args: ['run', 'dev'] },
99
+ solidstart: { command: 'npm', args: ['run', 'dev'] },
100
+ qwik: { command: 'npm', args: ['run', 'dev'] },
101
+ analog: { command: 'npm', args: ['run', 'dev'] },
102
+ fresh: { command: 'deno', args: ['task', 'dev'] },
103
+ tanstack: { command: 'npm', args: ['run', 'dev'] },
104
+ waku: { command: 'npm', args: ['run', 'dev'] },
105
+
106
+ // Desktop
107
+ electron: { command: 'npm', args: ['run', 'dev'] },
108
+ tauri: { command: 'npm', args: ['run', 'dev'] },
109
+ nwjs: { command: 'npm', args: ['run', 'dev'] },
110
+
111
+ // Mobile
112
+ reactnative: { command: 'npm', args: ['start'] },
113
+ expo: { command: 'npm', args: ['start'] },
114
+ ionic: { command: 'npm', args: ['start'] },
115
+ tamagui: { command: 'npm', args: ['start'] },
116
+ nativebase: { command: 'npm', args: ['start'] },
117
+
118
+ // Database
119
+ drizzle: { command: 'npm', args: ['run', 'dev'] },
120
+ prisma: { command: 'npm', args: ['run', 'dev'] },
121
+ };
122
+
123
+ const devConfig = devCommands[projectInfo.framework.name];
124
+ if (devConfig) {
125
+ command = devConfig.command;
126
+ args = devConfig.args;
127
+ }
128
+ }
129
+
130
+ // Fallback to package.json scripts
131
+ if (!command) {
132
+ if (scripts.dev) {
133
+ command = 'npm';
134
+ args = ['run', 'dev'];
135
+ } else if (scripts['start:dev']) {
136
+ command = 'npm';
137
+ args = ['run', 'start:dev'];
138
+ } else if (scripts.serve) {
139
+ command = 'npm';
140
+ args = ['run', 'serve'];
141
+ } else {
142
+ throw new Error('No dev script found. Add a "dev" script to package.json');
143
+ }
144
+ }
145
+
146
+ logger.info(`Starting: ${command} ${args.join(' ')}`);
147
+ logger.dim('Press Ctrl+C to stop');
148
+ logger.info('');
149
+
150
+ const child = spawn(command, args, {
151
+ stdio: 'inherit',
152
+ shell: true,
153
+ env: {
154
+ ...process.env,
155
+ NODE_ENV: 'development',
156
+ PORT: options.port,
157
+ HOST: options.host,
158
+ },
159
+ });
160
+
161
+ child.on('error', (error) => {
162
+ logger.error(`Process failed: ${error.message}`);
163
+ process.exit(1);
164
+ });
165
+
166
+ child.on('close', (code) => {
167
+ if (code !== 0) {
168
+ logger.error(`Process exited with code ${code}`);
169
+ process.exit(code);
170
+ }
171
+ });
172
+ }
173
+
174
+ async function setupNodePath() {
175
+ const sharedPath = sharedModules.getSharedModulesPath();
176
+ const currentPath = process.env.NODE_PATH || '';
177
+
178
+ if (!currentPath.includes(sharedPath)) {
179
+ process.env.NODE_PATH = currentPath
180
+ ? `${sharedPath}${path.delimiter}${currentPath}`
181
+ : sharedPath;
182
+
183
+ // Rehash require paths
184
+ require('module')._initPaths();
185
+ }
186
+ }
187
+
188
+ module.exports = devCommand;
@@ -0,0 +1,264 @@
1
+ const { Command } = require('commander');
2
+ const { spawn } = require('child_process');
3
+ const path = require('path');
4
+ const fs = require('fs-extra');
5
+ const logger = require('../utils/logger');
6
+ const ProjectDetector = require('../utils/detector');
7
+ const ConfigLoader = require('../utils/config');
8
+
9
+ const dockerCommand = new Command('docker')
10
+ .description('Docker operations')
11
+ .option('-a, --action <action>', 'Action (build, run, stop, logs, push)', 'build')
12
+ .option('-t, --tag <tag>', 'Docker image tag', 'latest')
13
+ .option('-p, --port <port>', 'Port mapping', '3000')
14
+ .action(async (options) => {
15
+ logger.header('🐳 Docker Operations');
16
+
17
+ const detector = new ProjectDetector();
18
+ const config = new ConfigLoader();
19
+
20
+ try {
21
+ const projectInfo = await detector.detect();
22
+ const configData = await config.load();
23
+
24
+ logger.info(`Action: ${options.action}`);
25
+ logger.info(`Tag: ${options.tag}`);
26
+
27
+ await dockerOperation(projectInfo, configData, options);
28
+ } catch (error) {
29
+ logger.error(`Docker operation failed: ${error.message}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ async function dockerOperation(projectInfo, config, options) {
35
+ // Ensure Dockerfile exists
36
+ const dockerfilePath = path.join(process.cwd(), 'Dockerfile');
37
+ if (!(await fs.pathExists(dockerfilePath))) {
38
+ logger.warning('No Dockerfile found. Generating one...');
39
+ await generateDockerfile(projectInfo, config);
40
+ }
41
+
42
+ const actions = {
43
+ build: dockerBuild,
44
+ run: dockerRun,
45
+ stop: dockerStop,
46
+ logs: dockerLogs,
47
+ push: dockerPush,
48
+ compose: dockerCompose,
49
+ };
50
+
51
+ const action = actions[options.action];
52
+ if (!action) {
53
+ throw new Error(`Unknown action: ${options.action}`);
54
+ }
55
+
56
+ await action(projectInfo, config, options);
57
+ }
58
+
59
+ async function generateDockerfile(projectInfo, config) {
60
+ const dockerConfig = config.docker || {};
61
+ const baseImage = dockerConfig.baseImage || 'node:20-alpine';
62
+ const workdir = dockerConfig.workdir || '/app';
63
+ const port = dockerConfig.port || 3000;
64
+
65
+ const dockerfile = `# Use Node.js alpine image
66
+ FROM ${baseImage} AS builder
67
+
68
+ # Set working directory
69
+ WORKDIR ${workdir}
70
+
71
+ # Copy package files
72
+ COPY package*.json ./
73
+
74
+ # Install dependencies
75
+ RUN npm ci
76
+
77
+ # Copy source code
78
+ COPY . .
79
+
80
+ # Build application (if needed)
81
+ RUN npm run build 2>/dev/null || true
82
+
83
+ # Production stage
84
+ FROM ${baseImage}
85
+
86
+ # Set working directory
87
+ WORKDIR ${workdir}
88
+
89
+ # Copy package files
90
+ COPY package*.json ./
91
+
92
+ # Install production dependencies only
93
+ RUN npm ci --only=production
94
+
95
+ # Copy built application
96
+ COPY --from=builder ${workdir}/dist ./dist
97
+ COPY --from=builder ${workdir}/src ./src
98
+
99
+ # Expose port
100
+ EXPOSE ${port}
101
+
102
+ # Start application
103
+ CMD ["node", "src/index.js"]
104
+ `;
105
+
106
+ await fs.writeFile(dockerfilePath, dockerfile);
107
+ logger.success('Dockerfile generated');
108
+ }
109
+
110
+ async function dockerBuild(projectInfo, config, options) {
111
+ logger.info('Building Docker image...');
112
+
113
+ const pkg = await fs.readJson(path.join(process.cwd(), 'package.json'));
114
+ const imageName = pkg.name || 'app';
115
+
116
+ const child = spawn('docker', ['build', '-t', `${imageName}:${options.tag}`, '.'], {
117
+ stdio: 'inherit',
118
+ shell: true,
119
+ });
120
+
121
+ return new Promise((resolve, reject) => {
122
+ child.on('close', (code) => {
123
+ if (code === 0) {
124
+ logger.success(`Docker image built: ${imageName}:${options.tag}`);
125
+ resolve();
126
+ } else {
127
+ reject(new Error('Docker build failed'));
128
+ }
129
+ });
130
+ });
131
+ }
132
+
133
+ async function dockerRun(projectInfo, config, options) {
134
+ logger.info('Running Docker container...');
135
+
136
+ const pkg = await fs.readJson(path.join(process.cwd(), 'package.json'));
137
+ const imageName = pkg.name || 'app';
138
+ const containerName = `${imageName}-container`;
139
+
140
+ // Stop existing container if running
141
+ try {
142
+ await new Promise((resolve) => {
143
+ const stop = spawn('docker', ['stop', containerName], {
144
+ shell: true,
145
+ });
146
+ stop.on('close', () => resolve());
147
+ });
148
+ } catch (e) {
149
+ // Ignore if container doesn't exist
150
+ }
151
+
152
+ const child = spawn('docker', [
153
+ 'run', '-d',
154
+ '--name', containerName,
155
+ '-p', `${options.port}:3000`,
156
+ `${imageName}:${options.tag}`,
157
+ ], {
158
+ stdio: 'inherit',
159
+ shell: true,
160
+ });
161
+
162
+ return new Promise((resolve, reject) => {
163
+ child.on('close', (code) => {
164
+ if (code === 0) {
165
+ logger.success(`Container running on port ${options.port}`);
166
+ resolve();
167
+ } else {
168
+ reject(new Error('Docker run failed'));
169
+ }
170
+ });
171
+ });
172
+ }
173
+
174
+ async function dockerStop(projectInfo, config, options) {
175
+ logger.info('Stopping Docker container...');
176
+
177
+ const pkg = await fs.readJson(path.join(process.cwd(), 'package.json'));
178
+ const imageName = pkg.name || 'app';
179
+ const containerName = `${imageName}-container`;
180
+
181
+ const child = spawn('docker', ['stop', containerName], {
182
+ stdio: 'inherit',
183
+ shell: true,
184
+ });
185
+
186
+ return new Promise((resolve, reject) => {
187
+ child.on('close', (code) => {
188
+ if (code === 0) {
189
+ logger.success('Container stopped');
190
+ resolve();
191
+ } else {
192
+ reject(new Error('Docker stop failed'));
193
+ }
194
+ });
195
+ });
196
+ }
197
+
198
+ async function dockerLogs(projectInfo, config, options) {
199
+ logger.info('Showing Docker logs...');
200
+
201
+ const pkg = await fs.readJson(path.join(process.cwd(), 'package.json'));
202
+ const imageName = pkg.name || 'app';
203
+ const containerName = `${imageName}-container`;
204
+
205
+ const child = spawn('docker', ['logs', '-f', containerName], {
206
+ stdio: 'inherit',
207
+ shell: true,
208
+ });
209
+
210
+ return new Promise((resolve, reject) => {
211
+ child.on('close', (code) => {
212
+ if (code === 0) {
213
+ resolve();
214
+ } else {
215
+ reject(new Error('Docker logs failed'));
216
+ }
217
+ });
218
+ });
219
+ }
220
+
221
+ async function dockerPush(projectInfo, config, options) {
222
+ logger.info('Pushing Docker image...');
223
+
224
+ const pkg = await fs.readJson(path.join(process.cwd(), 'package.json'));
225
+ const imageName = pkg.name || 'app';
226
+
227
+ const child = spawn('docker', ['push', `${imageName}:${options.tag}`], {
228
+ stdio: 'inherit',
229
+ shell: true,
230
+ });
231
+
232
+ return new Promise((resolve, reject) => {
233
+ child.on('close', (code) => {
234
+ if (code === 0) {
235
+ logger.success('Image pushed successfully');
236
+ resolve();
237
+ } else {
238
+ reject(new Error('Docker push failed'));
239
+ }
240
+ });
241
+ });
242
+ }
243
+
244
+ async function dockerCompose(projectInfo, config, options) {
245
+ logger.info('Running Docker Compose...');
246
+
247
+ const child = spawn('docker-compose', ['up', '-d'], {
248
+ stdio: 'inherit',
249
+ shell: true,
250
+ });
251
+
252
+ return new Promise((resolve, reject) => {
253
+ child.on('close', (code) => {
254
+ if (code === 0) {
255
+ logger.success('Docker Compose started');
256
+ resolve();
257
+ } else {
258
+ reject(new Error('Docker Compose failed'));
259
+ }
260
+ });
261
+ });
262
+ }
263
+
264
+ module.exports = dockerCommand;
@@ -0,0 +1,210 @@
1
+ const { Command } = require('commander');
2
+ const { spawn } = require('child_process');
3
+ const path = require('path');
4
+ const fs = require('fs-extra');
5
+ const logger = require('../utils/logger');
6
+ const ProjectDetector = require('../utils/detector');
7
+ const ConfigLoader = require('../utils/config');
8
+
9
+ const electronCommand = new Command('electron')
10
+ .description('Electron operations')
11
+ .option('-a, --action <action>', 'Action (dev, build, pack)', 'dev')
12
+ .option('-p, --platform <platform>', 'Target platform (win, mac, linux, all)', 'current')
13
+ .option('--arch <arch>', 'Target architecture (x64, arm64, all)', 'current')
14
+ .action(async (options) => {
15
+ logger.header('⚡ Electron Operations');
16
+
17
+ const detector = new ProjectDetector();
18
+ const config = new ConfigLoader();
19
+
20
+ try {
21
+ const projectInfo = await detector.detect();
22
+ const configData = await config.load();
23
+
24
+ logger.info(`Action: ${options.action}`);
25
+ logger.info(`Platform: ${options.platform}`);
26
+
27
+ await electronOperation(projectInfo, configData, options);
28
+ } catch (error) {
29
+ logger.error(`Electron operation failed: ${error.message}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ async function electronOperation(projectInfo, config, options) {
35
+ // Ensure electron config exists
36
+ const electronConfig = config.electron || {};
37
+
38
+ // Check if electron-builder config exists
39
+ const builderConfigPath = path.join(process.cwd(), 'electron-builder.yml');
40
+ const builderJsonPath = path.join(process.cwd(), 'electron-builder.json');
41
+
42
+ if (!(await fs.pathExists(builderConfigPath)) && !(await fs.pathExists(builderJsonPath))) {
43
+ logger.warning('No electron-builder config found. Generating one...');
44
+ await generateElectronConfig(projectInfo, config);
45
+ }
46
+
47
+ const actions = {
48
+ dev: electronDev,
49
+ build: electronBuild,
50
+ pack: electronPack,
51
+ };
52
+
53
+ const action = actions[options.action];
54
+ if (!action) {
55
+ throw new Error(`Unknown action: ${options.action}`);
56
+ }
57
+
58
+ await action(projectInfo, config, options);
59
+ }
60
+
61
+ async function generateElectronConfig(projectInfo, config) {
62
+ const electronConfig = config.electron || {};
63
+
64
+ const builderConfig = {
65
+ appId: `com.${projectInfo.packageJson?.name || 'app'}.electron`,
66
+ productName: projectInfo.packageJson?.name || 'Electron App',
67
+ directories: {
68
+ output: electronConfig.output || 'release',
69
+ },
70
+ files: [
71
+ 'electron/**/*',
72
+ 'dist/**/*',
73
+ 'package.json',
74
+ ],
75
+ mac: {
76
+ category: 'public.app-category.developer-tools',
77
+ icon: electronConfig.icon || null,
78
+ target: [
79
+ { target: 'dmg', arch: ['x64', 'arm64'] },
80
+ { target: 'zip', arch: ['x64', 'arm64'] },
81
+ ],
82
+ },
83
+ win: {
84
+ icon: electronConfig.icon || null,
85
+ target: [
86
+ { target: 'nsis', arch: ['x64'] },
87
+ { target: 'portable', arch: ['x64'] },
88
+ ],
89
+ },
90
+ linux: {
91
+ icon: electronConfig.icon || null,
92
+ target: [
93
+ { target: 'AppImage', arch: ['x64'] },
94
+ { target: 'deb', arch: ['x64'] },
95
+ { target: 'rpm', arch: ['x64'] },
96
+ ],
97
+ category: 'Development',
98
+ },
99
+ nsis: {
100
+ oneClick: false,
101
+ allowToChangeInstallationDirectory: true,
102
+ },
103
+ };
104
+
105
+ await fs.writeFile(
106
+ path.join(process.cwd(), 'electron-builder.yml'),
107
+ require('js-yaml').dump(builderConfig)
108
+ );
109
+
110
+ logger.success('electron-builder.yml generated');
111
+ }
112
+
113
+ async function electronDev(projectInfo, config, options) {
114
+ logger.info('Starting Electron in development mode...');
115
+
116
+ // Check if electron is installed
117
+ const pkg = await fs.readJson(path.join(process.cwd(), 'package.json'));
118
+ if (!pkg.devDependencies?.electron && !pkg.dependencies?.electron) {
119
+ logger.info('Installing Electron...');
120
+ await new Promise((resolve, reject) => {
121
+ const install = spawn('npm', ['install', 'electron', '--save-dev'], {
122
+ stdio: 'inherit',
123
+ shell: true,
124
+ });
125
+ install.on('close', (code) => {
126
+ if (code === 0) resolve();
127
+ else reject(new Error('Failed to install Electron'));
128
+ });
129
+ });
130
+ }
131
+
132
+ const child = spawn('electron', ['.'], {
133
+ stdio: 'inherit',
134
+ shell: true,
135
+ env: {
136
+ ...process.env,
137
+ NODE_ENV: 'development',
138
+ },
139
+ });
140
+
141
+ return new Promise((resolve, reject) => {
142
+ child.on('close', (code) => {
143
+ if (code === 0) {
144
+ resolve();
145
+ } else {
146
+ reject(new Error('Electron dev failed'));
147
+ }
148
+ });
149
+ });
150
+ }
151
+
152
+ async function electronBuild(projectInfo, config, options) {
153
+ logger.info('Building Electron application...');
154
+
155
+ const args = ['electron-builder'];
156
+
157
+ // Platform
158
+ if (options.platform === 'all') {
159
+ args.push('-mwl');
160
+ } else if (options.platform === 'win') {
161
+ args.push('--win');
162
+ } else if (options.platform === 'mac') {
163
+ args.push('--mac');
164
+ } else if (options.platform === 'linux') {
165
+ args.push('--linux');
166
+ }
167
+
168
+ // Architecture
169
+ if (options.arch && options.arch !== 'current') {
170
+ args.push(`--${options.arch}`);
171
+ }
172
+
173
+ const child = spawn('npx', args, {
174
+ stdio: 'inherit',
175
+ shell: true,
176
+ });
177
+
178
+ return new Promise((resolve, reject) => {
179
+ child.on('close', (code) => {
180
+ if (code === 0) {
181
+ logger.success('Electron build completed!');
182
+ resolve();
183
+ } else {
184
+ reject(new Error('Electron build failed'));
185
+ }
186
+ });
187
+ });
188
+ }
189
+
190
+ async function electronPack(projectInfo, config, options) {
191
+ logger.info('Packaging Electron application...');
192
+
193
+ const child = spawn('npx', ['electron-builder', '--dir'], {
194
+ stdio: 'inherit',
195
+ shell: true,
196
+ });
197
+
198
+ return new Promise((resolve, reject) => {
199
+ child.on('close', (code) => {
200
+ if (code === 0) {
201
+ logger.success('Electron packaging completed!');
202
+ resolve();
203
+ } else {
204
+ reject(new Error('Electron packaging failed'));
205
+ }
206
+ });
207
+ });
208
+ }
209
+
210
+ module.exports = electronCommand;