slicejs-cli 3.4.0 → 3.5.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.
Files changed (35) hide show
  1. package/AGENTS.md +247 -0
  2. package/client.js +63 -64
  3. package/commands/Print.js +11 -15
  4. package/commands/Validations.js +12 -23
  5. package/commands/buildProduction/buildProduction.js +23 -26
  6. package/commands/bundle/bundle.js +10 -11
  7. package/commands/createComponent/createComponent.js +14 -16
  8. package/commands/deleteComponent/deleteComponent.js +6 -6
  9. package/commands/doctor/doctor.js +11 -14
  10. package/commands/getComponent/getComponent.js +99 -162
  11. package/commands/init/init.js +77 -26
  12. package/commands/listComponents/listComponents.js +18 -21
  13. package/commands/startServer/startServer.js +21 -24
  14. package/commands/startServer/watchServer.js +7 -7
  15. package/commands/types/types.js +53 -18
  16. package/commands/utils/PathHelper.js +9 -2
  17. package/commands/utils/VersionChecker.js +3 -3
  18. package/commands/utils/bundling/DependencyAnalyzer.js +8 -16
  19. package/commands/utils/loadConfig.js +31 -0
  20. package/commands/utils/updateManager.js +3 -4
  21. package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +105 -105
  22. package/package.json +14 -2
  23. package/post.js +2 -2
  24. package/tests/bundle-generator.test.js +3 -20
  25. package/tests/component-registry-parse.test.js +34 -0
  26. package/tests/fixtures/components.js +8 -0
  27. package/tests/fixtures/sliceConfig.json +74 -0
  28. package/tests/getcomponent.test.js +407 -0
  29. package/tests/helpers/setup.js +97 -0
  30. package/tests/init-command-contract.test.js +46 -0
  31. package/tests/local-cli-delegation.test.js +7 -5
  32. package/tests/path-helper.test.js +206 -0
  33. package/tests/types-breakage.test.js +491 -0
  34. package/tests/types-generator-errors.test.js +361 -0
  35. package/tests/types-generator.test.js +172 -184
@@ -3,12 +3,10 @@ import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import ora from 'ora';
5
5
  import Print from '../Print.js';
6
- import { getProjectRoot, getApiPath, getSrcPath } from '../utils/PathHelper.js';
6
+ import { getProjectRoot, getApiPath, getSrcPath, getPath } from '../utils/PathHelper.js';
7
7
  import { execSync } from 'child_process';
8
8
 
9
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
-
11
- // Importar la clase ComponentRegistry del getComponent
9
+ // Import ComponentRegistry class from getComponent
12
10
  import { ComponentRegistry } from '../getComponent/getComponent.js';
13
11
 
14
12
  // Visual components used by the App Shell + MultiRoute starter project.
@@ -23,6 +21,15 @@ const STARTER_VISUAL_COMPONENTS = [
23
21
  'Route'
24
22
  ];
25
23
 
