@flowdevcli/flowdev 1.0.4 → 1.0.5

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,10 +1,28 @@
1
- import ollama from 'ollama';
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
2
20
  import chalk from 'chalk';
3
21
  import ora from 'ora';
4
22
  import fs from 'fs-extra';
5
23
  import path from 'path';
6
24
  import { logger } from '../../utils/logger.js';
7
- import { ensureEngineReady } from '../../utils/engine-check.js';
25
+ import { getAIResponse } from '../../utils/engine-check.js'; // IMPORT UPDATED
8
26
 
9
27
  export async function testCommand(fileRelativePath) {
10
28
  const spinner = ora(chalk.cyan(`Preparing test generation...`)).start();
@@ -12,15 +30,11 @@ export async function testCommand(fileRelativePath) {
12
30
  try {
13
31
  const filePath = path.resolve(process.cwd(), fileRelativePath);
14
32
 
15
-
16
33
  if (!(await fs.pathExists(filePath))) {
17
34
  spinner.fail(chalk.red(`File not found: ${fileRelativePath}`));
18
35
  return;
19
36
  }
20
37
 
21
-
22
- await ensureEngineReady(spinner, 'llama3');
23
-
24
38
  const content = await fs.readFile(filePath, 'utf-8');
25
39
  const ext = path.extname(filePath);
26
40
  const fileName = path.basename(filePath, ext);
@@ -34,27 +48,35 @@ export async function testCommand(fileRelativePath) {
34
48
  testFileName = `test_${fileName}${ext}`;
35
49
  }
36
50
 
37
- spinner.text = chalk.magenta(`Writing ${framework} tests for ${fileName}...`);
38
-
39
51
  const prompt = `
40
52
  Analyze the following code and generate a complete test file using ${framework}.
41
53
  Requirements:
42
54
  - Include all necessary imports.
43
- - Cover the main functions with "happy path" and "edge cases" (extremes, nulls, errors).
44
- - Use descriptive test names.
55
+ - Cover main functions with happy paths and edge cases.
45
56
  - Return ONLY the code block starting with \`\`\` and ending with \`\`\`.
46
57
 
47
58
  Code to test:
48
59
  ${content}
49
60
  `;
50
61
 
51
- const response = await ollama.chat({
52
- model: 'llama3',
53
- messages: [{ role: 'user', content: prompt }],
54
- });
62
+ // APPEL UNIFIÉ
63
+ const responseStream = await getAIResponse(
64
+ [{ role: 'user', content: prompt }],
65
+ spinner
66
+ );
55
67
 
56
- const fullResponse = response.message.content;
68
+ // On consomme le stream pour reconstruire la réponse complète
69
+ let fullResponse = "";
70
+ spinner.text = chalk.yellow("Writing tests (Streaming)...");
57
71
 
72
+ for await (const part of responseStream) {
73
+ fullResponse += part.message.content;
74
+ // Petit effet visuel optionnel pour montrer que ça bosse
75
+ spinner.text = chalk.yellow(`Generating tests... (${fullResponse.length} chars)`);
76
+ }
77
+
78
+ spinner.stop();
79
+
58
80
  const codeBlockRegex = /```[\w]*\n([\s\S]*?)```/;
59
81
  const match = fullResponse.match(codeBlockRegex);
60
82
  const testCode = match ? match[1] : fullResponse;
@@ -62,12 +84,12 @@ export async function testCommand(fileRelativePath) {
62
84
  const outputPath = path.join(dir, testFileName);
63
85
  await fs.writeFile(outputPath, testCode);
64
86
 
65
- (chalk.green(`Tests generated successfully!`));
66
- console.log(chalk.gray(`\n Location: `) + chalk.white(outputPath));
87
+ console.log(chalk.green(`\n✅ Tests generated successfully!`));
88
+ console.log(chalk.gray(` Location: `) + chalk.white(outputPath));
67
89
  console.log(chalk.yellow(` Tip: Run your tests with '${ext === '.py' ? 'pytest' : 'npm test'}'`));
68
90
 
69
91
  } catch (error) {
70
- (chalk.red('Test generation failed.'));
71
- logger.error(error.message);
92
+ spinner.stop();
93
+ logger.error('Test generation failed: ' + error.message);
72
94
  }
73
95
  }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
20
+ import inquirer from 'inquirer';
21
+ import chalk from 'chalk';
22
+ import { setDeepSeekKey, getDeepSeekKey, clearDeepSeekKey } from '../utils/config-manager.js';
23
+
24
+ export async function configCommand() {
25
+ const currentKey = getDeepSeekKey();
26
+
27
+ if (currentKey) {
28
+ console.log(`DeepSeek API Key: ${chalk.green('Configured' + '•'.repeat(10))}`);
29
+ } else {
30
+ console.log(`DeepSeek API Key: ${chalk.red('Not configured')}`);
31
+ }
32
+ console.log('');
33
+
34
+ const { action } = await inquirer.prompt([
35
+ {
36
+ type: 'list',
37
+ name: 'action',
38
+ message: 'What do you want to do?',
39
+ choices: [
40
+ { name: 'Configure/Update the DeepSeek key', value: 'set' },
41
+ { name: 'Delete the existing key', value: 'delete' },
42
+ { name: 'Leave', value: 'exit' }
43
+ ]
44
+ }
45
+ ]);
46
+
47
+ if (action === 'set') {
48
+ const { key } = await inquirer.prompt([
49
+ {
50
+ type: 'password',
51
+ name: 'key',
52
+ message: 'Enter your DeepSeek API key (sk-...) :',
53
+ mask: '*'
54
+ }
55
+ ]);
56
+ if (key) {
57
+ setDeepSeekKey(key.trim());
58
+ console.log(chalk.green('\nKey saved successfully!'));
59
+ }
60
+ } else if (action === 'delete') {
61
+ clearDeepSeekKey();
62
+ console.log(chalk.yellow('\nKey deleted.'));
63
+ }
64
+ }
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import fs from 'fs-extra';
2
21
  import path from 'node:path';
3
22
  import inquirer from 'inquirer';
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import fs from 'fs-extra';
2
21
  import path from 'path';
3
22
  import chalk from 'chalk';
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import fs from 'fs-extra';
2
21
  import path from 'path';
3
22
  import chalk from 'chalk';
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import fs from 'fs-extra';
2
21
  import path from 'node:path';
3
22
  import chalk from 'chalk';
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import fs from 'fs-extra';
2
21
  import path from 'path';
3
22
  import chalk from 'chalk';
@@ -13,6 +32,25 @@ const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
13
32
  const PYTHON_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
14
33
  const GENERAL_REGEX = /^[a-zA-Z][a-zA-Z0-9-_]*$/;
15
34
 
35
+
36
+ function execute(command, spinner, progressText) {
37
+ if (progressText) spinner.text = progressText;
38
+ try {
39
+
40
+ execSync(command, { stdio: 'pipe', encoding: 'utf-8' });
41
+ } catch (error) {
42
+ const logFile = path.join(process.cwd(), 'flowdev-debug.log');
43
+ const errorLog = `
44
+ COMMAND: ${command}
45
+ ERROR: ${error.message}
46
+ STDOUT: ${error.stdout}
47
+ STDERR: ${error.stderr}
48
+ `;
49
+ fs.writeFileSync(logFile, errorLog);
50
+ throw new Error(`Command failed. Check the log file for details: ${chalk.bold(logFile)}`);
51
+ }
52
+ }
53
+
16
54
  export async function generateCommand() {
17
55
  const answers = await inquirer.prompt([
18
56
  {
@@ -40,7 +78,7 @@ export async function generateCommand() {
40
78
  if (currentAnswers.type === 'django') {
41
79
  if (!PYTHON_REGEX.test(name)) return 'Use underscores (_) for Django projects.';
42
80
  } else {
43
- if (!GENERAL_REGEX.test(name)) return 'Invalid characters used.';
81
+ if (!GENERAL_REGEX.test(name)) return 'Invalid characters used (use alphanumeric, - or _).';
44
82
  }
45
83
  return true;
46
84
  }
@@ -53,7 +91,11 @@ export async function generateCommand() {
53
91
  name: 'appName',
54
92
  message: 'Initial app name:',
55
93
  default: 'core',
56
- validate: (input) => PYTHON_REGEX.test(input) || 'Invalid Python App name.'
94
+ validate: (input) => {
95
+ if (!PYTHON_REGEX.test(input)) return 'Invalid Python App name.';
96
+ if (input === answers.projectName) return 'App name cannot be the same as project name.';
97
+ return true;
98
+ }
57
99
  }]);
58
100
  answers.appName = djangoSub.appName;
59
101
  }
@@ -77,97 +119,79 @@ export async function generateCommand() {
77
119
  }
78
120
 
79
121
  await initGit(projectDir, spinner);
80
- spinner.succeed(chalk.green(`Project "${answers.projectName}" is ready!`));
122
+ spinner.succeed(chalk.green(`Project "${answers.projectName}" successfully generated.`));
81
123
  showSuccessTips(answers);
82
124
 
83
125
  } catch (error) {
84
- spinner.fail(chalk.red('Generation failed.'));
85
- console.error(chalk.red(`\nError: ${error.message}`));
126
+ spinner.fail(chalk.red('Installation encountered an error.'));
127
+ console.error(`\n${chalk.bgRed(' DEBUG ')} ${error.message}`);
86
128
  }
87
129
  }
88
130
 
131
+
132
+
89
133
  async function setupVite(dir, name, framework, withTailwind, spinner) {
90
- spinner.text = `Scaffolding ${framework} with Vite...`;
91
- execSync(`${npmCmd} create vite@latest "${name}" -- --template ${framework}`, { stdio: 'ignore' });
134
+ execute(`${npmCmd} create vite@latest "${name}" -- --template ${framework}`, spinner, `Scaffolding ${framework} with Vite...`);
92
135
 
93
136
  const originalDir = process.cwd();
94
137
  process.chdir(dir);
95
138
 
96
- spinner.text = 'Installing core dependencies...';
97
- execSync(`${npmCmd} install`, { stdio: 'ignore' });
98
-
139
+ execute(`${npmCmd} install`, spinner, 'Installing project dependencies...');
99
140
 
100
141
  const folders = ['components', 'services', 'utils', 'hooks', 'assets'];
101
142
  for (const f of folders) await fs.ensureDir(path.join(dir, 'src', f));
102
143
 
103
144
  if (withTailwind) {
104
- spinner.text = 'Configuring Tailwind CSS v3...';
105
-
106
-
107
- execSync(`${npmCmd} install -D tailwindcss@3 postcss@8 autoprefixer@10`, { stdio: 'ignore' });
145
+ execute(`${npmCmd} install -D tailwindcss@3 postcss@8 autoprefixer@10`, spinner, 'Installing Tailwind CSS...');
108
146
 
109
-
110
- const tailwindConfig = `/** @type {import('tailwindcss').Config} */
111
- export default {
112
- content: [
113
- "./index.html",
114
- "./src/**/*.{js,ts,jsx,tsx,vue}",
115
- ],
116
- theme: {
117
- extend: {},
118
- },
147
+ const tailwindConfig = `export default {
148
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx,vue}"],
149
+ theme: { extend: {} },
119
150
  plugins: [],
120
151
  }`;
121
152
  await fs.writeFile(path.join(dir, 'tailwind.config.js'), tailwindConfig);
153
+ await fs.writeFile(path.join(dir, 'postcss.config.js'), `export default { plugins: { tailwindcss: {}, autoprefixer: {} } }`);
122
154
 
123
-
124
- const postcssConfig = `export default {
125
- plugins: {
126
- tailwindcss: {},
127
- autoprefixer: {},
128
- },
129
- }`;
130
- await fs.writeFile(path.join(dir, 'postcss.config.js'), postcssConfig);
131
-
132
-
133
- const possibleCssFiles = ['index.css', 'style.css', 'App.css'];
134
- let targetCssFile = 'index.css';
135
-
136
- for (const file of possibleCssFiles) {
137
- if (await fs.pathExists(path.join(dir, 'src', file))) {
138
- targetCssFile = file;
139
- break;
140
- }
141
- }
142
-
143
- const cssPath = path.join(dir, 'src', targetCssFile);
155
+ const cssPath = path.join(dir, 'src', 'index.css');
144
156
  const tailwindDirectives = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n`;
145
-
146
- let currentCss = "";
147
- if (await fs.pathExists(cssPath)) {
148
- currentCss = await fs.readFile(cssPath, 'utf-8');
149
- }
157
+ const currentCss = (await fs.pathExists(cssPath)) ? await fs.readFile(cssPath, 'utf-8') : "";
150
158
  await fs.writeFile(cssPath, tailwindDirectives + currentCss);
151
159
  }
152
-
153
160
  process.chdir(originalDir);
154
161
  }
