slicejs-cli 3.3.0 β†’ 3.4.1

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 (46) hide show
  1. package/AGENTS.md +247 -0
  2. package/LICENSE +21 -21
  3. package/client.js +663 -626
  4. package/commands/Print.js +163 -167
  5. package/commands/Validations.js +92 -103
  6. package/commands/build/build.js +40 -40
  7. package/commands/buildProduction/buildProduction.js +576 -579
  8. package/commands/bundle/bundle.js +234 -235
  9. package/commands/createComponent/VisualComponentTemplate.js +55 -55
  10. package/commands/createComponent/createComponent.js +124 -126
  11. package/commands/deleteComponent/deleteComponent.js +77 -77
  12. package/commands/doctor/doctor.js +366 -369
  13. package/commands/getComponent/getComponent.js +684 -747
  14. package/commands/init/init.js +269 -261
  15. package/commands/listComponents/listComponents.js +172 -175
  16. package/commands/startServer/startServer.js +261 -264
  17. package/commands/startServer/watchServer.js +79 -79
  18. package/commands/types/types.js +69 -27
  19. package/commands/utils/LocalCliDelegation.js +53 -53
  20. package/commands/utils/PathHelper.js +75 -68
  21. package/commands/utils/VersionChecker.js +167 -167
  22. package/commands/utils/bundling/BundleGenerator.js +2292 -2292
  23. package/commands/utils/bundling/DependencyAnalyzer.js +925 -933
  24. package/commands/utils/loadConfig.js +31 -0
  25. package/commands/utils/updateManager.js +452 -453
  26. package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +105 -105
  27. package/package.json +58 -46
  28. package/post.js +66 -65
  29. package/tests/bundle-generator.test.js +691 -708
  30. package/tests/bundle-v2-register-output.test.js +470 -470
  31. package/tests/client-launcher-contract.test.js +211 -211
  32. package/tests/client-update-flow-contract.test.js +272 -272
  33. package/tests/component-registry-parse.test.js +34 -0
  34. package/tests/dependency-analyzer.test.js +24 -24
  35. package/tests/fixtures/components.js +8 -0
  36. package/tests/fixtures/sliceConfig.json +74 -0
  37. package/tests/getcomponent.test.js +407 -0
  38. package/tests/helpers/setup.js +97 -0
  39. package/tests/init-command-contract.test.js +46 -0
  40. package/tests/local-cli-delegation.test.js +81 -79
  41. package/tests/path-helper.test.js +206 -0
  42. package/tests/types-breakage.test.js +491 -0
  43. package/tests/types-generator-errors.test.js +361 -0
  44. package/tests/types-generator.test.js +172 -184
  45. package/tests/update-manager-notifications.test.js +88 -88
  46. package/.github/workflows/docs-render-cicd.yml +0 -65
