g360-cli 1.14.0 → 1.15.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.
- package/README.md +72 -6
- package/package.json +71 -71
- package/src/assets/config/g360-skills.json +126 -0
- package/src/assets/config/project-types.json +8 -0
- package/src/assets/snippets/snippets.json +4 -0
- package/src/assets/templates/lit-web/src/index.js +1 -1
- package/src/assets/templates/python-cli/src/core/__init__.py +0 -0
- package/src/assets/templates/python-flet/pyproject.toml +1 -0
- package/src/assets/templates/python-flet/src/core/skill.json +1 -1
- package/src/assets/templates/python-flet-migrate/pyproject.toml +1 -3
- package/src/assets/templates/python-flet-polished/src/core/skill.json +16 -17
- package/src/assets/templates/solid-web/src/components/App.jsx +2 -2
- package/src/commands/clean.js +0 -12
- package/src/commands/docs.js +105 -1
- package/src/commands/ingest.js +11 -61
- package/src/commands/init.js +1 -1
- package/src/commands/lint.js +35 -77
- package/src/commands/scan.js +9 -37
- package/src/commands/validate.js +6 -36
- package/src/lib/file-utils.js +89 -2
- package/src/lib/python-runner.js +77 -0
- package/src/assets/templates/python-cli/package.json +0 -7
- /package/src/assets/config/{skills.json → agent-skills.json} +0 -0
package/src/lib/file-utils.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
const IGNORE_DIRS = ['node_modules', '.git', 'dist', 'build', '.next', 'out', '.nuxt', 'coverage', '.cache', '.svelte-kit', '__pycache__', '.pytest_cache'];
|
|
4
|
+
const IGNORE_DIRS = ['node_modules', '.git', 'dist', 'build', '.next', 'out', '.nuxt', 'coverage', '.cache', '.svelte-kit', '__pycache__', '.pytest_cache', 'g360'];
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Obtiene todos los archivos relativos de un directorio (recursivo)
|
|
8
|
+
* @param {string} dir - Directorio raiz
|
|
9
|
+
* @param {string} baseDir - Directorio base para paths relativos
|
|
10
|
+
* @returns {Promise<string[]>} Lista de paths relativos
|
|
11
|
+
*/
|
|
6
12
|
export async function getAllFiles(dir, baseDir = dir) {
|
|
7
13
|
const files = [];
|
|
8
14
|
|
|
@@ -11,7 +17,7 @@ export async function getAllFiles(dir, baseDir = dir) {
|
|
|
11
17
|
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
12
18
|
|
|
13
19
|
for (const item of items) {
|
|
14
|
-
if (IGNORE_DIRS.includes(item.name)) continue;
|
|
20
|
+
if (IGNORE_DIRS.includes(item.name) || item.name.startsWith('.')) continue;
|
|
15
21
|
|
|
16
22
|
const fullPath = path.join(dir, item.name);
|
|
17
23
|
const relativePath = path.relative(baseDir, fullPath).replace(/\\/g, '/');
|
|
@@ -25,3 +31,84 @@ export async function getAllFiles(dir, baseDir = dir) {
|
|
|
25
31
|
|
|
26
32
|
return files;
|
|
27
33
|
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Walk recursivo de proyecto con callbacks por tipo de archivo
|
|
37
|
+
* Consolidacion de los walk() duplicados en lint.js, docs.js, clean.js
|
|
38
|
+
* @param {string} dir - Directorio a escanear
|
|
39
|
+
* @param {Object} callbacks - Callbacks por extension
|
|
40
|
+
* @param {Function} callbacks.onJs - Callback para archivos .js/.jsx
|
|
41
|
+
* @param {Function} callbacks.onPy - Callback para archivos .py
|
|
42
|
+
* @param {Function} callbacks.onFile - Callback para cualquier archivo (recibe fullPath, relativePath)
|
|
43
|
+
* @param {Function} callbacks.onDir - Callback para directorios (recibe relativePath)
|
|
44
|
+
* @param {Object} options - Opciones extras
|
|
45
|
+
* @param {number} options.maxDepth - Profundidad maxima (default: 10)
|
|
46
|
+
* @param {string[]} options.skipDirs - Directorios adicionales a ignorar
|
|
47
|
+
*/
|
|
48
|
+
export function walkProject(dir, callbacks, options = {}) {
|
|
49
|
+
const { maxDepth = 10, skipDirs = [] } = options;
|
|
50
|
+
const allSkip = [...IGNORE_DIRS, ...skipDirs];
|
|
51
|
+
|
|
52
|
+
function walk(d, depth) {
|
|
53
|
+
if (depth > maxDepth) return;
|
|
54
|
+
const items = fs.readdirSync(d, { withFileTypes: true });
|
|
55
|
+
|
|
56
|
+
for (const item of items) {
|
|
57
|
+
if (item.name.startsWith('.') || allSkip.includes(item.name)) continue;
|
|
58
|
+
|
|
59
|
+
const fullPath = path.join(d, item.name);
|
|
60
|
+
const relPath = path.relative(dir, fullPath).replace(/\\/g, '/');
|
|
61
|
+
|
|
62
|
+
if (item.isDirectory()) {
|
|
63
|
+
if (callbacks.onDir) callbacks.onDir(relPath, fullPath);
|
|
64
|
+
walk(fullPath, depth + 1);
|
|
65
|
+
} else if (item.isFile()) {
|
|
66
|
+
if (callbacks.onFile) callbacks.onFile(fullPath, relPath, item.name);
|
|
67
|
+
|
|
68
|
+
if (item.name.endsWith('.js') && !item.name.endsWith('.test.js') && !item.name.endsWith('.spec.js')) {
|
|
69
|
+
if (callbacks.onJs) callbacks.onJs(fullPath, relPath);
|
|
70
|
+
}
|
|
71
|
+
if (item.name.endsWith('.jsx') && !item.name.endsWith('.test.jsx')) {
|
|
72
|
+
if (callbacks.onJs) callbacks.onJs(fullPath, relPath);
|
|
73
|
+
}
|
|
74
|
+
if (item.name.endsWith('.ts') && !item.name.endsWith('.test.ts')) {
|
|
75
|
+
if (callbacks.onJs) callbacks.onJs(fullPath, relPath);
|
|
76
|
+
}
|
|
77
|
+
if (item.name.endsWith('.tsx') && !item.name.endsWith('.test.tsx')) {
|
|
78
|
+
if (callbacks.onJs) callbacks.onJs(fullPath, relPath);
|
|
79
|
+
}
|
|
80
|
+
if (item.name.endsWith('.py')) {
|
|
81
|
+
if (callbacks.onPy) callbacks.onPy(fullPath, relPath);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
walk(dir, 0);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Obtiene archivos JS/TS de un proyecto (sin tests)
|
|
92
|
+
* @param {string} dir - Directorio del proyecto
|
|
93
|
+
* @returns {string[]} Lista de paths absolutos
|
|
94
|
+
*/
|
|
95
|
+
export function getJsFiles(dir) {
|
|
96
|
+
const files = [];
|
|
97
|
+
walkProject(dir, {
|
|
98
|
+
onJs: (fullPath) => files.push(fullPath),
|
|
99
|
+
});
|
|
100
|
+
return files;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Obtiene archivos Python de un proyecto (sin __init__.py)
|
|
105
|
+
* @param {string} dir - Directorio del proyecto
|
|
106
|
+
* @returns {string[]} Lista de paths absolutos
|
|
107
|
+
*/
|
|
108
|
+
export function getPyFiles(dir) {
|
|
109
|
+
const files = [];
|
|
110
|
+
walkProject(dir, {
|
|
111
|
+
onPy: (fullPath) => files.push(fullPath),
|
|
112
|
+
});
|
|
113
|
+
return files;
|
|
114
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file python-runner.js
|
|
3
|
+
* @description Runner consolidado para ejecutar codigo Python desde Node.js
|
|
4
|
+
* @author @carloscus
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ejecuta codigo Python y retorna stdout/stderr
|
|
13
|
+
* @param {string} code - Codigo Python a ejecutar
|
|
14
|
+
* @param {Object} options - Opciones opcionales
|
|
15
|
+
* @param {string} options.pythonPath - Ruta al interprete Python
|
|
16
|
+
* @param {number} options.timeout - Timeout en ms
|
|
17
|
+
* @returns {Promise<{stdout: string, stderr: string}>}
|
|
18
|
+
*/
|
|
19
|
+
export function runPython(code, options = {}) {
|
|
20
|
+
const { pythonPath, timeout } = options;
|
|
21
|
+
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const pyExec = pythonPath || process.env.PYTHON || 'python3';
|
|
24
|
+
const proc = spawn(pyExec, ['-c', code], {
|
|
25
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
let stdout = '';
|
|
29
|
+
let stderr = '';
|
|
30
|
+
let timer;
|
|
31
|
+
|
|
32
|
+
if (timeout) {
|
|
33
|
+
timer = setTimeout(() => {
|
|
34
|
+
proc.kill();
|
|
35
|
+
reject(new Error(`Python timeout despues de ${timeout}ms`));
|
|
36
|
+
}, timeout);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
proc.stdout?.on('data', (data) => { stdout += data.toString(); });
|
|
40
|
+
proc.stderr?.on('data', (data) => { stderr += data.toString(); });
|
|
41
|
+
|
|
42
|
+
proc.on('close', (code) => {
|
|
43
|
+
if (timer) clearTimeout(timer);
|
|
44
|
+
if (code === 0) {
|
|
45
|
+
resolve({ stdout, stderr });
|
|
46
|
+
} else {
|
|
47
|
+
reject(new Error(stderr || `Python termino con codigo ${code}`));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
proc.on('error', (err) => {
|
|
52
|
+
if (timer) clearTimeout(timer);
|
|
53
|
+
reject(new Error(`No se pudo ejecutar Python: ${err.message}`));
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Ejecuta codigo Python y retorna solo stdout
|
|
60
|
+
* @param {string} code - Codigo Python a ejecutar
|
|
61
|
+
* @param {Object} options - Mismas opciones que runPython
|
|
62
|
+
* @returns {Promise<string>} stdout
|
|
63
|
+
*/
|
|
64
|
+
export async function runPythonStdout(code, options = {}) {
|
|
65
|
+
const { stdout } = await runPython(code, options);
|
|
66
|
+
return stdout;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Crea el prefijo de Python para importar desde src/py/src
|
|
71
|
+
* @param {string} commandDir - Directorio del comando que invoca (usar __dirname o import.meta)
|
|
72
|
+
* @returns {string} Lineas Python para sys.path.insert
|
|
73
|
+
*/
|
|
74
|
+
export function g360CorePath(commandDir) {
|
|
75
|
+
const pySrc = path.join(commandDir, '..', 'py', 'src').replace(/\\/g, '\\\\');
|
|
76
|
+
return `import sys\nsys.path.insert(0, '${pySrc}')`;
|
|
77
|
+
}
|
|
File without changes
|