155
162
 
156
163
  async function setupDjango(dir, data, spinner) {
157
164
  const { projectName, appName } = data;
158
165
  const isWin = process.platform === 'win32';
166
+
159
167
  await fs.ensureDir(dir);
160
168
  const originalDir = process.cwd();
161
169
  process.chdir(dir);
170
+
162
171
  try {
163
- spinner.text = 'Setting up Django environment...';
164
- execSync(`${pythonCmd} -m venv venv`, { stdio: 'ignore' });
172
+ execute(`${pythonCmd} -m venv venv`, spinner, 'Creating Virtual Environment...');
173
+
165
174
  const venvPython = isWin ? path.join(dir, 'venv', 'Scripts', 'python.exe') : path.join(dir, 'venv', 'bin', 'python');
166
- execSync(`"${venvPython}" -m pip install django`, { stdio: 'ignore' });
167
- execSync(`"${venvPython}" -m django startproject config .`, { stdio: 'ignore' });
168
- execSync(`"${venvPython}" manage.py startapp ${appName}`, { stdio: 'ignore' });
175
+
176
+ execute(`"${venvPython}" -m pip install django`, spinner, 'Installing Django via pip...');
177
+ execute(`"${venvPython}" -m django startproject config .`, spinner, 'Initializing Django core...');
178
+ execute(`"${venvPython}" manage.py startapp ${appName}`, spinner, `Creating app: ${appName}...`);
179
+
180
+
181
+ const settingsPath = path.join(dir, 'config', 'settings.py');
182
+ let settings = await fs.readFile(settingsPath, 'utf-8');
183
+ settings = settings.replace("INSTALLED_APPS = [", `INSTALLED_APPS = [\n '${appName}',`);
184
+ await fs.writeFile(settingsPath, settings);
185
+
186
+ // Basic app configuration
169
187
  await fs.writeFile(path.join(dir, appName, 'urls.py'), `from django.urls import path\nfrom . import views\n\nurlpatterns = [ path('', views.index, name='index'), ]`);
170
188
  await fs.writeFile(path.join(dir, appName, 'views.py'), `from django.http import HttpResponse\n\ndef index(request):\n return HttpResponse("<h1>${projectName} is live!</h1>")`);
189
+
190
+ // Global URL routing
191
+ const projectUrlsPath = path.join(dir, 'config', 'urls.py');
192
+ const projectUrls = `from django.contrib import admin\nfrom django.urls import path, include\n\nurlpatterns = [\n path('admin/', admin.site.urls),\n path('', include('${appName}.urls')),\n]`;
193
+ await fs.writeFile(projectUrlsPath, projectUrls);
194
+
171
195
  } finally {
172
196
  process.chdir(originalDir);
173
197
  }
@@ -175,49 +199,54 @@ async function setupDjango(dir, data, spinner) {
175
199
 
176
200
  async function initGit(dir, spinner) {
177
201
  try {
178
- spinner.text = 'Initializing Git...';
202
+ spinner.text = 'Initializing Git repository...';
179
203
  const ignorePath = path.join(dir, '.gitignore');
180
204
  if (!(await fs.pathExists(ignorePath))) {
181
- await fs.writeFile(ignorePath, 'node_modules\n.env\ndist\nbuild\n__pycache__\n*.log\nvenv\n');
205
+ await fs.writeFile(ignorePath, 'node_modules\n.env\ndist\nbuild\n__pycache__\n*.log\nvenv\n*.pyc\n');
182
206
  }
183
207
  const originalDir = process.cwd();
184
208
  process.chdir(dir);
185
- execSync('git init', { stdio: 'ignore' });
186
- execSync('git add .', { stdio: 'ignore' });
187
- execSync('git commit -m "Initial commit by FlowDev "', { stdio: 'ignore' });
209
+ execute('git init', spinner);
210
+ execute('git add .', spinner);
211
+ execute('git commit -m "Initial commit by FlowDev"', spinner);
188
212
  process.chdir(originalDir);
189
213
  } catch (err) {
190
- spinner.warn(chalk.yellow('Git initialization skipped.'));
214
+ spinner.warn(chalk.yellow('Git initialization skipped. Please ensure Git is installed.'));
191
215
  }
192
216
  }
193
217
 
194
218
  async function setupAngular(dir, name, spinner) {
195
- spinner.text = 'Generating Angular Workspace...';
196
- execSync(`${npxCmd} --yes -p @angular/cli ng new "${name}" --defaults --skip-git`, { stdio: 'ignore' });
219
+ execute(`${npxCmd} --yes -p @angular/cli ng new "${name}" --defaults --skip-git`, spinner, 'Generating Angular Workspace...');
197
220
  }
198
221
 
199
222
  async function setupExpress(dir, name, spinner) {
200
- spinner.text = 'Setting up Express...';
201
223
  await fs.ensureDir(dir);
202
- const pkg = { name, version: '1.0.0', type: 'module', scripts: { start: 'node src/index.js' }, dependencies: { express: '^4.18.2', cors: '^2.8.5' }};
224
+ const pkg = {
225
+ name,
226
+ version: '1.0.0',
227
+ type: 'module',
228
+ scripts: { start: 'node src/index.js' },
229
+ dependencies: { express: '^4.18.2', cors: '^2.8.5' }
230
+ };
203
231
  await fs.writeJson(path.join(dir, 'package.json'), pkg, { spaces: 2 });
204
232
  await fs.ensureDir(path.join(dir, 'src'));
205
- await fs.writeFile(path.join(dir, 'src', 'index.js'), `import express from 'express';\nconst app = express();\napp.get('/', (req, res) => res.send('API OK'));\napp.listen(3000, () => console.log('Server on 3000'));`);
233
+ await fs.writeFile(path.join(dir, 'src', 'index.js'), `import express from 'express';\nconst app = express();\napp.get('/', (req, res) => res.send('API OK'));\napp.listen(3000, () => console.log('Server running on http://localhost:3000'));`);
234
+
206
235
  const originalDir = process.cwd();
207
236
  process.chdir(dir);
208
- execSync(`${npmCmd} install`, { stdio: 'ignore' });
237
+ execute(`${npmCmd} install`, spinner, 'Installing Express dependencies...');
209
238
  process.chdir(originalDir);
210
239
  }
211
240
 
212
241
  function showSuccessTips(data) {
213
- console.log(chalk.yellow('\n Tips :'));
214
- console.log(`${chalk.white('*')} cd ${chalk.bold(data.projectName)}`);
215
- if (data.type.includes('tailwind')) {
216
- console.log(`${chalk.green('*')} Tailwind CSS v3 successfully configured.`);
217
- console.log(`${chalk.white('*')} Run: ${chalk.bold('npm run dev')}`);
218
- } else if (data.type === 'django') {
219
- console.log(`${chalk.white('*')} Run: ${chalk.bold('python manage.py runserver')}`);
242
+ console.log(chalk.blue('\n Next Steps :'));
243
+ console.log(`${chalk.white('1.')} cd ${chalk.bold(data.projectName)}`);
244
+ if (data.type === 'django') {
245
+ console.log(`${chalk.white('2.')} ${process.platform === 'win32' ? 'venv\\Scripts\\activate' : 'source venv/bin/activate'}`);
246
+ console.log(`${chalk.white('3.')} python manage.py runserver`);
247
+ } else if (data.type === 'angular') {
248
+ console.log(`${chalk.white('2.')} ng serve`);
220
249
  } else {
221
- console.log(`${chalk.white('*')} Run: ${chalk.bold('npm start')}`);
250
+ console.log(`${chalk.white('2.')} npm ${data.type.includes('tailwind') ? 'run dev' : 'start'}`);
222
251
  }
223
252
  }
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import chalk from "chalk";
2
21
  import { execSync } from "child_process";
3
22
  import path from "path";
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import ora from 'ora';
2
21
  import chalk from 'chalk';
3
22
  import { analyzeProject } from '../../services/analyzer.js';
@@ -1,3 +1,22 @@
1
+ /**
2
+ * @fileoverview FlowDev - Intelligent CLI tool
3
+ * @module flowdev
4
+ * @version 1.0.5
5
+ * * @license MIT
6
+ * Copyright (c) 2026 FlowDev Technologies.
7
+ * * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ * * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ */
19
+
1
20
  import chalk from 'chalk';
2
21
  import { generateTree } from '../../services/file-system.js';
3
22