24
+ // Service components are now also pulled from the registry on init (instead of
25
+ // being vendored in the framework package), so Visual and Service share a single
26
+ // source of truth. Newcomers add more on demand with `slice get <Name>`.
27
+ const STARTER_SERVICE_COMPONENTS = [
28
+ 'FetchManager',
29
+ 'IndexedDbManager',
30
+ 'LocalStorageManager'
31
+ ];
32
+
26
33
  export default async function initializeProject(projectType) {
27
34
  try {
28
35
  const projectRoot = getProjectRoot(import.meta.url);
@@ -35,7 +42,7 @@ export default async function initializeProject(projectType) {
35
42
  try {
36
43
  const latest = execSync('npm view slicejs-web-framework version', { cwd: projectRoot }).toString().trim();
37
44
  latestVersion = latest;
38
- const installedPkgPath = path.join(projectRoot, 'node_modules', 'slicejs-web-framework', 'package.json');
45
+ const installedPkgPath = getPath(import.meta.url, 'node_modules', 'slicejs-web-framework', 'package.json');
39
46
  let installed = null;
40
47
  if (await fs.pathExists(installedPkgPath)) {
41
48
  const pkg = await fs.readJson(installedPkgPath);
@@ -44,9 +51,11 @@ export default async function initializeProject(projectType) {
44
51
  if (installed !== latest) {
45
52
  execSync(`npm install slicejs-web-framework@${latest} --save`, { cwd: projectRoot, stdio: 'inherit' });
46
53
  }
47
- sliceBaseDir = path.join(projectRoot, 'node_modules', 'slicejs-web-framework');
54
+ sliceBaseDir = getPath(import.meta.url, 'node_modules', 'slicejs-web-framework');
48
55
  fwSpinner.succeed(`slicejs-web-framework@${latest} ready`);
49
56
  } catch (err) {
57
+ // Fallback uses __dirname-style path because it looks for a local development copy,
58
+ // not a project-relative path — npm install failed, so we fall back to monorepo sibling.
50
59
  const fallback = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../slicejs-web-framework');
51
60
  if (await fs.pathExists(fallback)) {
52
61
  sliceBaseDir = fallback;
@@ -58,6 +67,8 @@ export default async function initializeProject(projectType) {
58
67
  }
59
68
  }
60
69
 
70
+ // These derive from sliceBaseDir (which comes from npm install or fallback),
71
+ // so they're already dynamic — no PathHelper needed.
61
72
  const apiDir = path.join(sliceBaseDir, 'api');
62
73
  const srcDir = path.join(sliceBaseDir, 'src');
63
74
 
@@ -69,7 +80,7 @@ export default async function initializeProject(projectType) {
69
80
  return;
70
81
  }
71
82
 
72
- // 1. COPIAR LA CARPETA API (mantener lógica original)
83
+ // 1. COPY API FOLDER (keep original logic)
73
84
  const apiSpinner = ora('Copying API structure...').start();
74
85
  try {
75
86
  if (!fs.existsSync(apiDir)) throw new Error(`API folder not found: ${apiDir}`);
@@ -81,15 +92,15 @@ export default async function initializeProject(projectType) {
81
92
  return;
82
93
  }
83
94
 
84
- // 2. CREAR ESTRUCTURA SRC BÁSICA (sin copiar componentes Visual)
95
+ // 2. CREATE BASIC SRC STRUCTURE (without copying Visual components)
85
96
  const srcSpinner = ora('Creating src structure...').start();
86
97
  try {
87
98
  if (!fs.existsSync(srcDir)) throw new Error(`src folder not found: ${srcDir}`);
88
99
 
89
- // Copiar solo los archivos base de src, excluyendo Components/Visual
100
+ // Copy only base src files, excluding Components/Visual
90
101
  await fs.ensureDir(destinationSrc);
91
102
 
92
- // Copiar archivos y carpetas de src excepto Components/Visual
103
+ // Copy src files and folders except Components/Visual
93
104
  const srcItems = await fs.readdir(srcDir);
94
105
 
95
106
  for (const item of srcItems) {
@@ -99,7 +110,7 @@ export default async function initializeProject(projectType) {
99
110
 
100
111
  if (stat.isDirectory()) {
101
112
  if (item === 'Components') {
102
- // Crear estructura de Components pero sin copiar Visual
113
+ // Create Components structure but without copying Visual or Service
103
114
  await fs.ensureDir(destItemPath);
104
115
 
105
116
  const componentItems = await fs.readdir(srcItemPath);
@@ -107,11 +118,11 @@ export default async function initializeProject(projectType) {
107
118
  const componentItemPath = path.join(srcItemPath, componentItem);
108
119
  const destComponentItemPath = path.join(destItemPath, componentItem);
109
120
 
110
- if (componentItem !== 'Visual') {
111
- // Copy Service and other component types
121
+ if (componentItem !== 'Visual' && componentItem !== 'Service') {
122
+ // Copy AppComponents and other template types from the framework
112
123
  await fs.copy(componentItemPath, destComponentItemPath, { recursive: true });
113
124
  } else {
114
- // Only create empty Visual directory
125
+ // Visual and Service are installed from the registry below
115
126
  await fs.ensureDir(destComponentItemPath);
116
127
  }
117
128
  }
@@ -132,7 +143,7 @@ export default async function initializeProject(projectType) {
132
143
  return;
133
144
  }
134
145
 
135
- // 3. DESCARGAR TODOS LOS COMPONENTES VISUAL DESDE EL REPOSITORIO OFICIAL
146
+ // 3. DOWNLOAD ALL VISUAL COMPONENTS FROM OFFICIAL REPOSITORY
136
147
  const componentsSpinner = ora('Loading component registry...').start();
137
148
  try {
138
149
  const registry = new ComponentRegistry();
@@ -148,7 +159,7 @@ export default async function initializeProject(projectType) {
148
159
  const results = await registry.installMultipleComponents(
149
160
  allVisualComponents,
150
161
  'Visual',
151
- true // force = true para instalación inicial
162
+ true // force = true for initial installation
152
163
  );
153
164
 
154
165
  const successful = results.filter(r => r.success).length;
@@ -174,11 +185,47 @@ export default async function initializeProject(projectType) {
174
185
  Print.info('You can add them later using "slice get <component-name>"');
175
186
  }
176
187
 
177
- // 4. CONFIGURAR SCRIPTS EN package.json DEL PROYECTO
188
+ // 3b. DOWNLOAD STARTER SERVICE COMPONENTS FROM OFFICIAL REPOSITORY
189
+ const serviceSpinner = ora('Installing starter Service components...').start();
190
+ try {
191
+ const registry = new ComponentRegistry();
192
+ await registry.loadRegistry();
193
+
194
+ if (STARTER_SERVICE_COMPONENTS.length > 0) {
195
+ Print.info(`Installing ${STARTER_SERVICE_COMPONENTS.length} starter Service components: ${STARTER_SERVICE_COMPONENTS.join(', ')}`);
196
+ serviceSpinner.text = `Installing ${STARTER_SERVICE_COMPONENTS.length} starter Service components...`;
197
+
198
+ const results = await registry.installMultipleComponents(
199
+ STARTER_SERVICE_COMPONENTS,
200
+ 'Service',
201
+ true // force = true for initial installation
202
+ );
203
+
204
+ const successful = results.filter(r => r.success).length;
205
+ const failed = results.filter(r => !r.success).length;
206
+
207
+ if (successful > 0 && failed === 0) {
208
+ serviceSpinner.succeed(`All ${successful} Service components installed successfully`);
209
+ } else if (successful > 0) {
210
+ serviceSpinner.warn(`${successful} Service components installed, ${failed} failed`);
211
+ Print.info('You can install failed components later using "slice get <component-name>"');
212
+ } else {
213
+ serviceSpinner.fail('Failed to install Service components');
214
+ }
215
+ } else {
216
+ serviceSpinner.succeed('No starter Service components to install');
217
+ }
218
+ } catch (error) {
219
+ serviceSpinner.fail('Could not download Service components from official repository');
220
+ Print.error(`Repository error: ${error.message}`);
221
+ Print.info('You can add them later using "slice get <component-name>"');
222
+ }
223
+
224
+ // 4. CONFIGURE SCRIPTS IN PROJECT package.json
178
225
  const pkgSpinner = ora('Configuring npm scripts...').start();
179
226
  try {
180
227
  const projectRoot = getProjectRoot(import.meta.url);
181
- const pkgPath = path.join(projectRoot, 'package.json');
228
+ const pkgPath = getPath(import.meta.url, 'package.json');
182
229
 
183
230
  let pkg;
184
231
  if (await fs.pathExists(pkgPath)) {
@@ -200,7 +247,7 @@ export default async function initializeProject(projectType) {
200
247
  pkg.scripts['dev'] = 'slice dev';
201
248
  pkg.scripts['start'] = 'slice start';
202
249
 
203
- // Gestión de componentes
250
+ // Component management
204
251
  pkg.scripts['component:create'] = 'slice component create';
205
252
  pkg.scripts['component:list'] = 'slice component list';
206
253
  pkg.scripts['component:delete'] = 'slice component delete';
@@ -215,7 +262,7 @@ export default async function initializeProject(projectType) {
215
262
  pkg.scripts['slice:update'] = 'slice update';
216
263
  pkg.scripts['slice:types'] = 'slice types generate';
217
264
 
218
- // Legacy (compatibilidad)
265
+ // Legacy (compatibility)
219
266
  pkg.scripts['slice:init'] = 'slice init';
220
267
  pkg.scripts['slice:start'] = 'slice start';
221
268
  pkg.scripts['slice:dev'] = 'slice dev';
@@ -227,7 +274,7 @@ export default async function initializeProject(projectType) {
227
274
  pkg.scripts['slice:sync'] = 'slice sync';
228
275
  pkg.scripts['run'] = 'slice dev';
229
276
 
230
- // Configuración de módulo
277
+ // Module configuration
231
278
  pkg.type = 'module';
232
279
  pkg.engines = pkg.engines || { node: '>=20.0.0' };
233
280
 
@@ -239,7 +286,7 @@ export default async function initializeProject(projectType) {
239
286
  await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2), 'utf8');
240
287
  pkgSpinner.succeed('npm scripts configured successfully');
241
288
 
242
- console.log('\n🎯 New recommended commands:');
289
+ Print.title('New recommended commands:');
243
290
  console.log(' npm run dev - Start development server');
244
291
  console.log(' npm run get - Install components');
245
292
  console.log(' npm run browse - Browse components');
@@ -248,9 +295,11 @@ export default async function initializeProject(projectType) {
248
295
  Print.error(error.message);
249
296
  }
250
297
 
251
- Print.success('Project initialized successfully.');
298
+ const projectName = path.basename(process.cwd());
299
+ Print.success(`Project initialized successfully in "${projectName}/"`);
252
300
  Print.newLine();
253
- Print.info('Next steps:');
301
+ Print.title('Next steps:');
302
+ console.log(` cd ${projectName}`);
254
303
  console.log(' slice browse - View available components');
255
304
  console.log(' slice get Button - Install specific components');
256
305
  console.log(' slice sync - Update all components to latest versions');
@@ -260,6 +309,8 @@ export default async function initializeProject(projectType) {
260
309
  }
261
310
  }
262
311
 
263
- // NOTE: `slice init` now installs only STARTER_VISUAL_COMPONENTS (see top of file).
312
+ // NOTE: `slice init` installs only STARTER_VISUAL_COMPONENTS and
313
+ // STARTER_SERVICE_COMPONENTS (see top of file); both Visual and Service are pulled
314
+ // from the registry rather than vendored in the framework package.
264
315
  // To install every registry component instead, iterate
265
- // `Object.keys(registry.getAvailableComponents('Visual'))`.
316
+ // `Object.keys(registry.getAvailableComponents('Visual'))` (and likewise 'Service').
@@ -1,16 +1,13 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { fileURLToPath } from 'url';
4
3
  import Table from 'cli-table3';
5
4
  import chalk from 'chalk';
6
5
  import Print from '../Print.js';
7
6
  import { getSrcPath, getComponentsJsPath, getConfigPath } from '../utils/PathHelper.js';
8
7
 
9
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
-
11
8
  /**
12
- * Carga la configuración desde sliceConfig.json
13
- * @returns {object} - Objeto de configuración
9
+ * Loads configuration from sliceConfig.json
10
+ * @returns {object} - Configuration object
14
11
  */
15
12
  const loadConfig = () => {
16
13
  try {
@@ -30,9 +27,9 @@ const loadConfig = () => {
30
27
  };
31
28
 
32
29
  /**
33
- * Lista los archivos en una carpeta dada, filtrando solo los archivos .js
34
- * @param {string} folderPath - Ruta de la carpeta a leer
35
- * @returns {string[]} - Lista de archivos encontrados
30
+ * Lists files in a given folder, filtering only .js files
31
+ * @param {string} folderPath - Path of the folder to read
32
+ * @returns {string[]} - List of found files
36
33
  */
37
34
  const listComponents = (folderPath) => {
38
35
  try {
@@ -48,7 +45,7 @@ const listComponents = (folderPath) => {
48
45
  };
49
46
 
50
47
  /**
51
- * Cuenta archivos en un directorio de componente
48
+ * Counts files in a component directory
52
49
  */
53
50
  const countComponentFiles = (componentPath) => {
54
51
  try {
@@ -61,14 +58,14 @@ const countComponentFiles = (componentPath) => {
61
58
  };
62
59
 
63
60
  /**
64
- * Obtiene los componentes dinámicamente desde sliceConfig.json
65
- * @returns {object} - Mapeo de componentes con su categoría
61
+ * Gets components dynamically from sliceConfig.json
62
+ * @returns {object} - Component mapping with their category
66
63
  */
67
64
  const getComponents = () => {
68
65
  const config = loadConfig();
69
66
  if (!config) return {};
70
67
 
71
- const folderSuffix = 'src'; // Siempre usar 'src' para desarrollo
68
+ const folderSuffix = 'src'; // Always use 'src' for development
72
69
  const componentPaths = config.paths?.components || {};
73
70
  let allComponents = new Map();
74
71
 
@@ -91,7 +88,7 @@ const getComponents = () => {
91
88
 
92
89
  function listComponentsReal() {
93
90
  try {
94
- // Obtener componentes dinámicamente
91
+ // Get components dynamically
95
92
  const components = getComponents();
96
93
 
97
94
  if (Object.keys(components).length === 0) {
@@ -100,7 +97,7 @@ function listComponentsReal() {
100
97
  return;
101
98
  }
102
99
 
103
- // Crear tabla con cli-table3
100
+ // Create table with cli-table3
104
101
  const table = new Table({
105
102
  head: [
106
103
  chalk.cyan.bold('Component'),
@@ -114,7 +111,7 @@ function listComponentsReal() {
114
111
  }
115
112
  });
116
113
 
117
- // Agrupar por categoría para mejor visualización
114
+ // Group by category for better visualization
118
115
  const byCategory = {};
119
116
  Object.entries(components).forEach(([name, data]) => {
120
117
  if (!byCategory[data.category]) {
@@ -123,18 +120,18 @@ function listComponentsReal() {
123
120
  byCategory[data.category].push({ name, files: data.files });
124
121
  });
125
122
 
126
- // Agregar filas a la tabla
123
+ // Add rows to the table
127
124
  Object.entries(byCategory).forEach(([category, comps]) => {
128
125
  comps.forEach((comp, index) => {
129
126
  if (index === 0) {
130
- // Primera fila de la categoría
127
+ // First row of the category
131
128
  table.push([
132
129
  chalk.bold(comp.name),
133
130
  chalk.yellow(category),
134
131
  comp.files.toString()
135
132
  ]);
136
133
  } else {
137
- // Resto de componentes en la categoría
134
+ // Rest of components in the category
138
135
  table.push([
139
136
  chalk.bold(comp.name),
140
137
  chalk.gray('″'), // Ditto mark
@@ -151,16 +148,16 @@ function listComponentsReal() {
151
148
  Print.newLine();
152
149
  Print.info(`Total: ${Object.keys(components).length} component${Object.keys(components).length !== 1 ? 's' : ''} found`);
153
150
 
154
- // Ruta donde se generará components.js
151
+ // Path where components.js will be generated
155
152
  const outputPath = getComponentsJsPath(import.meta.url);
156
153
 
157
- // Asegurar que el directorio existe
154
+ // Ensure the directory exists
158
155
  const outputDir = path.dirname(outputPath);
159
156
  if (!fs.existsSync(outputDir)) {
160
157
  fs.mkdirSync(outputDir, { recursive: true });
161
158
  }
162
159
 
163
- // Generar archivo components.js con los componentes detectados
160
+ // Generate components.js file with detected components
164
161
  const componentsForExport = Object.fromEntries(
165
162
  Object.entries(components).map(([name, data]) => [name, data.category])
166
163
  );
@@ -1,19 +1,16 @@
1
- // commands/startServer/startServer.js - MEJORADO CON VALIDACIÓN Y FEEDBACK
1
+ // commands/startServer/startServer.js - IMPROVED WITH VALIDATION AND FEEDBACK
2
2
 
3
3
  import fs from 'fs-extra';
4
4
  import path from 'path';
5
- import { fileURLToPath } from 'url';
6
5
  import { spawn } from 'child_process';
7
6
  import { createServer } from 'net';
8
7
  import setupWatcher, { stopWatcher } from './watchServer.js';
9
8
  import Print from '../Print.js';
10
- import { getConfigPath, getApiPath, getSrcPath, getDistPath } from '../utils/PathHelper.js';
9
+ import { getConfigPath, getApiPath, getSrcPath, getDistPath, getPath } from '../utils/PathHelper.js';
11
10
  import build from '../build/build.js';
12
11
 
13
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
-
15
12
  /**
16
- * Carga la configuración desde sliceConfig.json
13
+ * Loads configuration from sliceConfig.json
17
14
  */
18
15
  const loadConfig = () => {
19
16
  try {
@@ -27,7 +24,7 @@ const loadConfig = () => {
27
24
  };
28
25
 
29
26
  /**
30
- * Verifica si un puerto está disponible
27
+ * Checks if a port is available
31
28
  */
32
29
  async function isPortAvailable(port) {
33
30
  return new Promise((resolve) => {
@@ -51,16 +48,16 @@ async function isPortAvailable(port) {
51
48
  }
52
49
 
53
50
  /**
54
- * Verifica si existe un build de producción
51
+ * Checks if a production build exists
55
52
  */
56
53
  async function checkProductionBuild() {
57
54
  const distDir = getDistPath(import.meta.url);
58
- const bundleConfigPath = path.join(distDir, 'bundles', 'bundle.config.json');
55
+ const bundleConfigPath = getPath(import.meta.url, 'dist', 'bundles', 'bundle.config.json');
59
56
  return (await fs.pathExists(distDir)) && (await fs.pathExists(bundleConfigPath));
60
57
  }
61
58
 
62
59
  /**
63
- * Verifica si existe la estructura de desarrollo
60
+ * Checks if the development structure exists
64
61
  */
65
62
  async function checkDevelopmentStructure() {
66
63
  const srcDir = getSrcPath(import.meta.url);
@@ -70,13 +67,13 @@ async function checkDevelopmentStructure() {
70
67
  }
71
68
 
72
69
  /**
73
- * Inicia el servidor Node.js con argumentos y mejor feedback
70
+ * Starts the Node.js server with arguments and improved feedback
74
71
  */
75
72
  function startNodeServer(port, mode) {
76
73
  return new Promise((resolve, reject) => {
77
74
  const apiIndexPath = getApiPath(import.meta.url, 'index.js');
78
75
 
79
- // Verificar que el archivo existe
76
+ // Verify the file exists
80
77
  if (!fs.existsSync(apiIndexPath)) {
81
78
  reject(new Error(`Server file not found: ${apiIndexPath}`));
82
79
  return;
@@ -84,7 +81,7 @@ function startNodeServer(port, mode) {
84
81
 
85
82
  Print.serverStatus('starting', 'Starting server...');
86
83
 
87
- // Construir argumentos basados en el modo
84
+ // Build arguments based on mode
88
85
  const args = [apiIndexPath];
89
86
  if (mode === 'production') {
90
87
  args.push('--production');
@@ -109,12 +106,12 @@ function startNodeServer(port, mode) {
109
106
  let serverStarted = false;
110
107
  let outputBuffer = '';
111
108
 
112
- // Capturar la salida para detectar cuando el servidor está listo
109
+ // Capture output to detect when the server is ready
113
110
  serverProcess.stdout.on('data', (data) => {
114
111
  const output = data.toString();
115
112
  outputBuffer += output;
116
113
 
117
- // Detectar mensajes comunes que indican que el servidor ha iniciado
114
+ // Detect common messages indicating the server has started
118
115
  if (!serverStarted && (
119
116
  output.includes('Server running') ||
120
117
  output.includes('listening on') ||
@@ -125,7 +122,7 @@ function startNodeServer(port, mode) {
125
122
  Print.serverReady(port);
126
123
  }
127
124
 
128
- // Mostrar la salida del servidor
125
+ // Display server output
129
126
  process.stdout.write(output);
130
127
  });
131
128
 
@@ -161,7 +158,7 @@ function startNodeServer(port, mode) {
161
158
  serverProcess.kill('SIGTERM');
162
159
  });
163
160
 
164
- // Si después de 3 segundos no detectamos inicio, asumimos que está listo
161
+ // If after 3 seconds we haven't detected startup, assume it's ready
165
162
  setTimeout(() => {
166
163
  if (!serverStarted) {
167
164
  serverStarted = true;
@@ -173,7 +170,7 @@ function startNodeServer(port, mode) {
173
170
  }
174
171
 
175
172
  /**
176
- * Función principal para iniciar servidor
173
+ * Main function to start the server
177
174
  */
178
175
  export default async function startServer(options = {}) {
179
176
  const config = loadConfig();
@@ -185,7 +182,7 @@ export default async function startServer(options = {}) {
185
182
  Print.title(`🚀 Starting Slice.js ${mode} server...`);
186
183
  Print.newLine();
187
184
 
188
- // Verificar estructura del proyecto
185
+ // Verify project structure
189
186
  if (!await checkDevelopmentStructure()) {
190
187
  throw new Error('Project structure not found. Run "slice init" first.');
191
188
  }
@@ -204,7 +201,7 @@ export default async function startServer(options = {}) {
204
201
  Print.newLine();
205
202
 
206
203
  if (mode === 'production') {
207
- // Verificar que existe build de producción
204
+ // Verify production build exists
208
205
  if (!await checkProductionBuild()) {
209
206
  Print.info('No production build found. Running "slice build"...');
210
207
  const success = await build({});
@@ -219,10 +216,10 @@ export default async function startServer(options = {}) {
219
216
 
220
217
  Print.newLine();
221
218
 
222
- // Iniciar el servidor con argumentos
219
+ // Start the server with arguments
223
220
  let serverProcess = await startNodeServer(actualPort, mode);
224
221
 
225
- // Configurar watch mode si está habilitado
222
+ // Configure watch mode if enabled
226
223
  if (watch) {
227
224
  Print.newLine();
228
225
  const watcher = setupWatcher(serverProcess, async (changedPath) => {
@@ -253,12 +250,12 @@ export default async function startServer(options = {}) {
253
250
 
254
251
  } catch (error) {
255
252
  Print.newLine();
256
- Print.error(error.message);
253
+ Print.error(`Failed to start development server: ${error.message}`);
257
254
  throw error;
258
255
  }
259
256
  }
260
257
 
261
258
  /**
262
- * Funciones de utilidad exportadas
259
+ * Exported utility functions
263
260
  */
264
261
  export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
@@ -3,9 +3,9 @@ import chalk from 'chalk';
3
3
  import Print from '../Print.js';
4
4
 
5
5
  /**
6
- * Configura el watcher para archivos del proyecto
7
- * @param {ChildProcess} serverProcess - Proceso del servidor
8
- * @returns {FSWatcher} - Watcher de chokidar
6
+ * Configures the watcher for project files
7
+ * @param {ChildProcess} serverProcess - Server process
8
+ * @returns {FSWatcher} - Chokidar watcher
9
9
  */
10
10
  export default function setupWatcher(serverProcess, onRestart) {
11
11
  Print.info('Watch mode enabled - monitoring file changes...');
@@ -13,7 +13,7 @@ export default function setupWatcher(serverProcess, onRestart) {
13
13
 
14
14
  const watcher = chokidar.watch(['src/**/*', 'api/**/*'], {
15
15
  ignored: [
16
- /(^|[\/\\])\../, // archivos ocultos
16
+ /(^|[\/\\])\../, // hidden files
17
17
  '**/node_modules/**',
18
18
  '**/dist/**',
19
19
  '**/bundles/**',
@@ -31,7 +31,7 @@ export default function setupWatcher(serverProcess, onRestart) {
31
31
 
32
32
  watcher
33
33
  .on('change', (path) => {
34
- // Debounce para evitar múltiples reloads
34
+ // Debounce to avoid multiple reloads
35
35
  clearTimeout(reloadTimeout);
36
36
  reloadTimeout = setTimeout(() => {
37
37
  if(onRestart) {
@@ -68,8 +68,8 @@ export default function setupWatcher(serverProcess, onRestart) {
68
68
  }
69
69
 
70
70
  /**
71
- * Detiene el watcher de forma segura
72
- * @param {FSWatcher} watcher - Watcher a detener
71
+ * Stops the watcher safely
72
+ * @param {FSWatcher} watcher - Watcher to stop
73
73
  */
74
74
  export function stopWatcher(watcher) {
75
75
  if (watcher) {