g360-cli 1.12.0 → 1.13.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.
@@ -1,260 +0,0 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- import os from 'os';
4
- import { logger } from './logger.js';
5
-
6
- /**
7
- * @typedef {Object} GlobalConfig
8
- * @property {string} defaultSkill - Skill por defecto
9
- * @property {string} defaultTemplate - Plantilla por defecto
10
- * @property {Object} preferences - Preferencias del usuario
11
- * @property {string[]} recentProjects - Proyectos recientes
12
- * @property {Object} cache - Configuración de caché
13
- */
14
-
15
- /**
16
- * Ruta del directorio de configuración global
17
- * @type {string}
18
- */
19
- const G360_CONFIG_DIR = path.join(os.homedir(), '.g360');
20
-
21
- /**
22
- * Ruta del archivo de configuración global
23
- * @type {string}
24
- */
25
- const G360_CONFIG_FILE = path.join(G360_CONFIG_DIR, 'config.json');
26
-
27
- /**
28
- * Configuración por defecto
29
- * @type {GlobalConfig}
30
- */
31
- const DEFAULT_CONFIG = {
32
- defaultSkill: 'corporativo-movil',
33
- defaultTemplate: 'web-pwa',
34
- preferences: {
35
- language: 'es',
36
- theme: 'dark',
37
- verbose: false
38
- },
39
- recentProjects: [],
40
- cache: {
41
- enabled: true,
42
- maxSize: 100
43
- }
44
- };
45
-
46
- /**
47
- * Módulo de configuración global para G360-CLI
48
- * @namespace globalConfig
49
- */
50
- export const globalConfig = {
51
- /**
52
- * Obtiene la ruta del directorio de configuración
53
- * @returns {string} Ruta del directorio de configuración
54
- * @example
55
- * const configDir = globalConfig.getConfigDir();
56
- * console.log('Config dir:', configDir);
57
- */
58
- getConfigDir() {
59
- return G360_CONFIG_DIR;
60
- },
61
-
62
- /**
63
- * Obtiene la ruta del archivo de configuración
64
- * @returns {string} Ruta del archivo de configuración
65
- * @example
66
- * const configFile = globalConfig.getConfigFile();
67
- * console.log('Config file:', configFile);
68
- */
69
- getConfigFile() {
70
- return G360_CONFIG_FILE;
71
- },
72
-
73
- /**
74
- * Inicializa el directorio de configuración global
75
- * @returns {Promise<void>}
76
- * @example
77
- * await globalConfig.init();
78
- */
79
- async init() {
80
- try {
81
- await fs.ensureDir(G360_CONFIG_DIR);
82
-
83
- if (!fs.existsSync(G360_CONFIG_FILE)) {
84
- await this.save(DEFAULT_CONFIG);
85
- logger.info('Global config initialized', { path: G360_CONFIG_FILE });
86
- }
87
- } catch (error) {
88
- logger.error('Failed to initialize global config', { error: error.message });
89
- throw error;
90
- }
91
- },
92
-
93
- /**
94
- * Carga la configuración global
95
- * @returns {Promise<GlobalConfig>} Configuración global cargada
96
- * @example
97
- * const config = await globalConfig.load();
98
- * console.log('Default skill:', config.defaultSkill);
99
- */
100
- async load() {
101
- try {
102
- if (!fs.existsSync(G360_CONFIG_FILE)) {
103
- await this.init();
104
- return { ...DEFAULT_CONFIG };
105
- }
106
-
107
- const config = await fs.readJson(G360_CONFIG_FILE);
108
- return { ...DEFAULT_CONFIG, ...config };
109
- } catch (error) {
110
- logger.error('Failed to load global config', { error: error.message });
111
- return { ...DEFAULT_CONFIG };
112
- }
113
- },
114
-
115
- /**
116
- * Guarda la configuración global
117
- * @param {GlobalConfig} config - Configuración a guardar
118
- * @returns {Promise<void>}
119
- * @example
120
- * await globalConfig.save({ defaultSkill: 'moderno' });
121
- */
122
- async save(config) {
123
- try {
124
- await fs.ensureDir(G360_CONFIG_DIR);
125
- await fs.writeJson(G360_CONFIG_FILE, config, { spaces: 2 });
126
- logger.debug('Global config saved');
127
- } catch (error) {
128
- logger.error('Failed to save global config', { error: error.message });
129
- throw error;
130
- }
131
- },
132
-
133
- /**
134
- * Obtiene un valor de configuración específico
135
- * @param {string} key - Clave de configuración (notación de puntos)
136
- * @param {*} defaultValue - Valor por defecto si no existe
137
- * @returns {Promise<*>} Valor de configuración
138
- * @example
139
- * const skill = await globalConfig.get('defaultSkill');
140
- * const theme = await globalConfig.get('preferences.theme', 'dark');
141
- */
142
- async get(key, defaultValue = undefined) {
143
- const config = await this.load();
144
-
145
- const keys = key.split('.');
146
- let value = config;
147
-
148
- for (const k of keys) {
149
- if (value && typeof value === 'object' && k in value) {
150
- value = value[k];
151
- } else {
152
- return defaultValue;
153
- }
154
- }
155
-
156
- return value;
157
- },
158
-
159
- /**
160
- * Establece un valor de configuración específico
161
- * @param {string} key - Clave de configuración (notación de puntos)
162
- * @param {*} value - Valor a establecer
163
- * @returns {Promise<void>}
164
- * @example
165
- * await globalConfig.set('defaultSkill', 'moderno');
166
- * await globalConfig.set('preferences.theme', 'light');
167
- */
168
- async set(key, value) {
169
- const config = await this.load();
170
-
171
- const keys = key.split('.');
172
- let current = config;
173
-
174
- for (let i = 0; i < keys.length - 1; i++) {
175
- const k = keys[i];
176
- if (!current[k] || typeof current[k] !== 'object') {
177
- current[k] = {};
178
- }
179
- current = current[k];
180
- }
181
-
182
- current[keys[keys.length - 1]] = value;
183
- await this.save(config);
184
- },
185
-
186
- /**
187
- * Agrega un proyecto a la lista de proyectos recientes
188
- * @param {string} projectPath - Ruta del proyecto
189
- * @param {Object} metadata - Metadatos del proyecto
190
- * @returns {Promise<void>}
191
- * @example
192
- * await globalConfig.addRecentProject('/my/project', {
193
- * template: 'web-pwa',
194
- * skill: 'corporativo-movil'
195
- * });
196
- */
197
- async addRecentProject(projectPath, metadata = {}) {
198
- const config = await this.load();
199
-
200
- // Eliminar el proyecto si ya existe
201
- config.recentProjects = config.recentProjects.filter(
202
- p => p.path !== projectPath
203
- );
204
-
205
- // Agregar al inicio
206
- config.recentProjects.unshift({
207
- path: projectPath,
208
- lastAccessed: new Date().toISOString(),
209
- ...metadata
210
- });
211
-
212
- // Mantener solo los últimos 10 proyectos
213
- config.recentProjects = config.recentProjects.slice(0, 10);
214
-
215
- await this.save(config);
216
- logger.debug('Project added to recent projects', { path: projectPath });
217
- },
218
-
219
- /**
220
- * Obtiene la lista de proyectos recientes
221
- * @returns {Promise<Array>} Lista de proyectos recientes
222
- * @example
223
- * const recent = await globalConfig.getRecentProjects();
224
- * recent.forEach(project => console.log(project.path));
225
- */
226
- async getRecentProjects() {
227
- const config = await this.load();
228
- return config.recentProjects || [];
229
- },
230
-
231
- /**
232
- * Limpia la configuración global
233
- * @returns {Promise<void>}
234
- * @example
235
- * await globalConfig.clear();
236
- */
237
- async clear() {
238
- try {
239
- if (fs.existsSync(G360_CONFIG_FILE)) {
240
- await fs.remove(G360_CONFIG_FILE);
241
- logger.info('Global config cleared');
242
- }
243
- } catch (error) {
244
- logger.error('Failed to clear global config', { error: error.message });
245
- throw error;
246
- }
247
- },
248
-
249
- /**
250
- * Verifica si la configuración global existe
251
- * @returns {boolean} true si existe, false en caso contrario
252
- * @example
253
- * if (await globalConfig.exists()) {
254
- * console.log('Config exists');
255
- * }
256
- */
257
- async exists() {
258
- return fs.existsSync(G360_CONFIG_FILE);
259
- }
260
- };
package/src/lib/i18n.js DELETED
@@ -1,238 +0,0 @@
1
- /**
2
- * @file i18n.js
3
- * @description Sistema de internacionalización para G360-CLI
4
- */
5
-
6
- /**
7
- * Traducciones disponibles
8
- * @type {Object.<string, Object.<string, string>>}
9
- */
10
- const translations = {
11
- es: {
12
- // Comandos
13
- 'command.init.title': '🚀 Inicialización de Proyecto G360',
14
- 'command.init.project': 'Proyecto',
15
- 'command.init.template': 'Plantilla',
16
- 'command.init.skill': 'Skill',
17
- 'command.init.target': 'Destino',
18
- 'command.init.success': '✅ Proyecto creado exitosamente',
19
- 'command.init.portable': '📦 Versión portable habilitada',
20
- 'command.init.next_steps': 'Próximos pasos',
21
-
22
- 'command.list.title': '📋 Assets G360',
23
- 'command.list.templates': '📁 Plantillas',
24
- 'command.list.components': '🧩 Componentes',
25
- 'command.list.skills': '⚡ Skills',
26
- 'command.list.snippets': '📝 Snippets',
27
- 'command.list.no_templates': 'No se encontraron plantillas',
28
- 'command.list.no_components': 'No se encontraron componentes',
29
- 'command.list.no_skills': 'No se encontraron skills',
30
- 'command.list.no_snippets': 'No se encontraron snippets',
31
-
32
- 'command.set-skill.title': '🎨 Selector de Skill G360',
33
- 'command.set-skill.success': '✅ Skill configurado correctamente',
34
- 'command.set-skill.not_found': '❌ Skill no encontrado',
35
- 'command.set-skill.already_exists': '⚠️ El proyecto ya tiene un skill configurado',
36
- 'command.set-skill.use_force': 'Usa --force para sobrescribir',
37
-
38
- 'command.audit.title': '🔍 Auditoría de Proyecto G360',
39
- 'command.audit.results': '📊 Resultados de Auditoría',
40
- 'command.audit.passed': 'Pasaron',
41
- 'command.audit.failed': 'Fallaron',
42
- 'command.audit.warnings': 'Advertencias',
43
- 'command.audit.issues': 'Issues Encontrados',
44
- 'command.audit.compliant': '✅ El proyecto es compliant con G360',
45
- 'command.audit.issues_found': '⚠️ Algunos issues necesitan atención',
46
-
47
- 'command.health.title': '🏥 Verificación de Salud G360',
48
- 'command.health.status': 'Estado del Sistema',
49
- 'command.health.healthy': '✅ El sistema está saludable',
50
- 'command.health.failed': '❌ Algunos checks fallaron',
51
-
52
- 'command.clean.title': '🧹 Limpieza de Proyecto G360',
53
- 'command.clean.preview': '📋 DRY RUN - No se eliminarán archivos',
54
- 'command.clean.success': '✅ Limpieza completada',
55
-
56
- // Errores
57
- 'error.templates_not_found': '❌ Plantillas no encontradas. Ejecuta: g360 update',
58
- 'error.template_not_found': '❌ Plantilla no encontrada',
59
- 'error.directory_exists': '❌ El directorio ya existe. Usa --force para sobrescribir',
60
- 'error.path_not_found': '❌ Ruta no encontrada',
61
- 'error.config_not_found': '❌ No se pudo cargar la configuración de skills',
62
-
63
- // General
64
- 'general.available': 'Disponibles',
65
- 'general.device': 'Dispositivo',
66
- 'general.description': 'Descripción',
67
- 'general.language': 'Lenguaje',
68
- 'general.loading': 'Cargando...',
69
- 'general.done': 'Completado',
70
- 'general.cancelled': 'Cancelado',
71
- 'general.error': 'Error',
72
- 'general.warning': 'Advertencia',
73
- 'general.info': 'Información',
74
- 'general.success': 'Éxito'
75
- },
76
-
77
- en: {
78
- // Commands
79
- 'command.init.title': '🚀 G360 Project Initialization',
80
- 'command.init.project': 'Project',
81
- 'command.init.template': 'Template',
82
- 'command.init.skill': 'Skill',
83
- 'command.init.target': 'Target',
84
- 'command.init.success': '✅ Project created successfully',
85
- 'command.init.portable': '📦 Portable version enabled',
86
- 'command.init.next_steps': 'Next steps',
87
-
88
- 'command.list.title': '📋 G360 Assets',
89
- 'command.list.templates': '📁 Templates',
90
- 'command.list.components': '🧩 Components',
91
- 'command.list.skills': '⚡ Skills',
92
- 'command.list.snippets': '📝 Snippets',
93
- 'command.list.no_templates': 'No templates found',
94
- 'command.list.no_components': 'No components found',
95
- 'command.list.no_skills': 'No skills found',
96
- 'command.list.no_snippets': 'No snippets found',
97
-
98
- 'command.set-skill.title': '🎨 G360 Skill Selector',
99
- 'command.set-skill.success': '✅ Skill configured successfully',
100
- 'command.set-skill.not_found': '❌ Skill not found',
101
- 'command.set-skill.already_exists': '⚠️ Project already has a skill configured',
102
- 'command.set-skill.use_force': 'Use --force to overwrite',
103
-
104
- 'command.audit.title': '🔍 G360 Project Audit',
105
- 'command.audit.results': '📊 Audit Results',
106
- 'command.audit.passed': 'Passed',
107
- 'command.audit.failed': 'Failed',
108
- 'command.audit.warnings': 'Warnings',
109
- 'command.audit.issues': 'Issues Found',
110
- 'command.audit.compliant': '✅ Project is G360 compliant',
111
- 'command.audit.issues_found': '⚠️ Some issues need attention',
112
-
113
- 'command.health.title': '🏥 G360 Health Check',
114
- 'command.health.status': 'System Status',
115
- 'command.health.healthy': '✅ System is healthy',
116
- 'command.health.failed': '❌ Some checks failed',
117
-
118
- 'command.clean.title': '🧹 G360 Project Clean',
119
- 'command.clean.preview': '📋 DRY RUN - No files will be removed',
120
- 'command.clean.success': '✅ Cleanup completed',
121
-
122
- // Errors
123
- 'error.templates_not_found': '❌ Templates not found. Run: g360 update',
124
- 'error.template_not_found': '❌ Template not found',
125
- 'error.directory_exists': '❌ Directory already exists. Use --force to overwrite',
126
- 'error.path_not_found': '❌ Path not found',
127
- 'error.config_not_found': '❌ Could not load skills configuration',
128
-
129
- // General
130
- 'general.available': 'Available',
131
- 'general.device': 'Device',
132
- 'general.description': 'Description',
133
- 'general.language': 'Language',
134
- 'general.loading': 'Loading...',
135
- 'general.done': 'Done',
136
- 'general.cancelled': 'Cancelled',
137
- 'general.error': 'Error',
138
- 'general.warning': 'Warning',
139
- 'general.info': 'Info',
140
- 'general.success': 'Success'
141
- }
142
- };
143
-
144
- /**
145
- * Idioma actual
146
- * @type {string}
147
- */
148
- let currentLanguage = 'es';
149
-
150
- /**
151
- * Módulo de internacionalización para G360-CLI
152
- * @namespace i18n
153
- */
154
- export const i18n = {
155
- /**
156
- * Establece el idioma actual
157
- * @param {string} language - Código de idioma ('es' | 'en')
158
- * @returns {void}
159
- * @example
160
- * i18n.setLanguage('en');
161
- */
162
- setLanguage(language) {
163
- if (translations[language]) {
164
- currentLanguage = language;
165
- } else {
166
- console.warn(`Language '${language}' not supported, using 'es'`);
167
- }
168
- },
169
-
170
- /**
171
- * Obtiene el idioma actual
172
- * @returns {string} Código de idioma actual
173
- * @example
174
- * const lang = i18n.getLanguage();
175
- */
176
- getLanguage() {
177
- return currentLanguage;
178
- },
179
-
180
- /**
181
- * Traduce una clave de texto
182
- * @param {string} key - Clave de traducción
183
- * @param {Object} [params] - Parámetros para interpolación
184
- * @returns {string} Texto traducido
185
- * @example
186
- * const text = i18n.t('command.init.success');
187
- * const text = i18n.t('command.init.project', { name: 'my-project' });
188
- */
189
- t(key, params = {}) {
190
- const lang = translations[currentLanguage] || translations.es;
191
- let text = lang[key] || translations.es[key] || key;
192
-
193
- // Interpolación de parámetros
194
- Object.keys(params).forEach(param => {
195
- text = text.replace(`{${param}}`, params[param]);
196
- });
197
-
198
- return text;
199
- },
200
-
201
- /**
202
- * Verifica si una clave de traducción existe
203
- * @param {string} key - Clave de traducción
204
- * @returns {boolean} true si existe, false en caso contrario
205
- * @example
206
- * if (i18n.has('command.init.success')) {
207
- * console.log(i18n.t('command.init.success'));
208
- * }
209
- */
210
- has(key) {
211
- const lang = translations[currentLanguage] || translations.es;
212
- return key in lang;
213
- },
214
-
215
- /**
216
- * Obtiene todos los idiomas disponibles
217
- * @returns {string[]} Lista de códigos de idioma
218
- * @example
219
- * const languages = i18n.getAvailableLanguages();
220
- * console.log('Available languages:', languages);
221
- */
222
- getAvailableLanguages() {
223
- return Object.keys(translations);
224
- },
225
-
226
- /**
227
- * Obtiene las traducciones para un idioma específico
228
- * @param {string} language - Código de idioma
229
- * @returns {Object|null} Objeto de traducciones o null si no existe
230
- * @example
231
- * const esTranslations = i18n.getTranslations('es');
232
- */
233
- getTranslations(language) {
234
- return translations[language] || null;
235
- }
236
- };
237
-
238
- export default i18n;
@@ -1,89 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Utilidad para obtener la ruta al módulo Python empaquetado.
4
- * Funciona tanto en desarrollo como en ejecutables empaquetados con pkg.
5
- */
6
-
7
- import path from 'path';
8
- import { fileURLToPath } from 'url';
9
- import fs from 'fs-extra';
10
-
11
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
-
13
- /**
14
- * Retorna la ruta al directorio src/g360_core del módulo Python.
15
- */
16
- export function getPythonModulePath() {
17
- // Ruta de desarrollo: py/src/g360_core relativo a este archivo
18
- const devPath = path.join(__dirname, '..', 'py', 'src');
19
- if (fs.existsSync(devPath)) {
20
- return devPath;
21
- }
22
-
23
- // En pkg (ejecutable empaquetado)
24
- const basePath = process.execPath || process.argv[0];
25
- const pkgPath = path.join(basePath, '..', 'resources', 'py', 'src');
26
- if (fs.existsSync(pkgPath)) {
27
- return pkgPath;
28
- }
29
-
30
- // Fallback: directorio actual
31
- const cwdPath = path.join(process.cwd(), 'py', 'src');
32
- if (fs.existsSync(cwdPath)) {
33
- return cwdPath;
34
- }
35
-
36
- return devPath;
37
- }
38
-
39
- /**
40
- * Genera código Python que configura sys.path correctamente.
41
- */
42
- export function wrapPythonCode(pyCode) {
43
- const modulePath = getPythonModulePath().replace(/\\/g, '\\\\');
44
-
45
- return `
46
- import sys
47
- import os
48
- from pathlib import Path
49
-
50
- module_path = r"${modulePath}"
51
- if module_path not in sys.path:
52
- sys.path.insert(0, module_path)
53
-
54
- ${pyCode}
55
- `;
56
- }
57
-
58
- /**
59
- * Ejecuta código Python y retorna su salida.
60
- */
61
- export async function runPython(pyCode) {
62
- const fullCode = wrapPythonCode(pyCode);
63
- const pyExec = process.env.PYTHON || 'python3';
64
-
65
- const { spawn } = await import('child_process');
66
- const proc = spawn(pyExec, ['-c', fullCode], {
67
- stdio: ['ignore', 'pipe', 'pipe'],
68
- env: { ...process.env, PYTHONIOENCODING: 'utf-8' },
69
- });
70
-
71
- let stdout = '';
72
- let stderr = '';
73
-
74
- await new Promise((resolve, reject) => {
75
- proc.stdout?.on('data', (data) => { stdout += data.toString(); });
76
- proc.stderr?.on('data', (data) => { stderr += data.toString(); });
77
-
78
- proc.on('close', (code) => {
79
- if (code === 0) resolve();
80
- else reject(new Error(stderr || `Python código ${code}`));
81
- });
82
-
83
- proc.on('error', (err) => {
84
- reject(new Error(`Python no disponible: ${err.message}`));
85
- });
86
- });
87
-
88
- return { stdout, stderr };
89
- }