slicejs-cli 2.6.0 → 2.7.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.
package/client.js CHANGED
@@ -8,11 +8,12 @@ import deleteComponent from "./commands/deleteComponent/deleteComponent.js";
8
8
  import getComponent, { listComponents as listRemoteComponents, syncComponents } from "./commands/getComponent/getComponent.js";
9
9
  import startServer from "./commands/startServer/startServer.js";
10
10
  import runDiagnostics from "./commands/doctor/doctor.js";
11
- import versionChecker from "./commands/utils/versionChecker.js";
11
+ import versionChecker from "./commands/utils/VersionChecker.js";
12
12
  import updateManager from "./commands/utils/updateManager.js";
13
13
  import fs from "fs";
14
14
  import path from "path";
15
15
  import { fileURLToPath } from "url";
16
+ import { getConfigPath } from "./commands/utils/PathHelper.js";
16
17
  import validations from "./commands/Validations.js";
17
18
  import Print from "./commands/Print.js";
18
19
 
@@ -20,7 +21,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
20
21
 
21
22
  const loadConfig = () => {
22
23
  try {
23
- const configPath = path.join(__dirname, "../../src/sliceConfig.json");
24
+ const configPath = getConfigPath(import.meta.url);
24
25
  const rawData = fs.readFileSync(configPath, "utf-8");
25
26
  return JSON.parse(rawData);
26
27
  } catch (error) {
@@ -37,10 +38,13 @@ const getCategories = () => {
37
38
  // Function to run version check for all commands
38
39
  async function runWithVersionCheck(commandFunction, ...args) {
39
40
  try {
40
- // Run the command first
41
+ const updateInfo = await updateManager.checkForUpdates();
42
+ if (updateInfo && updateInfo.hasUpdates) {
43
+ await updateManager.checkAndPromptUpdates({});
44
+ }
45
+
41
46
  const result = await commandFunction(...args);
42
47
 
43
- // Then check for updates (non-blocking)
44
48
  setTimeout(() => {
45
49
  versionChecker.checkForUpdates(false);
46
50
  }, 100);
@@ -54,7 +58,7 @@ async function runWithVersionCheck(commandFunction, ...args) {
54
58
 
55
59
  const sliceClient = program;
56
60
 
57
- sliceClient.version("2.5.0").description("CLI for managing Slice.js framework components");
61
+ sliceClient.version("2.6.1").description("CLI for managing Slice.js framework components");
58
62
 
59
63
  // INIT COMMAND
60
64
  sliceClient
@@ -337,6 +341,17 @@ sliceClient
337
341
  });
338
342
  });
339
343
 
344
+ // LIST COMMAND - Quick shortcut for listing local components
345
+ sliceClient
346
+ .command("list")
347
+ .description("Quick list all local components (alias for component list)")
348
+ .action(async () => {
349
+ await runWithVersionCheck(() => {
350
+ listComponents();
351
+ return Promise.resolve();
352
+ });
353
+ });
354
+
340
355
  // UPDATE COMMAND
341
356
  sliceClient
342
357
  .command("update")
@@ -379,11 +394,12 @@ Common Usage Examples:
379
394
  slice browse - Browse all available components
380
395
  slice sync - Update local components to latest versions
381
396
  slice component create - Create new local component
397
+ slice list - List all local components
382
398
  slice doctor - Run project diagnostics
383
399
 
384
400
  Command Categories:
385
401
  • init, dev, start - Project lifecycle (development only)
386
- • get, browse, sync - Quick registry shortcuts
402
+ • get, browse, sync, list - Quick shortcuts
387
403
  • component <cmd> - Local component management
388
404
  • registry <cmd> - Official repository operations
389
405
  • version, update, doctor - Maintenance commands
@@ -419,4 +435,4 @@ const helpCommand = sliceClient.command("help").description("Display help inform
419
435
  sliceClient.outputHelp();
420
436
  });
421
437
 
422
- program.parse();
438
+ program.parse();
@@ -1,14 +1,28 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { getConfigPath, getComponentsJsPath } from './utils/PathHelper.js';
4
5
 
5
6
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
7
 
7
8
  class Validations {
8
9
  constructor() {
9
- this.config = this.loadConfig(); // Cargamos la configuración solo una vez al instanciar
10
- this.categories = this.config?.paths?.components;
10
+ this._config = null;
11
+ this._categories = null;
12
+ }
13
+
14
+ _ensureConfig() {
15
+ if (!this._config) {
16
+ this._config = this.loadConfig();
17
+ if (this._config) {
18
+ this._categories = this._config.paths?.components;
19
+ }
20
+ }
21
+ }
11
22
 
23
+ get config() {
24
+ this._ensureConfig();
25
+ return this._config;
12
26
  }
13
27
 
14
28
  isValidComponentName(componentName) {
@@ -19,36 +33,40 @@ class Validations {
19
33
 
20
34
  loadConfig() {
21
35
  try {
22
- const configPath = path.join(__dirname, '../../../src/sliceConfig.json');
36
+ const configPath = getConfigPath(import.meta.url);
23
37
  if (!fs.existsSync(configPath)) {
24
- console.error('\x1b[31m', '❌ Error: sliceConfig.json not found', '\x1b[0m');
25
- console.log('\x1b[36m', 'ℹ️ Info: Run "slice init" to initialize your project', '\x1b[0m');
38
+ // Return null silently - let commands handle missing config if needed
26
39
  return null;
27
- }
40
+ }
28
41
  const rawData = fs.readFileSync(configPath, 'utf-8');
29
-
42
+
30
43
  return JSON.parse(rawData);
31
44
  } catch (error) {
32
45
  console.error('\x1b[31m', `❌ Error loading configuration: ${error.message}`, '\x1b[0m');
33
- console.log('\x1b[36m', 'ℹ️ Info: Check that sliceConfig.json is valid JSON', '\x1b[0m');
34
46
  return null;
35
47
  }
36
48
  }
37
49
 
38
50
  getCategories() {
39
- return this.categories; // Usamos las categorías cargadas en el constructor
51
+ this._ensureConfig();
52
+ return this._categories;
40
53
  }
41
54
 
42
55
  getCategoryPath(category) {
43
- return this.categories[category].path;
56
+ this._ensureConfig();
57
+ return this._categories && this._categories[category] ? this._categories[category].path : null;
44
58
  }
45
59
 
46
- getCategoryType(category){
47
- return this.categories[category].type;
60
+ getCategoryType(category) {
61
+ this._ensureConfig();
62
+ return this._categories && this._categories[category] ? this._categories[category].type : null;
48
63
  }
49
64
 
50
65
  isValidCategory(category) {
51
- const availableCategories = Object.keys(this.categories).map(cat => cat.toLowerCase());
66
+ this._ensureConfig();
67
+ if (!this._categories) return { isValid: false, category: null };
68
+
69
+ const availableCategories = Object.keys(this._categories).map(cat => cat.toLowerCase());
52
70
 
53
71
  if (availableCategories.includes(category.toLowerCase())) {
54
72
  return { isValid: true, category };
@@ -59,17 +77,17 @@ class Validations {
59
77
 
60
78
  componentExists(componentName) {
61
79
  try {
62
- const componentFilePath = path.join(__dirname, '../../../src/Components/components.js');
63
-
80
+ const componentFilePath = getComponentsJsPath(import.meta.url);
81
+
64
82
  if (!fs.existsSync(componentFilePath)) {
65
83
  console.error('\x1b[31m', '❌ Error: components.js not found in expected path', '\x1b[0m');
66
84
  console.log('\x1b[36m', 'ℹ️ Info: Run "slice component list" to generate components.js', '\x1b[0m');
67
85
  return false;
68
86
  }
69
-
87
+
70
88
  const fileContent = fs.readFileSync(componentFilePath, 'utf-8');
71
89
  const components = eval(fileContent.replace('export default', '')); // Evalúa el contenido como objeto
72
-
90
+
73
91
  return components.hasOwnProperty(componentName);
74
92
 
75
93
  } catch (error) {
@@ -82,4 +100,4 @@ class Validations {
82
100
 
83
101
  const validations = new Validations();
84
102
 
85
- export default validations;
103
+ export default validations;
@@ -7,6 +7,7 @@ import { minify as terserMinify } from 'terser';
7
7
  import { minify } from 'html-minifier-terser';
8
8
  import CleanCSS from 'clean-css';
9
9
  import Print from '../Print.js';
10
+ import { getSrcPath, getDistPath, getConfigPath } from '../utils/PathHelper.js';
10
11
 
11
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
13
 
@@ -15,7 +16,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
16
  */
16
17
  const loadConfig = () => {
17
18
  try {
18
- const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
19
+ const configPath = getConfigPath(import.meta.url);
19
20
  const rawData = fs.readFileSync(configPath, 'utf-8');
20
21
  return JSON.parse(rawData);
21
22
  } catch (error) {
@@ -28,7 +29,7 @@ const loadConfig = () => {
28
29
  * Verifica dependencias necesarias para el build
29
30
  */
30
31
  async function checkBuildDependencies() {
31
- const srcDir = path.join(__dirname, '../../../../src');
32
+ const srcDir = getSrcPath(import.meta.url);
32
33
 
33
34
  if (!await fs.pathExists(srcDir)) {
34
35
  Print.error('Source directory (/src) not found');
@@ -103,8 +104,8 @@ async function verifyBuildIntegrity(distDir) {
103
104
  * Copia sliceConfig.json al directorio dist
104
105
  */
105
106
  async function copySliceConfig() {
106
- const srcConfig = path.join(__dirname, '../../../../src/sliceConfig.json');
107
- const distConfig = path.join(__dirname, '../../../../dist/sliceConfig.json');
107
+ const srcConfig = getConfigPath(import.meta.url);
108
+ const distConfig = getDistPath(import.meta.url, 'sliceConfig.json');
108
109
 
109
110
  if (await fs.pathExists(srcConfig)) {
110
111
  await fs.copy(srcConfig, distConfig);
@@ -336,7 +337,7 @@ async function minifyHTML(srcPath, distPath) {
336
337
  async function createOptimizedBundle() {
337
338
  Print.buildProgress('Creating optimized bundle...');
338
339
 
339
- const mainJSPath = path.join(__dirname, '../../../../dist/App/index.js');
340
+ const mainJSPath = getDistPath(import.meta.url, 'App', 'index.js');
340
341
 
341
342
  if (await fs.pathExists(mainJSPath)) {
342
343
  Print.success('Main bundle optimized');
@@ -389,7 +390,7 @@ async function generateBuildStats(srcDir, distDir) {
389
390
  * Analiza el build sin construir
390
391
  */
391
392
  async function analyzeBuild() {
392
- const distDir = path.join(__dirname, '../../../../dist');
393
+ const distDir = getDistPath(import.meta.url);
393
394
 
394
395
  if (!await fs.pathExists(distDir)) {
395
396
  Print.error('No build found to analyze. Run "slice build" first.');
@@ -398,7 +399,7 @@ async function analyzeBuild() {
398
399
 
399
400
  Print.info('Analyzing production build...');
400
401
  await generateBuildStats(
401
- path.join(__dirname, '../../../../src'),
402
+ getSrcPath(import.meta.url),
402
403
  distDir
403
404
  );
404
405
  }
@@ -413,8 +414,8 @@ export default async function buildProduction(options = {}) {
413
414
  Print.title('🔨 Building Slice.js project for production...');
414
415
  Print.newLine();
415
416
 
416
- const srcDir = path.join(__dirname, '../../../../src');
417
- const distDir = path.join(__dirname, '../../../../dist');
417
+ const srcDir = getSrcPath(import.meta.url);
418
+ const distDir = getDistPath(import.meta.url);
418
419
 
419
420
  if (!await fs.pathExists(srcDir)) {
420
421
  throw new Error('Source directory not found. Run "slice init" first.');
@@ -470,7 +471,7 @@ export async function serveProductionBuild(port) {
470
471
  const defaultPort = config?.server?.port || 3001;
471
472
  const finalPort = port || defaultPort;
472
473
 
473
- const distDir = path.join(__dirname, '../../../../dist');
474
+ const distDir = getDistPath(import.meta.url);
474
475
 
475
476
  if (!await fs.pathExists(distDir)) {
476
477
  throw new Error('No production build found. Run "slice build" first.');
@@ -540,4 +541,4 @@ export async function buildCommand(options = {}) {
540
541
  }
541
542
 
542
543
  return success;
543
- }
544
+ }
@@ -5,7 +5,8 @@ import path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import Validations from '../Validations.js';
7
7
  import Print from '../Print.js';
8
- const __dirname = path.dirname(new URL(import.meta.url).pathname);
8
+ import { getSrcPath } from '../utils/PathHelper.js';
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
 
10
11
  function createComponent(componentName, category) {
11
12
  // Validación: Nombre de componente requerido
@@ -62,10 +63,8 @@ function createComponent(componentName, category) {
62
63
  }
63
64
 
64
65
  const categoryPath = Validations.getCategoryPath(category);
65
-
66
- // Determinar la ruta del directorio del componente
67
- let componentDir = path.join(__dirname, '../../../../src/', categoryPath, className);
68
- componentDir = componentDir.slice(1);
66
+ const categoryPathClean = categoryPath ? categoryPath.replace(/^[/\\]+/, '') : '';
67
+ const componentDir = getSrcPath(import.meta.url, categoryPathClean, className);
69
68
 
70
69
  try {
71
70
  // Crear directorio del componente
@@ -2,7 +2,9 @@ import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import Validations from '../Validations.js';
4
4
  import Print from '../Print.js';
5
- const __dirname = path.dirname(new URL(import.meta.url).pathname);
5
+ import { fileURLToPath } from 'url';
6
+ import { getSrcPath } from '../utils/PathHelper.js';
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
8
 
7
9
  function deleteComponent(componentName, category) {
8
10
  // Validación: Nombre de componente requerido
@@ -31,10 +33,8 @@ function deleteComponent(componentName, category) {
31
33
  category = flagCategory.category;
32
34
 
33
35
  const categoryPath = Validations.getCategoryPath(category);
34
-
35
- // Construir la ruta del directorio del componente
36
- let componentDir = path.join(__dirname, '../../../../src/', categoryPath, componentName);
37
- componentDir = componentDir.slice(1);
36
+ const categoryPathClean = categoryPath ? categoryPath.replace(/^[/\\]+/, '') : '';
37
+ const componentDir = getSrcPath(import.meta.url, categoryPathClean, componentName);
38
38
 
39
39
  // Verificar si el directorio del componente existe
40
40
  if (!fs.existsSync(componentDir)) {
@@ -5,6 +5,7 @@ import { createServer } from 'net';
5
5
  import chalk from 'chalk';
6
6
  import Table from 'cli-table3';
7
7
  import Print from '../Print.js';
8
+ import { getProjectRoot, getSrcPath, getApiPath, getConfigPath, getPath } from '../utils/PathHelper.js';
8
9
 
9
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
11
 
@@ -34,9 +35,8 @@ async function checkNodeVersion() {
34
35
  * Verifica la estructura de directorios
35
36
  */
36
37
  async function checkDirectoryStructure() {
37
- const projectRoot = path.join(__dirname, '../../../../');
38
- const srcPath = path.join(projectRoot, 'src');
39
- const apiPath = path.join(projectRoot, 'api');
38
+ const srcPath = getSrcPath(import.meta.url);
39
+ const apiPath = getApiPath(import.meta.url);
40
40
 
41
41
  const srcExists = await fs.pathExists(srcPath);
42
42
  const apiExists = await fs.pathExists(apiPath);
@@ -63,7 +63,7 @@ async function checkDirectoryStructure() {
63
63
  * Verifica sliceConfig.json
64
64
  */
65
65
  async function checkConfig() {
66
- const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
66
+ const configPath = getConfigPath(import.meta.url);
67
67
 
68
68
  if (!await fs.pathExists(configPath)) {
69
69
  return {
@@ -101,7 +101,7 @@ async function checkConfig() {
101
101
  * Verifica disponibilidad del puerto
102
102
  */
103
103
  async function checkPort() {
104
- const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
104
+ const configPath = getConfigPath(import.meta.url);
105
105
  let port = 3000;
106
106
 
107
107
  try {
@@ -145,7 +145,7 @@ async function checkPort() {
145
145
  * Verifica dependencias en package.json
146
146
  */
147
147
  async function checkDependencies() {
148
- const packagePath = path.join(__dirname, '../../../../package.json');
148
+ const packagePath = getPath(import.meta.url, '', 'package.json');
149
149
 
150
150
  if (!await fs.pathExists(packagePath)) {
151
151
  return {
@@ -189,8 +189,8 @@ async function checkDependencies() {
189
189
  * Verifica integridad de componentes
190
190
  */
191
191
  async function checkComponents() {
192
- const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
193
- const projectRoot = path.join(__dirname, '../../../../');
192
+ const configPath = getConfigPath(import.meta.url);
193
+ const projectRoot = getProjectRoot(import.meta.url);
194
194
 
195
195
  if (!await fs.pathExists(configPath)) {
196
196
  return {
@@ -208,7 +208,7 @@ async function checkComponents() {
208
208
  let componentIssues = 0;
209
209
 
210
210
  for (const [category, { path: compPath }] of Object.entries(componentPaths)) {
211
- const fullPath = path.join(projectRoot, 'src', compPath);
211
+ const fullPath = getSrcPath(import.meta.url, compPath);
212
212
 
213
213
  if (await fs.pathExists(fullPath)) {
214
214
  const items = await fs.readdir(fullPath);
@@ -6,6 +6,7 @@ import { fileURLToPath } from "url";
6
6
  import inquirer from "inquirer";
7
7
  import validations from "../Validations.js";
8
8
  import Print from "../Print.js";
9
+ import { getConfigPath, getComponentsJsPath, getPath } from "../utils/PathHelper.js";
9
10
 
10
11
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
12
 
@@ -19,8 +20,7 @@ const COMPONENTS_REGISTRY_URL = 'https://raw.githubusercontent.com/VKneider/slic
19
20
  */
20
21
  const loadConfig = () => {
21
22
  try {
22
- // CORREGIDO: Usar 4 niveles como en listComponents para compatibilidad con node_modules
23
- const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
23
+ const configPath = getConfigPath(import.meta.url);
24
24
  if (!fs.existsSync(configPath)) {
25
25
  throw new Error('sliceConfig.json not found in src folder');
26
26
  }
@@ -98,8 +98,7 @@ filterOfficialComponents(allComponents) {
98
98
 
99
99
  async getLocalComponents() {
100
100
  try {
101
- // CORREGIDO: Usar 4 niveles como en listComponents para compatibilidad con node_modules
102
- const componentsPath = path.join(__dirname, '../../../../src/Components/components.js');
101
+ const componentsPath = getComponentsJsPath(import.meta.url);
103
102
 
104
103
  if (!await fs.pathExists(componentsPath)) {
105
104
  return {};
@@ -132,8 +131,7 @@ filterOfficialComponents(allComponents) {
132
131
  // ✅ CORREGIDO: Usar 4 niveles para compatibilidad con node_modules
133
132
  const isProduction = this.config?.production?.enabled === true;
134
133
  const folderSuffix = isProduction ? 'dist' : 'src';
135
-
136
- const componentPath = path.join(__dirname, `../../../../${folderSuffix}`, categoryPath, name);
134
+ const componentPath = getPath(import.meta.url, folderSuffix, categoryPath, name);
137
135
 
138
136
  if (fs.pathExistsSync(componentPath)) {
139
137
  updatableComponents.push({
@@ -180,43 +178,6 @@ filterOfficialComponents(allComponents) {
180
178
  return components;
181
179
  }
182
180
 
183
- displayAvailableComponents() {
184
- if (!this.componentsRegistry) {
185
- Print.error('❌ No se pudo cargar el registro de componentes');
186
- return;
187
- }
188
-
189
- console.log('\n📚 Componentes disponibles en el repositorio oficial de Slice.js:\n');
190
-
191
- const visualComponents = this.getAvailableComponents('Visual');
192
- const serviceComponents = this.getAvailableComponents('Service');
193
-
194
- // ✅ SIMPLIFICADO: Solo mostrar nombres sin descripciones
195
- Print.info('🎨 Visual Components (UI):');
196
- Object.keys(visualComponents).forEach(name => {
197
- const files = visualComponents[name].files;
198
- const fileIcons = files.map(file => {
199
- if (file.endsWith('.js')) return '📜';
200
- if (file.endsWith('.html')) return '🌐';
201
- if (file.endsWith('.css')) return '🎨';
202
- return '📄';
203
- }).join(' ');
204
- console.log(` • ${name} ${fileIcons}`);
205
- });
206
-
207
- Print.info('\n⚙️ Service Components (Logic):');
208
- Object.keys(serviceComponents).forEach(name => {
209
- console.log(` • ${name} 📜`);
210
- });
211
-
212
- Print.newLine();
213
- Print.info(`Total: ${Object.keys(visualComponents).length} Visual + ${Object.keys(serviceComponents).length} Service components`);
214
-
215
- console.log(`\n💡 Ejemplos de uso:`);
216
- console.log(`slice get Button Card Input # Obtener componentes Visual`);
217
- console.log(`slice get FetchManager --service # Obtener componente Service`);
218
- console.log(`slice sync # Sincronizar componentes Visual`);
219
- }
220
181
 
221
182
  async downloadComponentFiles(componentName, category, targetPath) {
222
183
  const component = this.getAvailableComponents(category)[componentName];
@@ -270,6 +231,36 @@ filterOfficialComponents(allComponents) {
270
231
  return downloadedFiles;
271
232
  }
272
233
 
234
+ async updateLocalRegistrySafe(componentName, category) {
235
+ const componentsPath = path.join(__dirname, '../../../../src/Components/components.js');
236
+ try {
237
+ if (!await fs.pathExists(componentsPath)) {
238
+ const dir = path.dirname(componentsPath);
239
+ await fs.ensureDir(dir);
240
+ const initial = `const components = {};\n\nexport default components;\n`;
241
+ await fs.writeFile(componentsPath, initial, 'utf8');
242
+ }
243
+ const content = await fs.readFile(componentsPath, 'utf8');
244
+ const match = content.match(/const components = ({[\s\S]*?});/);
245
+ if (!match) throw new Error('Invalid components.js format in local project');
246
+ const componentsObj = eval('(' + match[1] + ')');
247
+ if (!componentsObj[componentName]) {
248
+ componentsObj[componentName] = category;
249
+ const sorted = Object.keys(componentsObj)
250
+ .sort()
251
+ .reduce((obj, key) => { obj[key] = componentsObj[key]; return obj; }, {});
252
+ const newContent = `const components = ${JSON.stringify(sorted, null, 2)};\n\nexport default components;\n`;
253
+ await fs.writeFile(componentsPath, newContent, 'utf8');
254
+ Print.registryUpdate(`Registered ${componentName} in local components.js`);
255
+ } else {
256
+ Print.info(`${componentName} already exists in local registry`);
257
+ }
258
+ } catch (error) {
259
+ Print.error(`Updating local components.js: ${error.message}`);
260
+ throw error;
261
+ }
262
+ }
263
+
273
264
  async updateLocalRegistry(componentName, category) {
274
265
  // ✅ CORREGIDO: Usar 4 niveles para compatibilidad con node_modules
275
266
  const componentsPath = path.join(__dirname, '../../../../src/Components/components.js');
@@ -331,14 +322,12 @@ filterOfficialComponents(allComponents) {
331
322
  validations.config.paths.components[category];
332
323
 
333
324
  if (hasValidConfig) {
334
- // Usar validations cuando la config está disponible
335
325
  categoryPath = validations.getCategoryPath(category);
336
326
  } else {
337
- // Usar rutas por defecto cuando no hay config (durante init o error)
338
327
  if (category === 'Visual') {
339
- categoryPath = '/Components/Visual';
328
+ categoryPath = 'Components/Visual';
340
329
  } else if (category === 'Service') {
341
- categoryPath = '/Components/Service';
330
+ categoryPath = 'Components/Service';
342
331
  } else {
343
332
  throw new Error(`Unknown category: ${category}`);
344
333
  }
@@ -347,7 +336,8 @@ filterOfficialComponents(allComponents) {
347
336
  const isProduction = this.config?.production?.enabled === true;
348
337
  const folderSuffix = isProduction ? 'dist' : 'src';
349
338
 
350
- const targetPath = path.join(__dirname, `../../../../${folderSuffix}`, categoryPath, componentName);
339
+ const cleanCategoryPath = categoryPath ? categoryPath.replace(/^[/\\]+/, '') : '';
340
+ const targetPath = getPath(import.meta.url, folderSuffix, cleanCategoryPath, componentName);
351
341
 
352
342
 
353
343
 
@@ -375,8 +365,7 @@ filterOfficialComponents(allComponents) {
375
365
  // Download component files
376
366
  const downloadedFiles = await this.downloadComponentFiles(componentName, category, targetPath);
377
367
 
378
- // Update components registry
379
- await this.updateLocalRegistry(componentName, category);
368
+ await this.updateLocalRegistrySafe(componentName, category);
380
369
 
381
370
  Print.success(`${componentName} installed successfully from official repository!`);
382
371
  console.log(`📁 Location: ${folderSuffix}/${categoryPath}/${componentName}/`);
@@ -717,4 +706,4 @@ async function syncComponents(options = {}) {
717
706
  }
718
707
 
719
708
  export default getComponents;
720
- export { listComponents, syncComponents, ComponentRegistry };
709
+ export { listComponents, syncComponents, ComponentRegistry };
@@ -3,6 +3,8 @@ 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';
7
+ import { execSync } from 'child_process';
6
8
 
7
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
10
 
@@ -11,12 +13,39 @@ import { ComponentRegistry } from '../getComponent/getComponent.js';
11
13
 
12
14
  export default async function initializeProject(projectType) {
13
15
  try {
14
- // Directorio de origen para API (mantener copia local)
15
- let sliceBaseDir = path.join(__dirname, '../../../slicejs-web-framework');
16
- let apiDir = path.join(sliceBaseDir, 'api');
17
- let srcDir = path.join(sliceBaseDir, 'src');
18
- let destinationApi = path.join(__dirname, '../../../../api');
19
- let destinationSrc = path.join(__dirname, '../../../../src');
16
+ const projectRoot = getProjectRoot(import.meta.url);
17
+ const destinationApi = getApiPath(import.meta.url);
18
+ const destinationSrc = getSrcPath(import.meta.url);
19
+
20
+ const fwSpinner = ora('Ensuring latest Slice framework...').start();
21
+ let sliceBaseDir;
22
+ try {
23
+ const latest = execSync('npm view slicejs-web-framework version', { cwd: projectRoot }).toString().trim();
24
+ const installedPkgPath = path.join(projectRoot, 'node_modules', 'slicejs-web-framework', 'package.json');
25
+ let installed = null;
26
+ if (await fs.pathExists(installedPkgPath)) {
27
+ const pkg = await fs.readJson(installedPkgPath);
28
+ installed = pkg.version;
29
+ }
30
+ if (installed !== latest) {
31
+ execSync(`npm install slicejs-web-framework@${latest} --save`, { cwd: projectRoot, stdio: 'inherit' });
32
+ }
33
+ sliceBaseDir = path.join(projectRoot, 'node_modules', 'slicejs-web-framework');
34
+ fwSpinner.succeed(`slicejs-web-framework@${latest} ready`);
35
+ } catch (err) {
36
+ const fallback = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../slicejs-web-framework');
37
+ if (await fs.pathExists(fallback)) {
38
+ sliceBaseDir = fallback;
39
+ fwSpinner.warn('Using local slicejs-web-framework fallback');
40
+ } else {
41
+ fwSpinner.fail('Failed to ensure latest slicejs-web-framework');
42
+ Print.error(err.message);
43
+ return;
44
+ }
45
+ }
46
+
47
+ const apiDir = path.join(sliceBaseDir, 'api');
48
+ const srcDir = path.join(sliceBaseDir, 'src');
20
49
 
21
50
  try {
22
51
  // Verificar si los directorios de destino ya existen
@@ -131,6 +160,73 @@ export default async function initializeProject(projectType) {
131
160
  Print.info('You can add them later using "slice get <component-name>"');
132
161
  }
133
162
 
163
+ // 4. CONFIGURAR SCRIPTS EN package.json DEL PROYECTO
164
+ const pkgSpinner = ora('Configuring npm scripts...').start();
165
+ try {
166
+ const projectRoot = getProjectRoot(import.meta.url);
167
+ const pkgPath = path.join(projectRoot, 'package.json');
168
+
169
+ let pkg;
170
+ if (await fs.pathExists(pkgPath)) {
171
+ pkg = await fs.readJson(pkgPath);
172
+ } else {
173
+ pkg = {
174
+ name: path.basename(projectRoot),
175
+ version: '1.0.0',
176
+ description: 'Slice.js project',
177
+ main: 'api/index.js',
178
+ scripts: {}
179
+ };
180
+ }
181
+
182
+ pkg.scripts = pkg.scripts || {};
183
+
184
+ // Comandos principales
185
+ pkg.scripts['dev'] = 'slice dev';
186
+ pkg.scripts['start'] = 'slice start';
187
+
188
+ // Gestión de componentes
189
+ pkg.scripts['component:create'] = 'slice component create';
190
+ pkg.scripts['component:list'] = 'slice component list';
191
+ pkg.scripts['component:delete'] = 'slice component delete';
192
+
193
+ // Atajos de repositorio
194
+ pkg.scripts['get'] = 'slice get';
195
+ pkg.scripts['browse'] = 'slice browse';
196
+ pkg.scripts['sync'] = 'slice sync';
197
+
198
+ // Utilidades
199
+ pkg.scripts['slice:version'] = 'slice version';
200
+ pkg.scripts['slice:update'] = 'slice update';
201
+
202
+ // Legacy (compatibilidad)
203
+ pkg.scripts['slice:init'] = 'slice init';
204
+ pkg.scripts['slice:start'] = 'slice start';
205
+ pkg.scripts['slice:dev'] = 'slice dev';
206
+ pkg.scripts['slice:create'] = 'slice component create';
207
+ pkg.scripts['slice:list'] = 'slice component list';
208
+ pkg.scripts['slice:delete'] = 'slice component delete';
209
+ pkg.scripts['slice:get'] = 'slice get';
210
+ pkg.scripts['slice:browse'] = 'slice browse';
211
+ pkg.scripts['slice:sync'] = 'slice sync';
212
+ pkg.scripts['run'] = 'slice dev';
213
+
214
+ // Configuración de módulo
215
+ pkg.type = pkg.type || 'module';
216
+ pkg.engines = pkg.engines || { node: '>=20.0.0' };
217
+
218
+ await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2), 'utf8');
219
+ pkgSpinner.succeed('npm scripts configured successfully');
220
+
221
+ console.log('\n🎯 New recommended commands:');
222
+ console.log(' npm run dev - Start development server');
223
+ console.log(' npm run get - Install components');
224
+ console.log(' npm run browse - Browse components');
225
+ } catch (error) {
226
+ pkgSpinner.fail('Failed to configure npm scripts');
227
+ Print.error(error.message);
228
+ }
229
+
134
230
  Print.success('Proyecto inicializado correctamente.');
135
231
  Print.newLine();
136
232
  Print.info('Next steps:');
@@ -155,4 +251,4 @@ async function getAllVisualComponents(registry) {
155
251
  Print.info(`Found ${allVisualComponents.length} Visual components in official repository`);
156
252
 
157
253
  return allVisualComponents;
158
- }
254
+ }
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'url';
4
4
  import Table from 'cli-table3';
5
5
  import chalk from 'chalk';
6
6
  import Print from '../Print.js';
7
+ import { getSrcPath, getComponentsJsPath, getConfigPath } from '../utils/PathHelper.js';
7
8
 
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
 
@@ -13,7 +14,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
14
  */
14
15
  const loadConfig = () => {
15
16
  try {
16
- const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
17
+ const configPath = getConfigPath(import.meta.url);
17
18
  if (!fs.existsSync(configPath)) {
18
19
  Print.error('sliceConfig.json not found');
19
20
  Print.info('Run "slice init" to initialize your project');
@@ -72,7 +73,8 @@ const getComponents = () => {
72
73
  let allComponents = new Map();
73
74
 
74
75
  Object.entries(componentPaths).forEach(([category, { path: folderPath }]) => {
75
- const fullPath = path.join(__dirname, `../../../../${folderSuffix}`, folderPath);
76
+ const cleanFolderPath = folderPath ? folderPath.replace(/^[/\\]+/, '') : '';
77
+ const fullPath = getSrcPath(import.meta.url, cleanFolderPath);
76
78
  const files = listComponents(fullPath);
77
79
 
78
80
  files.forEach(file => {
@@ -150,7 +152,7 @@ function listComponentsReal() {
150
152
  Print.info(`Total: ${Object.keys(components).length} component${Object.keys(components).length !== 1 ? 's' : ''} found`);
151
153
 
152
154
  // Ruta donde se generará components.js
153
- const outputPath = path.join(__dirname, '../../../../src/Components/components.js');
155
+ const outputPath = getComponentsJsPath(import.meta.url);
154
156
 
155
157
  // Asegurar que el directorio existe
156
158
  const outputDir = path.dirname(outputPath);
@@ -7,6 +7,7 @@ import { spawn } from 'child_process';
7
7
  import { createServer } from 'net';
8
8
  import setupWatcher, { stopWatcher } from './watchServer.js';
9
9
  import Print from '../Print.js';
10
+ import { getConfigPath, getApiPath, getSrcPath, getDistPath } from '../utils/PathHelper.js';
10
11
 
11
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
13
 
@@ -15,7 +16,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
16
  */
16
17
  const loadConfig = () => {
17
18
  try {
18
- const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
19
+ const configPath = getConfigPath(import.meta.url);
19
20
  const rawData = fs.readFileSync(configPath, 'utf-8');
20
21
  return JSON.parse(rawData);
21
22
  } catch (error) {
@@ -52,7 +53,7 @@ async function isPortAvailable(port) {
52
53
  * Verifica si existe un build de producción
53
54
  */
54
55
  async function checkProductionBuild() {
55
- const distDir = path.join(__dirname, '../../../../dist');
56
+ const distDir = getDistPath(import.meta.url);
56
57
  return await fs.pathExists(distDir);
57
58
  }
58
59
 
@@ -60,8 +61,8 @@ async function checkProductionBuild() {
60
61
  * Verifica si existe la estructura de desarrollo
61
62
  */
62
63
  async function checkDevelopmentStructure() {
63
- const srcDir = path.join(__dirname, '../../../../src');
64
- const apiDir = path.join(__dirname, '../../../../api');
64
+ const srcDir = getSrcPath(import.meta.url);
65
+ const apiDir = getApiPath(import.meta.url);
65
66
 
66
67
  return (await fs.pathExists(srcDir)) && (await fs.pathExists(apiDir));
67
68
  }
@@ -71,7 +72,7 @@ async function checkDevelopmentStructure() {
71
72
  */
72
73
  function startNodeServer(port, mode) {
73
74
  return new Promise((resolve, reject) => {
74
- const apiIndexPath = path.join(__dirname, '../../../../api/index.js');
75
+ const apiIndexPath = getApiPath(import.meta.url, 'index.js');
75
76
 
76
77
  // Verificar que el archivo existe
77
78
  if (!fs.existsSync(apiIndexPath)) {
@@ -235,4 +236,4 @@ export default async function startServer(options = {}) {
235
236
  /**
236
237
  * Funciones de utilidad exportadas
237
238
  */
238
- export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
239
+ export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
@@ -0,0 +1,58 @@
1
+ import path from 'path'
2
+ import fs from 'fs-extra'
3
+ import { fileURLToPath } from 'url'
4
+
5
+ const sanitize = (s) => (s || '').replace(/^[/\\]+/, '')
6
+ const dirOf = (url) => path.dirname(fileURLToPath(url))
7
+
8
+ function candidates(moduleUrl) {
9
+ const dir = dirOf(moduleUrl)
10
+ return [
11
+ path.join(dir, '../../'),
12
+ path.join(dir, '../../../../')
13
+ ]
14
+ }
15
+
16
+ function resolveProjectRoot(moduleUrl) {
17
+ const dirs = candidates(moduleUrl)
18
+ for (const root of dirs) {
19
+ const hasSrc = fs.pathExistsSync(path.join(root, 'src'))
20
+ const hasApi = fs.pathExistsSync(path.join(root, 'api'))
21
+ if (hasSrc || hasApi) return root
22
+ }
23
+ return dirs[1]
24
+ }
25
+
26
+ function joinProject(moduleUrl, ...segments) {
27
+ const root = resolveProjectRoot(moduleUrl)
28
+ const clean = segments.map(sanitize)
29
+ return path.join(root, ...clean)
30
+ }
31
+
32
+ export function getProjectRoot(moduleUrl) {
33
+ return resolveProjectRoot(moduleUrl)
34
+ }
35
+
36
+ export function getPath(moduleUrl, folder, ...segments) {
37
+ return joinProject(moduleUrl, folder, ...segments)
38
+ }
39
+
40
+ export function getSrcPath(moduleUrl, ...segments) {
41
+ return joinProject(moduleUrl, 'src', ...segments)
42
+ }
43
+
44
+ export function getApiPath(moduleUrl, ...segments) {
45
+ return joinProject(moduleUrl, 'api', ...segments)
46
+ }
47
+
48
+ export function getDistPath(moduleUrl, ...segments) {
49
+ return joinProject(moduleUrl, 'dist', ...segments)
50
+ }
51
+
52
+ export function getConfigPath(moduleUrl) {
53
+ return joinProject(moduleUrl, 'src', 'sliceConfig.json')
54
+ }
55
+
56
+ export function getComponentsJsPath(moduleUrl) {
57
+ return joinProject(moduleUrl, 'src', 'Components', 'components.js')
58
+ }
@@ -1,9 +1,10 @@
1
1
  // commands/utils/VersionChecker.js
2
2
 
3
- import fs from "fs-extra";
4
- import path from "path";
5
- import { fileURLToPath } from "url";
6
- import Print from "../Print.js";
3
+ import fs from "fs-extra";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ import Print from "../Print.js";
7
+ import { getProjectRoot } from "../utils/PathHelper.js";
7
8
 
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
 
@@ -22,8 +23,9 @@ class VersionChecker {
22
23
  const cliPackage = await fs.readJson(cliPackagePath);
23
24
  this.currentCliVersion = cliPackage.version;
24
25
 
25
- // Get Framework version from node_modules
26
- const frameworkPackagePath = path.join(__dirname, '../../../../node_modules/slicejs-web-framework/package.json');
26
+ // Get Framework version from project node_modules
27
+ const projectRoot = getProjectRoot(import.meta.url);
28
+ const frameworkPackagePath = path.join(projectRoot, 'node_modules', 'slicejs-web-framework', 'package.json');
27
29
  if (await fs.pathExists(frameworkPackagePath)) {
28
30
  const frameworkPackage = await fs.readJson(frameworkPackagePath);
29
31
  this.currentFrameworkVersion = frameworkPackage.version;
@@ -162,4 +164,4 @@ class VersionChecker {
162
164
  // Singleton instance
163
165
  const versionChecker = new VersionChecker();
164
166
 
165
- export default versionChecker;
167
+ export default versionChecker;
@@ -5,7 +5,10 @@ import { promisify } from "util";
5
5
  import inquirer from "inquirer";
6
6
  import ora from "ora";
7
7
  import Print from "../Print.js";
8
- import versionChecker from "./versionChecker.js";
8
+ import versionChecker from "./VersionChecker.js";
9
+ import { getProjectRoot } from "../utils/PathHelper.js";
10
+ import path from "path";
11
+ import { fileURLToPath } from "url";
9
12
 
10
13
  const execAsync = promisify(exec);
11
14
 
@@ -14,6 +17,31 @@ class UpdateManager {
14
17
  this.packagesToUpdate = [];
15
18
  }
16
19
 
20
+ async detectCliInstall() {
21
+ try {
22
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
23
+ const cliRoot = path.join(moduleDir, '../../');
24
+ const projectRoot = getProjectRoot(import.meta.url);
25
+ let globalPrefix = '';
26
+ try {
27
+ const { stdout } = await execAsync('npm config get prefix');
28
+ globalPrefix = stdout.toString().trim();
29
+ } catch {}
30
+ const localNodeModules = path.join(projectRoot, 'node_modules');
31
+ const globalNodeModules = globalPrefix ? path.join(globalPrefix, 'node_modules') : '';
32
+
33
+ if (cliRoot.startsWith(localNodeModules)) {
34
+ return { type: 'local', cliRoot, projectRoot, globalPrefix };
35
+ }
36
+ if (globalNodeModules && cliRoot.startsWith(globalNodeModules)) {
37
+ return { type: 'global', cliRoot, projectRoot, globalPrefix };
38
+ }
39
+ return { type: 'unknown', cliRoot, projectRoot, globalPrefix };
40
+ } catch (error) {
41
+ return { type: 'unknown' };
42
+ }
43
+ }
44
+
17
45
  /**
18
46
  * Check for available updates and return structured info
19
47
  */
@@ -132,13 +160,45 @@ class UpdateManager {
132
160
  return answers.packages;
133
161
  }
134
162
 
163
+ async buildUpdatePlan(packages) {
164
+ const plan = [];
165
+ const info = await this.detectCliInstall();
166
+ for (const pkg of packages) {
167
+ if (pkg === 'slicejs-cli') {
168
+ if (info.type === 'global') {
169
+ plan.push({ package: pkg, target: 'global', command: 'npm install -g slicejs-cli@latest' });
170
+ } else {
171
+ plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-cli@latest' });
172
+ }
173
+ } else if (pkg === 'slicejs-web-framework') {
174
+ plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-web-framework@latest' });
175
+ } else {
176
+ plan.push({ package: pkg, target: 'project', command: `npm install ${pkg}@latest` });
177
+ }
178
+ }
179
+ return plan;
180
+ }
181
+
135
182
  /**
136
183
  * Execute npm update command for a specific package
137
184
  */
138
185
  async updatePackage(packageName) {
139
186
  try {
140
- const command = `npm install ${packageName}@latest`;
141
- const { stdout, stderr } = await execAsync(command);
187
+ let command = `npm install ${packageName}@latest`;
188
+ let options = {};
189
+
190
+ if (packageName === 'slicejs-cli') {
191
+ const info = await this.detectCliInstall();
192
+ if (info.type === 'global') {
193
+ command = `npm install -g slicejs-cli@latest`;
194
+ } else {
195
+ options.cwd = info.projectRoot || getProjectRoot(import.meta.url);
196
+ }
197
+ } else {
198
+ options.cwd = getProjectRoot(import.meta.url);
199
+ }
200
+
201
+ const { stdout, stderr } = await execAsync(command, options);
142
202
 
143
203
  return {
144
204
  success: true,
@@ -213,24 +273,64 @@ class UpdateManager {
213
273
  // Display available updates
214
274
  this.displayUpdates(updateInfo);
215
275
 
216
- // Get packages to update
217
- const packagesToUpdate = await this.promptForUpdates(updateInfo, options);
276
+ // Get packages to update
277
+ const packagesToUpdate = await this.promptForUpdates(updateInfo, options);
218
278
 
219
279
  if (!packagesToUpdate || packagesToUpdate.length === 0) {
220
280
  Print.info('No se seleccionaron paquetes para actualizar.');
221
281
  return false;
222
282
  }
223
283
 
224
- // Confirm installation if not auto-confirmed
225
- if (!options.yes && !options.cli && !options.framework) {
226
- const { confirm } = await inquirer.prompt([
284
+ // Show plan and confirm installation if not auto-confirmed
285
+ let plan = await this.buildUpdatePlan(packagesToUpdate);
286
+ console.log('');
287
+ Print.info('🧭 Plan de actualización:');
288
+ plan.forEach(item => {
289
+ const where = item.target === 'global' ? 'GLOBAL' : 'PROYECTO';
290
+ console.log(` • ${item.package} → ${where}`);
291
+ console.log(` ${item.command}`);
292
+ });
293
+ console.log('');
294
+
295
+ const cliInfo = await this.detectCliInstall();
296
+ if (cliInfo.type === 'global' && !packagesToUpdate.includes('slicejs-cli')) {
297
+ if (!options.yes && !options.cli) {
298
+ const { addCli } = await inquirer.prompt([
227
299
  {
228
300
  type: 'confirm',
229
- name: 'confirm',
230
- message: '¿Deseas continuar con la actualización?',
301
+ name: 'addCli',
302
+ message: 'Se detectó CLI global. ¿Agregar la actualización global del CLI al plan?',
231
303
  default: true
232
304
  }
233
305
  ]);
306
+ if (addCli) {
307
+ packagesToUpdate.push('slicejs-cli');
308
+ plan = await this.buildUpdatePlan(packagesToUpdate);
309
+ console.log('');
310
+ Print.info('🧭 Plan actualizado:');
311
+ plan.forEach(item => {
312
+ const where = item.target === 'global' ? 'GLOBAL' : 'PROYECTO';
313
+ console.log(` • ${item.package} → ${where}`);
314
+ console.log(` ${item.command}`);
315
+ });
316
+ console.log('');
317
+ }
318
+ } else {
319
+ Print.warning('CLI global detectado. Se recomienda actualizar slicejs-cli global para mantener alineado con el framework.');
320
+ console.log(' Sugerencia: npm install -g slicejs-cli@latest');
321
+ console.log('');
322
+ }
323
+ }
324
+
325
+ if (!options.yes && !options.cli && !options.framework) {
326
+ const { confirm } = await inquirer.prompt([
327
+ {
328
+ type: 'confirm',
329
+ name: 'confirm',
330
+ message: '¿Deseas continuar con la actualización según el plan mostrado?',
331
+ default: true
332
+ }
333
+ ]);
234
334
 
235
335
  if (!confirm) {
236
336
  Print.info('Actualización cancelada.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slicejs-cli",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Command client for developing web applications with Slice.js framework",
5
5
  "main": "client.js",
6
6
  "bin": {
package/post.js CHANGED
@@ -5,142 +5,21 @@ import Print from './commands/Print.js';
5
5
 
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
- const projectName = path.basename(__dirname);
9
8
 
10
- const projectPackageJsonPath = path.resolve(__dirname, '../../package.json');
11
-
12
- // Check if package.json file exists
13
- fs.promises.access(projectPackageJsonPath, fs.constants.F_OK)
14
- .then(() => {
15
- // The package.json file exists, so we read it and add the commands
16
- return fs.promises.readFile(projectPackageJsonPath, 'utf8');
17
- })
18
- .then(data => {
19
- // Convert the file content to a JSON object
20
- const projectPackageJson = JSON.parse(data);
21
-
22
- // Add custom commands to the project scripts
23
- projectPackageJson.scripts = projectPackageJson.scripts || {};
24
-
25
- // Main project commands - using 'slice' directly
26
- projectPackageJson.scripts['dev'] = 'slice dev';
27
- projectPackageJson.scripts['start'] = 'slice start';
28
-
29
- // Component management
30
- projectPackageJson.scripts['component:create'] = 'slice component create';
31
- projectPackageJson.scripts['component:list'] = 'slice component list';
32
- projectPackageJson.scripts['component:delete'] = 'slice component delete';
33
-
34
- // Main repository commands (most used shortcuts)
35
- projectPackageJson.scripts['get'] = 'slice get';
36
- projectPackageJson.scripts['browse'] = 'slice browse';
37
- projectPackageJson.scripts['sync'] = 'slice sync';
38
-
39
- // Utility commands
40
- projectPackageJson.scripts['slice:version'] = 'slice version';
41
- projectPackageJson.scripts['slice:update'] = 'slice update';
42
-
43
- // Legacy commands - mantener por compatibilidad temporal
44
- projectPackageJson.scripts['slice:init'] = 'slice init';
45
- projectPackageJson.scripts['slice:start'] = 'slice start';
46
- projectPackageJson.scripts['slice:dev'] = 'slice dev';
47
- projectPackageJson.scripts['slice:create'] = 'slice component create';
48
- projectPackageJson.scripts['slice:list'] = 'slice component list';
49
- projectPackageJson.scripts['slice:delete'] = 'slice component delete';
50
- projectPackageJson.scripts['slice:get'] = 'slice get';
51
- projectPackageJson.scripts['slice:browse'] = 'slice browse';
52
- projectPackageJson.scripts['slice:sync'] = 'slice sync';
53
- projectPackageJson.scripts['run'] = 'slice dev';
54
-
55
- // Module configuration
56
- projectPackageJson.type = 'module';
57
- projectPackageJson.engines = {
58
- "node": ">=20.0.0"
59
- };
60
-
61
- // Write the new content to package.json
62
- return fs.promises.writeFile(projectPackageJsonPath, JSON.stringify(projectPackageJson, null, 2), 'utf8');
63
- })
64
- .then(() => {
65
- console.log('✅ SliceJS CLI configured successfully');
66
- console.log('\n🎯 New recommended commands:');
67
- console.log(' slice dev - Start development server');
68
- console.log(' slice get Button - Get components from repository');
69
- console.log(' slice browse - View available components');
70
- console.log(' slice component create - Create local component');
71
- console.log('\n📦 Available npm scripts:');
72
- console.log(' npm run dev - Start development server');
73
- console.log(' npm run get - Install components');
74
- console.log(' npm run browse - Browse components');
75
- console.log('\n⚠️ Legacy commands (deprecated but still work):');
76
- console.log(' npm run slice:dev - Use "slice dev" instead');
77
- console.log(' npm run slice:get - Use "slice get" instead');
78
- console.log('\n💡 You can also use npx:');
79
- console.log(' npx slicejs-cli dev');
80
- console.log('\n📘 Documentation: https://slice-js-docs.vercel.app/');
81
- })
82
- .catch(err => {
83
- if (err.code === 'ENOENT') {
84
- // The package.json file doesn't exist, so we create a new one with the commands
85
- const defaultPackageJson = {
86
- name: projectName,
87
- version: '1.0.0',
88
- description: 'Slice.js project',
89
- main: 'api/index.js',
90
- scripts: {
91
- // Main workflow commands
92
- 'dev': 'slice dev',
93
- 'start': 'slice start',
94
-
95
- // Component management
96
- 'component:create': 'slice component create',
97
- 'component:list': 'slice component list',
98
- 'component:delete': 'slice component delete',
99
-
100
- // Repository commands
101
- 'get': 'slice get',
102
- 'browse': 'slice browse',
103
- 'sync': 'slice sync',
104
-
105
- // Utility
106
- 'slice:version': 'slice version',
107
- 'slice:update': 'slice update',
108
-
109
- // Legacy commands (for compatibility)
110
- 'slice:init': 'slice init',
111
- 'slice:start': 'slice start',
112
- 'slice:dev': 'slice dev',
113
- 'slice:create': 'slice component create',
114
- 'slice:list': 'slice component list',
115
- 'slice:delete': 'slice component delete',
116
- 'slice:get': 'slice get',
117
- 'slice:browse': 'slice browse',
118
- 'slice:sync': 'slice sync',
119
- 'run': 'slice dev'
120
- },
121
- type: 'module',
122
- engines: {
123
- "node": ">=20.0.0"
124
- }
125
- };
126
-
127
- return fs.promises.writeFile(projectPackageJsonPath, JSON.stringify(defaultPackageJson, null, 2), 'utf8');
128
- } else {
129
- throw err;
130
- }
131
- })
132
- .then(() => {
133
- console.log('✅ SliceJS CLI commands configured successfully');
134
- console.log('\n🎯 Simplified development workflow:');
135
- console.log(' slice dev → Start development server');
136
- console.log(' slice get Button → Install components');
137
- console.log(' slice browse → View available components');
138
- console.log('\n🔧 Benefits:');
139
- console.log(' • Simple and direct commands');
140
- console.log(' • Can be used globally or with npx');
141
- console.log(' • Legacy npm scripts still work for compatibility');
142
- })
143
- .catch(err => {
144
- console.error('❌ Error setting up package.json:', err.message);
145
- process.exit(1);
146
- });
9
+ const isGlobal = process.env.npm_config_global === 'true';
10
+ const initCwd = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : null;
11
+ const targetRoot = initCwd || path.resolve(__dirname, '../../');
12
+ const projectPackageJsonPath = path.join(targetRoot, 'package.json');
13
+
14
+ if (isGlobal) {
15
+ console.log('ℹ️ Instalación global detectada de slicejs-cli.');
16
+ console.log(' Omite configuración de scripts. Usa el binario directamente:');
17
+ console.log(' slice dev');
18
+ console.log(' slice get Button');
19
+ process.exit(0);
20
+ }
21
+
22
+ console.log('ℹ️ Instalación local detectada de slicejs-cli.');
23
+ console.log(' Se omite configuración automática de scripts en postinstall.');
24
+ console.log(' Usa "slice init" para configurar los scripts del proyecto.');
25
+ process.exit(0);