@@ -1,369 +1,366 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { createServer } from 'net';
5
- import chalk from 'chalk';
6
- import Table from 'cli-table3';
7
- import Print from '../Print.js';
8
- import inquirer from 'inquirer';
9
- import { exec } from 'child_process';
10
- import { promisify } from 'util';
11
- import { getProjectRoot, getSrcPath, getApiPath, getConfigPath, getPath } from '../utils/PathHelper.js';
12
- import updateManager from '../utils/updateManager.js';
13
-
14
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
-
16
- /**
17
- * Verifica la versiΓ³n de Node.js
18
- */
19
- async function checkNodeVersion() {
20
- const currentVersion = process.version;
21
- const majorVersion = parseInt(currentVersion.slice(1).split('.')[0]);
22
- const required = 20;
23
-
24
- if (majorVersion >= required) {
25
- return {
26
- pass: true,
27
- message: `Node.js version: ${currentVersion} (required: >= v${required})`
28
- };
29
- } else {
30
- return {
31
- pass: false,
32
- message: `Node.js version: ${currentVersion} (required: >= v${required})`,
33
- suggestion: `Update Node.js to v${required} or higher`
34
- };
35
- }
36
- }
37
-
38
- /**
39
- * Verifica la estructura de directorios
40
- */
41
- async function checkDirectoryStructure() {
42
- const srcPath = getSrcPath(import.meta.url);
43
- const apiPath = getApiPath(import.meta.url);
44
-
45
- const srcExists = await fs.pathExists(srcPath);
46
- const apiExists = await fs.pathExists(apiPath);
47
-
48
- if (srcExists && apiExists) {
49
- return {
50
- pass: true,
51
- message: 'Project structure (src/ and api/) exists'
52
- };
53
- } else {
54
- const missing = [];
55
- if (!srcExists) missing.push('src/');
56
- if (!apiExists) missing.push('api/');
57
-
58
- return {
59
- pass: false,
60
- message: `Missing directories: ${missing.join(', ')}`,
61
- suggestion: 'Run "slice init" to initialize your project'
62
- };
63
- }
64
- }
65
-
66
- /**
67
- * Verifica sliceConfig.json
68
- */
69
- async function checkConfig() {
70
- const configPath = getConfigPath(import.meta.url);
71
-
72
- if (!await fs.pathExists(configPath)) {
73
- return {
74
- pass: false,
75
- message: 'sliceConfig.json not found',
76
- suggestion: 'Run "slice init" to create configuration'
77
- };
78
- }
79
-
80
- try {
81
- const config = await fs.readJson(configPath);
82
-
83
- if (!config.paths || !config.paths.components) {
84
- return {
85
- pass: false,
86
- message: 'sliceConfig.json is invalid (missing paths.components)',
87
- suggestion: 'Check your configuration file'
88
- };
89
- }
90
-
91
- return {
92
- pass: true,
93
- message: 'sliceConfig.json is valid'
94
- };
95
- } catch (error) {
96
- return {
97
- pass: false,
98
- message: `sliceConfig.json is invalid JSON: ${error.message}`,
99
- suggestion: 'Fix JSON syntax errors in sliceConfig.json'
100
- };
101
- }
102
- }
103
-
104
- /**
105
- * Verifica disponibilidad del puerto
106
- */
107
- async function checkPort() {
108
- const configPath = getConfigPath(import.meta.url);
109
- let port = 3000;
110
-
111
- try {
112
- if (await fs.pathExists(configPath)) {
113
- const config = await fs.readJson(configPath);
114
- port = config.server?.port || 3000;
115
- }
116
- } catch { }
117
-
118
- return new Promise((resolve) => {
119
- const server = createServer();
120
-
121
- server.once('error', (err) => {
122
- if (err.code === 'EADDRINUSE') {
123
- resolve({
124
- warn: true,
125
- message: `Port ${port} is already in use`,
126
- suggestion: `Stop the process using port ${port} or use: slice dev -p <other-port>`
127
- });
128
- } else {
129
- resolve({
130
- pass: true,
131
- message: `Port ${port} is available`
132
- });
133
- }
134
- });
135
-
136
- server.once('listening', () => {
137
- server.close();
138
- resolve({
139
- pass: true,
140
- message: `Port ${port} is available`
141
- });
142
- });
143
-
144
- server.listen(port);
145
- });
146
- }
147
-
148
- /**
149
- * Verifica dependencias en package.json
150
- */
151
- async function checkDependencies() {
152
- const projectRoot = getProjectRoot(import.meta.url);
153
- const packagePath = path.join(projectRoot, 'package.json');
154
-
155
- if (!await fs.pathExists(packagePath)) {
156
- return {
157
- warn: true,
158
- message: 'package.json not found',
159
- suggestion: 'Run "npm init" to create package.json'
160
- };
161
- }
162
-
163
- try {
164
- const pkg = await fs.readJson(packagePath);
165
- const hasFrameworkDep = pkg.dependencies?.['slicejs-web-framework'] || pkg.devDependencies?.['slicejs-web-framework'];
166
- const frameworkNodePath = path.join(projectRoot, 'node_modules', 'slicejs-web-framework', 'package.json');
167
- const hasFrameworkNode = await fs.pathExists(frameworkNodePath);
168
- const hasFramework = !!(hasFrameworkDep || hasFrameworkNode);
169
-
170
- if (hasFramework) {
171
- return {
172
- pass: true,
173
- message: 'Required framework dependency is installed'
174
- };
175
- } else {
176
- const missing = ['slicejs-web-framework'];
177
-
178
- return {
179
- warn: true,
180
- message: `Missing dependencies: ${missing.join(', ')}`,
181
- suggestion: missing.includes('slicejs-web-framework')
182
- ? 'Run "npm install slicejs-web-framework@latest" in your project'
183
- : 'Run "npm install -D slicejs-cli@latest" in your project',
184
- missing
185
- };
186
- }
187
- } catch (error) {
188
- return {
189
- pass: false,
190
- message: `package.json is invalid: ${error.message}`,
191
- suggestion: 'Fix JSON syntax errors in package.json'
192
- };
193
- }
194
- }
195
-
196
- /**
197
- * Verifica integridad de componentes
198
- */
199
- async function checkComponents() {
200
- const configPath = getConfigPath(import.meta.url);
201
- const projectRoot = getProjectRoot(import.meta.url);
202
-
203
- if (!await fs.pathExists(configPath)) {
204
- return {
205
- warn: true,
206
- message: 'Cannot check components (no config)',
207
- suggestion: 'Run "slice init" first'
208
- };
209
- }
210
-
211
- try {
212
- const config = await fs.readJson(configPath);
213
- const componentPaths = config.paths?.components || {};
214
-
215
- let totalComponents = 0;
216
- let componentIssues = 0;
217
-
218
- for (const [category, { path: compPath }] of Object.entries(componentPaths)) {
219
- const fullPath = getSrcPath(import.meta.url, compPath);
220
-
221
- if (await fs.pathExists(fullPath)) {
222
- const items = await fs.readdir(fullPath);
223
-
224
- for (const item of items) {
225
- const itemPath = path.join(fullPath, item);
226
- const stat = await fs.stat(itemPath);
227
-
228
- if (stat.isDirectory()) {
229
- totalComponents++;
230
-
231
- // Verificar archivos JS
232
- const jsFile = path.join(itemPath, `${item}.js`);
233
- if (!await fs.pathExists(jsFile)) {
234
- componentIssues++;
235
- }
236
- }
237
- }
238
- }
239
- }
240
-
241
- if (componentIssues === 0) {
242
- return {
243
- pass: true,
244
- message: `${totalComponents} components checked, all OK`
245
- };
246
- } else {
247
- return {
248
- warn: true,
249
- message: `${componentIssues} component(s) have missing files`,
250
- suggestion: 'Check your component directories'
251
- };
252
- }
253
- } catch (error) {
254
- return {
255
- warn: true,
256
- message: `Cannot check components: ${error.message}`,
257
- suggestion: 'Verify your project structure'
258
- };
259
- }
260
- }
261
-
262
- /**
263
- * Comando principal de diagnΓ³stico
264
- */
265
- export default async function runDiagnostics() {
266
- Print.newLine();
267
- Print.title('πŸ” Running Slice.js Diagnostics...');
268
- Print.newLine();
269
-
270
- const checks = [
271
- { name: 'Node.js Version', fn: checkNodeVersion },
272
- { name: 'Project Structure', fn: checkDirectoryStructure },
273
- { name: 'Configuration', fn: checkConfig },
274
- { name: 'Port Availability', fn: checkPort },
275
- { name: 'Dependencies', fn: checkDependencies },
276
- { name: 'Components', fn: checkComponents }
277
- ];
278
-
279
- const results = [];
280
-
281
- for (const check of checks) {
282
- const result = await check.fn();
283
- results.push({ ...result, name: check.name });
284
- }
285
-
286
- // Crear tabla de resultados
287
- const table = new Table({
288
- head: [chalk.cyan.bold('Check'), chalk.cyan.bold('Status'), chalk.cyan.bold('Details')],
289
- colWidths: [25, 10, 55],
290
- style: {
291
- head: [],
292
- border: ['gray']
293
- },
294
- wordWrap: true
295
- });
296
-
297
- results.forEach(result => {
298
- let status;
299
- if (result.pass) {
300
- status = chalk.green('βœ… PASS');
301
- } else if (result.warn) {
302
- status = chalk.yellow('⚠️ WARN');
303
- } else {
304
- status = chalk.red('❌ FAIL');
305
- }
306
-
307
- const details = result.suggestion
308
- ? `${result.message}\n${chalk.gray('β†’ ' + result.suggestion)}`
309
- : result.message;
310
-
311
- table.push([result.name, status, details]);
312
- });
313
-
314
- console.log(table.toString());
315
-
316
- // Resumen
317
- const issues = results.filter(r => !r.pass && !r.warn).length;
318
- const warnings = results.filter(r => r.warn).length;
319
- const passed = results.filter(r => r.pass).length;
320
-
321
- Print.newLine();
322
- Print.separator();
323
-
324
- const depsResult = results.find(r => r.name === 'Dependencies');
325
- if (depsResult && depsResult.warn && Array.isArray(depsResult.missing) && depsResult.missing.length > 0) {
326
- const projectRoot = getProjectRoot(import.meta.url);
327
- const execAsync = promisify(exec);
328
- const { confirmInstall } = await inquirer.prompt([
329
- {
330
- type: 'confirm',
331
- name: 'confirmInstall',
332
- message: `Install missing dependencies in this project now? (${depsResult.missing.join(', ')})`,
333
- default: true
334
- }
335
- ]);
336
- if (confirmInstall) {
337
- for (const pkg of depsResult.missing) {
338
- try {
339
- const cmd = 'npm install slicejs-web-framework@latest';
340
- Print.info(`Installing ${pkg}...`);
341
- await execAsync(cmd, { cwd: projectRoot });
342
- Print.success(`${pkg} installed`);
343
- } catch (e) {
344
- Print.error(`Installing ${pkg}: ${e.message}`);
345
- }
346
- }
347
- }
348
- }
349
-
350
- if (issues === 0 && warnings === 0) {
351
- Print.success('All checks passed! πŸŽ‰');
352
- Print.info('Your Slice.js project is correctly configured');
353
- } else {
354
- console.log(chalk.bold('πŸ“Š Summary:'));
355
- console.log(chalk.green(` βœ… Passed: ${passed}`));
356
- if (warnings > 0) console.log(chalk.yellow(` ⚠️ Warnings: ${warnings}`));
357
- if (issues > 0) console.log(chalk.red(` ❌ Issues: ${issues}`));
358
-
359
- Print.newLine();
360
-
361
- if (issues > 0) {
362
- Print.warning('Fix the issues above to ensure proper functionality');
363
- } else {
364
- Print.info('Warnings are non-critical but should be addressed');
365
- }
366
- }
367
-
368
- Print.separator();
369
- }
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { createServer } from 'net';
4
+ import chalk from 'chalk';
5
+ import Table from 'cli-table3';
6
+ import Print from '../Print.js';
7
+ import inquirer from 'inquirer';
8
+ import { exec } from 'child_process';
9
+ import { promisify } from 'util';
10
+ import { getProjectRoot, getSrcPath, getApiPath, getConfigPath, getPath } from '../utils/PathHelper.js';
11
+ import updateManager from '../utils/updateManager.js';
12
+
13
+ /**
14
+ * Checks the Node.js version
15
+ */
16
+ async function checkNodeVersion() {
17
+ const currentVersion = process.version;
18
+ const majorVersion = parseInt(currentVersion.slice(1).split('.')[0]);
19
+ const required = 20;
20
+
21
+ if (majorVersion >= required) {
22
+ return {
23
+ pass: true,
24
+ message: `Node.js version: ${currentVersion} (required: >= v${required})`
25
+ };
26
+ } else {
27
+ return {
28
+ pass: false,
29
+ message: `Node.js version: ${currentVersion} (required: >= v${required})`,
30
+ suggestion: `Update Node.js to v${required} or higher`
31
+ };
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Checks the directory structure
37
+ */
38
+ async function checkDirectoryStructure() {
39
+ const srcPath = getSrcPath(import.meta.url);
40
+ const apiPath = getApiPath(import.meta.url);
41
+
42
+ const srcExists = await fs.pathExists(srcPath);
43
+ const apiExists = await fs.pathExists(apiPath);
44
+
45
+ if (srcExists && apiExists) {
46
+ return {
47
+ pass: true,
48
+ message: 'Project structure (src/ and api/) exists'
49
+ };
50
+ } else {
51
+ const missing = [];
52
+ if (!srcExists) missing.push('src/');
53
+ if (!apiExists) missing.push('api/');
54
+
55
+ return {
56
+ pass: false,
57
+ message: `Missing directories: ${missing.join(', ')}`,
58
+ suggestion: 'Run "slice init" to initialize your project'
59
+ };
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Checks sliceConfig.json
65
+ */
66
+ async function checkConfig() {
67
+ const configPath = getConfigPath(import.meta.url);
68
+
69
+ if (!await fs.pathExists(configPath)) {
70
+ return {
71
+ pass: false,
72
+ message: 'sliceConfig.json not found',
73
+ suggestion: 'Run "slice init" to create configuration'
74
+ };
75
+ }
76
+
77
+ try {
78
+ const config = await fs.readJson(configPath);
79
+
80
+ if (!config.paths || !config.paths.components) {
81
+ return {
82
+ pass: false,
83
+ message: 'sliceConfig.json is invalid (missing paths.components)',
84
+ suggestion: 'Check your configuration file'
85
+ };
86
+ }
87
+
88
+ return {
89
+ pass: true,
90
+ message: 'sliceConfig.json is valid'
91
+ };
92
+ } catch (error) {
93
+ return {
94
+ pass: false,
95
+ message: `sliceConfig.json is invalid JSON: ${error.message}`,
96
+ suggestion: 'Fix JSON syntax errors in sliceConfig.json'
97
+ };
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Checks port availability
103
+ */
104
+ async function checkPort() {
105
+ const configPath = getConfigPath(import.meta.url);
106
+ let port = 3000;
107
+
108
+ try {
109
+ if (await fs.pathExists(configPath)) {
110
+ const config = await fs.readJson(configPath);
111
+ port = config.server?.port || 3000;
112
+ }
113
+ } catch { /* config missing or unreadable β€” use default port */ }
114
+
115
+ return new Promise((resolve) => {
116
+ const server = createServer();
117
+
118
+ server.once('error', (err) => {
119
+ if (err.code === 'EADDRINUSE') {
120
+ resolve({
121
+ warn: true,
122
+ message: `Port ${port} is already in use`,
123
+ suggestion: `Stop the process using port ${port} or use: slice dev -p <other-port>`
124
+ });
125
+ } else {
126
+ resolve({
127
+ pass: true,
128
+ message: `Port ${port} is available`
129
+ });
130
+ }
131
+ });
132
+
133
+ server.once('listening', () => {
134
+ server.close();
135
+ resolve({
136
+ pass: true,
137
+ message: `Port ${port} is available`
138
+ });
139
+ });
140
+
141
+ server.listen(port);
142
+ });
143
+ }
144
+
145
+ /**
146
+ * Checks dependencies in package.json
147
+ */
148
+ async function checkDependencies() {
149
+ const projectRoot = getProjectRoot(import.meta.url);
150
+ const packagePath = getPath(import.meta.url, 'package.json');
151
+
152
+ if (!await fs.pathExists(packagePath)) {
153
+ return {
154
+ warn: true,
155
+ message: 'package.json not found',
156
+ suggestion: 'Run "npm init" to create package.json'
157
+ };
158
+ }
159
+
160
+ try {
161
+ const pkg = await fs.readJson(packagePath);
162
+ const hasFrameworkDep = pkg.dependencies?.['slicejs-web-framework'] || pkg.devDependencies?.['slicejs-web-framework'];
163
+ const frameworkNodePath = getPath(import.meta.url, 'node_modules', 'slicejs-web-framework', 'package.json');
164
+ const hasFrameworkNode = await fs.pathExists(frameworkNodePath);
165
+ const hasFramework = !!(hasFrameworkDep || hasFrameworkNode);
166
+
167
+ if (hasFramework) {
168
+ return {
169
+ pass: true,
170
+ message: 'Required framework dependency is installed'
171
+ };
172
+ } else {
173
+ const missing = ['slicejs-web-framework'];
174
+
175
+ return {
176
+ warn: true,
177
+ message: `Missing dependencies: ${missing.join(', ')}`,
178
+ suggestion: missing.includes('slicejs-web-framework')
179
+ ? 'Run "npm install slicejs-web-framework@latest" in your project'
180
+ : 'Run "npm install -D slicejs-cli@latest" in your project',
181
+ missing
182
+ };
183
+ }
184
+ } catch (error) {
185
+ return {
186
+ pass: false,
187
+ message: `package.json is invalid: ${error.message}`,
188
+ suggestion: 'Fix JSON syntax errors in package.json'
189
+ };
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Checks component integrity
195
+ */
196
+ async function checkComponents() {
197
+ const configPath = getConfigPath(import.meta.url);
198
+ const projectRoot = getProjectRoot(import.meta.url);
199
+
200
+ if (!await fs.pathExists(configPath)) {
201
+ return {
202
+ warn: true,
203
+ message: 'Cannot check components (no config)',
204
+ suggestion: 'Run "slice init" first'
205
+ };
206
+ }
207
+
208
+ try {
209
+ const config = await fs.readJson(configPath);
210
+ const componentPaths = config.paths?.components || {};
211
+
212
+ let totalComponents = 0;
213
+ let componentIssues = 0;
214
+
215
+ for (const [category, { path: compPath }] of Object.entries(componentPaths)) {
216
+ const fullPath = getSrcPath(import.meta.url, compPath);
217
+
218
+ if (await fs.pathExists(fullPath)) {
219
+ const items = await fs.readdir(fullPath);
220
+
221
+ for (const item of items) {
222
+ const itemPath = path.join(fullPath, item);
223
+ const stat = await fs.stat(itemPath);
224
+
225
+ if (stat.isDirectory()) {
226
+ totalComponents++;
227
+
228
+ // Check JS files
229
+ const jsFile = path.join(itemPath, `${item}.js`);
230
+ if (!await fs.pathExists(jsFile)) {
231
+ componentIssues++;
232
+ }
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ if (componentIssues === 0) {
239
+ return {
240
+ pass: true,
241
+ message: `${totalComponents} components checked, all OK`
242
+ };
243
+ } else {
244
+ return {
245
+ warn: true,
246
+ message: `${componentIssues} component(s) have missing files`,
247
+ suggestion: 'Check your component directories'
248
+ };
249
+ }
250
+ } catch (error) {
251
+ return {
252
+ warn: true,
253
+ message: `Cannot check components: ${error.message}`,
254
+ suggestion: 'Verify your project structure'
255
+ };
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Main diagnostic command
261
+ */
262
+ export default async function runDiagnostics() {
263
+ Print.newLine();
264
+ Print.title('πŸ” Running Slice.js Diagnostics...');
265
+ Print.newLine();
266
+
267
+ const checks = [
268
+ { name: 'Node.js Version', fn: checkNodeVersion },
269
+ { name: 'Project Structure', fn: checkDirectoryStructure },
270
+ { name: 'Configuration', fn: checkConfig },
271
+ { name: 'Port Availability', fn: checkPort },
272
+ { name: 'Dependencies', fn: checkDependencies },
273
+ { name: 'Components', fn: checkComponents }
274
+ ];
275
+
276
+ const results = [];
277
+
278
+ for (const check of checks) {
279
+ const result = await check.fn();
280
+ results.push({ ...result, name: check.name });
281
+ }
282
+
283
+ // Crear tabla de resultados
284
+ const table = new Table({
285
+ head: [chalk.cyan.bold('Check'), chalk.cyan.bold('Status'), chalk.cyan.bold('Details')],
286
+ colWidths: [25, 10, 55],
287
+ style: {
288
+ head: [],
289
+ border: ['gray']
290
+ },
291
+ wordWrap: true
292
+ });
293
+
294
+ results.forEach(result => {
295
+ let status;
296
+ if (result.pass) {
297
+ status = chalk.green('βœ… PASS');
298
+ } else if (result.warn) {
299
+ status = chalk.yellow('⚠️ WARN');
300
+ } else {
301
+ status = chalk.red('❌ FAIL');
302
+ }
303
+
304
+ const details = result.suggestion
305
+ ? `${result.message}\n${chalk.gray('β†’ ' + result.suggestion)}`
306
+ : result.message;
307
+
308
+ table.push([result.name, status, details]);
309
+ });
310
+
311
+ console.log(table.toString());
312
+
313
+ // Resumen
314
+ const issues = results.filter(r => !r.pass && !r.warn).length;
315
+ const warnings = results.filter(r => r.warn).length;
316
+ const passed = results.filter(r => r.pass).length;
317
+
318
+ Print.newLine();
319
+ Print.separator();
320
+
321
+ const depsResult = results.find(r => r.name === 'Dependencies');
322
+ if (depsResult && depsResult.warn && Array.isArray(depsResult.missing) && depsResult.missing.length > 0) {
323
+ const projectRoot = getProjectRoot(import.meta.url);
324
+ const execAsync = promisify(exec);
325
+ const { confirmInstall } = await inquirer.prompt([
326
+ {
327
+ type: 'confirm',
328
+ name: 'confirmInstall',
329
+ message: `Install missing dependencies in this project now? (${depsResult.missing.join(', ')})`,
330
+ default: true
331
+ }
332
+ ]);
333
+ if (confirmInstall) {
334
+ for (const pkg of depsResult.missing) {
335
+ try {
336
+ const cmd = 'npm install slicejs-web-framework@latest';
337
+ Print.info(`Installing ${pkg}...`);
338
+ await execAsync(cmd, { cwd: projectRoot });
339
+ Print.success(`${pkg} installed`);
340
+ } catch (e) {
341
+ Print.error(`Installing ${pkg}: ${e.message}`);
342
+ }
343
+ }
344
+ }
345
+ }
346
+
347
+ if (issues === 0 && warnings === 0) {
348
+ Print.success('All checks passed! πŸŽ‰');
349
+ Print.info('Your Slice.js project is correctly configured');
350
+ } else {
351
+ console.log(chalk.bold('πŸ“Š Summary:'));
352
+ console.log(chalk.green(` βœ… Passed: ${passed}`));
353
+ if (warnings > 0) console.log(chalk.yellow(` ⚠️ Warnings: ${warnings}`));
354
+ if (issues > 0) console.log(chalk.red(` ❌ Issues: ${issues}`));
355
+
356
+ Print.newLine();
357
+
358
+ if (issues > 0) {
359
+ Print.warning('Fix the issues above to ensure proper functionality');
360
+ } else {
361
+ Print.info('Warnings are non-critical but should be addressed');
362
+ }
363
+ }
364
+
365
+ Print.separator();
366
+ }