g360-cli 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +209 -5
- package/package.json +15 -8
- package/src/assets/brand/brand.json +43 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_borde.png +0 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_borde.svg +9 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_solid.png +0 -0
- package/src/assets/brand/cipsa/logotypes/Logo_cipsa_solid.svg +9 -0
- package/src/assets/brand/g360/logotypes/logo-g360-dark.svg +19 -0
- package/src/assets/brand/g360/logotypes/logo-g360-light.svg +19 -0
- package/src/assets/brand/g360/logotypes/logo_g360_dark_b64.txt +1 -0
- package/src/assets/brand/g360/logotypes/logo_g360_light_b64.txt +1 -0
- package/src/assets/config/g360-skills.json +112 -0
- package/src/assets/config/project-types.json +16 -0
- package/src/assets/config/skills.json +12 -0
- package/src/assets/snippets/snippets.json +293 -24
- package/src/assets/templates/lit-web/src/core/skill.json +12 -5
- package/src/assets/templates/python-cli/build-portable.bat +43 -0
- package/src/assets/templates/python-cli/src/core/skill.json +25 -6
- package/src/assets/templates/python-cli/src/main.py +107 -3
- package/src/assets/templates/python-customtkinter/README.md +48 -0
- package/src/assets/templates/python-customtkinter/assets/images/logo-g360-dark.svg +19 -0
- package/src/assets/templates/python-customtkinter/assets/images/logo-g360-light.svg +19 -0
- package/src/assets/templates/python-customtkinter/build.bat +50 -0
- package/src/assets/templates/python-customtkinter/pyproject.toml +26 -0
- package/src/assets/templates/python-customtkinter/run.bat +20 -0
- package/src/assets/templates/python-customtkinter/src/core/g360_theme.py +101 -0
- package/src/assets/templates/python-customtkinter/src/core/skill.json +35 -0
- package/src/assets/templates/python-customtkinter/src/main.py +103 -0
- package/src/assets/templates/python-flet/README.md +89 -0
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.png +0 -0
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_borde.svg +9 -0
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.png +0 -0
- package/src/assets/templates/python-flet/assets/images/Logo_cipsa_solid.svg +9 -0
- package/src/assets/templates/python-flet/assets/images/logo-g360-dark.svg +19 -0
- package/src/assets/templates/python-flet/assets/images/logo-g360-light.svg +19 -0
- package/src/assets/templates/python-flet/build.bat +36 -0
- package/src/assets/templates/python-flet/pyproject.toml +26 -0
- package/src/assets/templates/python-flet/run.bat +20 -0
- package/src/assets/templates/python-flet/src/core/__init__.py +0 -0
- package/src/assets/templates/python-flet/src/core/g360_theme.py +186 -0
- package/src/assets/templates/python-flet/src/core/skill.json +41 -0
- package/src/assets/templates/python-flet/src/export/__init__.py +0 -0
- package/src/assets/templates/python-flet/src/main.py +146 -0
- package/src/assets/templates/python-flet/src/test_app.py +107 -0
- package/src/assets/templates/python-flet/src/ui/__init__.py +0 -0
- package/src/assets/templates/python-flet-migrate/README.md +70 -0
- package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-dark.svg +19 -0
- package/src/assets/templates/python-flet-migrate/assets/images/logo-g360-light.svg +19 -0
- package/src/assets/templates/python-flet-migrate/build.bat +36 -0
- package/src/assets/templates/python-flet-migrate/pyproject.toml +26 -0
- package/src/assets/templates/python-flet-migrate/run.bat +20 -0
- package/src/assets/templates/python-flet-migrate/src/core/__init__.py +0 -0
- package/src/assets/templates/python-flet-migrate/src/core/g360_theme.py +186 -0
- package/src/assets/templates/python-flet-migrate/src/core/skill.json +34 -0
- package/src/assets/templates/python-flet-migrate/src/main.py +97 -0
- package/src/assets/templates/python-flet-migrate/src/migrate_tkinter.py +56 -0
- package/src/assets/templates/solid-web/src/core/skill.json +12 -5
- package/src/assets/templates/svelte-web/src/core/skill.json +12 -5
- package/src/assets/templates/web-pwa/index.html +2 -7
- package/src/assets/templates/web-pwa/public/favicon.svg +4 -0
- package/src/assets/templates/web-pwa/public/manifest.json +11 -0
- package/src/assets/templates/web-pwa/src/App.jsx +22 -0
- package/src/assets/templates/web-pwa/src/components/FooterSignature.jsx +9 -0
- package/src/assets/templates/web-pwa/src/components/Header.jsx +12 -0
- package/src/assets/templates/web-pwa/src/components/LoadingOverlay.jsx +10 -0
- package/src/assets/templates/web-pwa/src/core/skill.json +25 -0
- package/src/assets/templates/web-pwa/src/main.jsx +9 -0
- package/src/assets/templates/web-pwa/src/styles/main.css +133 -0
- package/src/assets/templates/web-pwa/vite.config.js +12 -0
- package/src/cli.js +8 -4
- package/src/commands/bring.js +81 -6
- package/src/commands/clean.js +51 -4
- package/src/commands/init.js +60 -8
- package/src/commands/list.js +79 -9
- package/src/commands/signature.js +12 -8
- package/src/lib/asset-validator.js +145 -0
- package/src/lib/auditor.js +48 -0
- package/src/lib/global-config.js +260 -0
- package/src/lib/i18n.js +238 -0
- package/src/lib/logger.js +100 -0
- package/src/lib/manifest.js +70 -1
- package/src/lib/validator.js +39 -0
- package/src/schemas/skills-schema.json +1 -0
- package/src/schemas/snippets-schema.json +1 -0
- package/src/assets/templates/web-pwa/app.js +0 -1
- package/src/assets/templates/web-pwa/styles.css +0 -28
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--g360-bg: #0b1220;
|
|
3
|
+
--g360-surface: #151e2e;
|
|
4
|
+
--g360-accent: #00d084;
|
|
5
|
+
--g360-text: #f0f4f8;
|
|
6
|
+
--g360-muted: #94a3b8;
|
|
7
|
+
--g360-glass: rgba(21, 30, 46, 0.75);
|
|
8
|
+
--g360-blur: 16px;
|
|
9
|
+
--g360-rounded: 16px;
|
|
10
|
+
--g360-font: system-ui, -apple-system, sans-serif;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
font-family: var(--g360-font);
|
|
17
|
+
background: var(--g360-bg);
|
|
18
|
+
color: var(--g360-text);
|
|
19
|
+
line-height: 1.6;
|
|
20
|
+
-webkit-font-smoothing: antialiased;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.app {
|
|
24
|
+
min-height: 100vh;
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.container {
|
|
30
|
+
max-width: 480px;
|
|
31
|
+
margin: 0 auto;
|
|
32
|
+
padding: 24px 16px;
|
|
33
|
+
flex: 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.g360-header {
|
|
37
|
+
background: var(--g360-surface);
|
|
38
|
+
border-bottom: 1px solid rgba(255,255,255,0.08);
|
|
39
|
+
padding: 16px 24px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.header-content {
|
|
43
|
+
max-width: 480px;
|
|
44
|
+
margin: 0 auto;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: baseline;
|
|
47
|
+
gap: 12px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.logo {
|
|
51
|
+
font-size: 24px;
|
|
52
|
+
font-weight: 800;
|
|
53
|
+
color: var(--g360-accent);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.subtitle {
|
|
57
|
+
font-size: 14px;
|
|
58
|
+
color: var(--g360-muted);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
h1 { font-size: 24px; font-weight: 700; margin-bottom: 8px; }
|
|
62
|
+
|
|
63
|
+
.muted { color: var(--g360-muted); font-size: 14px; }
|
|
64
|
+
|
|
65
|
+
.g360-footer {
|
|
66
|
+
text-align: center;
|
|
67
|
+
padding: 12px;
|
|
68
|
+
font-size: 11px;
|
|
69
|
+
color: var(--g360-muted);
|
|
70
|
+
background: var(--g360-surface);
|
|
71
|
+
border-top: 1px solid rgba(255,255,255,0.08);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.g360-loading-overlay {
|
|
75
|
+
position: fixed;
|
|
76
|
+
inset: 0;
|
|
77
|
+
background: rgba(11, 18, 32, 0.9);
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
align-items: center;
|
|
81
|
+
justify-content: center;
|
|
82
|
+
gap: 16px;
|
|
83
|
+
z-index: 1000;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.g360-loading-spinner {
|
|
87
|
+
width: 40px;
|
|
88
|
+
height: 40px;
|
|
89
|
+
border: 3px solid var(--g360-surface);
|
|
90
|
+
border-top-color: var(--g360-accent);
|
|
91
|
+
border-radius: 50%;
|
|
92
|
+
animation: spin 0.8s linear infinite;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
96
|
+
|
|
97
|
+
.g360-card {
|
|
98
|
+
background: var(--g360-surface);
|
|
99
|
+
border-radius: var(--g360-rounded);
|
|
100
|
+
padding: 16px;
|
|
101
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.g360-glass {
|
|
105
|
+
background: var(--g360-glass);
|
|
106
|
+
backdrop-filter: blur(var(--g360-blur));
|
|
107
|
+
-webkit-backdrop-filter: blur(var(--g360-blur));
|
|
108
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.g360-btn {
|
|
112
|
+
background: var(--g360-accent);
|
|
113
|
+
color: var(--g360-bg);
|
|
114
|
+
border: none;
|
|
115
|
+
border-radius: 8px;
|
|
116
|
+
padding: 10px 20px;
|
|
117
|
+
font-size: 14px;
|
|
118
|
+
font-weight: 700;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
transition: opacity 0.2s;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.g360-btn:hover { opacity: 0.85; }
|
|
124
|
+
|
|
125
|
+
@media (prefers-color-scheme: light) {
|
|
126
|
+
:root {
|
|
127
|
+
--g360-bg: #ffffff;
|
|
128
|
+
--g360-surface: #f5f5f5;
|
|
129
|
+
--g360-muted: #6b7280;
|
|
130
|
+
--g360-text: #1f2937;
|
|
131
|
+
--g360-glass: rgba(255, 255, 255, 0.75);
|
|
132
|
+
}
|
|
133
|
+
}
|
package/src/cli.js
CHANGED
|
@@ -31,10 +31,12 @@ program
|
|
|
31
31
|
.command('init')
|
|
32
32
|
.argument('<name>', 'Project name')
|
|
33
33
|
.option('-t, --template <type>', 'Project template type', 'web-pwa')
|
|
34
|
-
.option('-s, --skill <skill>', 'Skill to use (corporativo, corporativo-movil, moderno, moderno-movil, minimalista, custom)', 'corporativo-movil')
|
|
34
|
+
.option('-s, --skill <skill>', 'Skill to use (corporativo, corporativo-movil, moderno, moderno-movil, minimalista, custom, flet-desktop, flet-desktop-corporativo, cipsa, cipsa-movil)', 'corporativo-movil')
|
|
35
35
|
.option('-d, --dir <path>', 'Target directory', '.')
|
|
36
36
|
.option('--dry-run', 'Preview without creating files')
|
|
37
37
|
.option('--force', 'Overwrite existing files')
|
|
38
|
+
.option('--portable', 'Create portable version (for python-flet, python-cli)')
|
|
39
|
+
.option('--no-portable', 'Skip portable version creation')
|
|
38
40
|
.action(init);
|
|
39
41
|
|
|
40
42
|
program
|
|
@@ -46,7 +48,7 @@ program
|
|
|
46
48
|
|
|
47
49
|
program
|
|
48
50
|
.command('bring')
|
|
49
|
-
.argument('[asset]', '
|
|
51
|
+
.argument('[asset]', 'Asset to bring: brand, brand/cipsa, brand/g360, components, templates, skills, all')
|
|
50
52
|
.option('-p, --path <path>', 'Target path', '.')
|
|
51
53
|
.option('--dry-run', 'Preview without copying')
|
|
52
54
|
.option('--force', 'Overwrite existing files')
|
|
@@ -54,7 +56,7 @@ program
|
|
|
54
56
|
|
|
55
57
|
program
|
|
56
58
|
.command('list')
|
|
57
|
-
.argument('[type]', 'Type to list (templates/components/skills/all)', 'all')
|
|
59
|
+
.argument('[type]', 'Type to list (templates/components/skills/snippets/brands/all)', 'all')
|
|
58
60
|
.option('--json', 'Output as JSON')
|
|
59
61
|
.action(list);
|
|
60
62
|
|
|
@@ -81,6 +83,8 @@ program
|
|
|
81
83
|
.option('--orphans', 'Remove orphan files (unreferenced)')
|
|
82
84
|
.option('--organize', 'Show misplaced files suggestions')
|
|
83
85
|
.option('--all', 'Run all cleanup tasks')
|
|
86
|
+
.option('--github', 'Prepare repo for GitHub (update .gitignore)')
|
|
87
|
+
.option('--pre-push', 'Alias for --github (prepare before push)')
|
|
84
88
|
.action(clean);
|
|
85
89
|
|
|
86
90
|
program
|
|
@@ -96,7 +100,7 @@ program
|
|
|
96
100
|
program
|
|
97
101
|
.command('convert')
|
|
98
102
|
.argument('[path]', 'Path to convert', '.')
|
|
99
|
-
.option('-s, --skill <skill>', 'Skill to apply', 'corporativo-movil')
|
|
103
|
+
.option('-s, --skill <skill>', 'Skill to apply (corporativo, corporativo-movil, moderno, moderno-movil, minimalista, custom, flet-desktop, flet-desktop-corporativo, cipsa, cipsa-movil)', 'corporativo-movil')
|
|
100
104
|
.option('--dry-run', 'Preview without applying')
|
|
101
105
|
.option('--restructure', 'Restructure project files')
|
|
102
106
|
.option('--force', 'Force dangerous changes')
|
package/src/commands/bring.js
CHANGED
|
@@ -10,7 +10,7 @@ export async function bring(asset, options) {
|
|
|
10
10
|
const { path: targetPath = '.', dryRun = false, force = false } = options;
|
|
11
11
|
const targetDir = path.join(process.cwd(), targetPath);
|
|
12
12
|
const assetsPath = path.join(__dirname, '../assets');
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
console.log(chalk.bold.cyan('\n📦 G360 Asset Manager\n'));
|
|
15
15
|
|
|
16
16
|
if (!asset || asset === 'all') {
|
|
@@ -19,14 +19,89 @@ export async function bring(asset, options) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const assetPath = path.join(assetsPath, asset);
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
if (!fs.existsSync(assetPath)) {
|
|
24
24
|
console.error(chalk.red(`❌ Asset "${asset}" not found.`));
|
|
25
|
-
console.log(chalk.gray('\nRun "g360 list
|
|
25
|
+
console.log(chalk.gray('\nRun "g360 list all" to see available assets.'));
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
await copyAssets(assetPath, targetDir, dryRun, force);
|
|
30
|
+
|
|
31
|
+
if (asset.startsWith('brand')) {
|
|
32
|
+
const brandName = asset.split('/')[1];
|
|
33
|
+
if (brandName) {
|
|
34
|
+
await applyBrand(targetDir, brandName, dryRun);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function applyBrand(targetDir, brandName, dryRun) {
|
|
40
|
+
const brandConfigPath = path.join(targetDir, 'g360', 'brand', 'brand.json');
|
|
41
|
+
if (!fs.existsSync(brandConfigPath)) {
|
|
42
|
+
console.log(chalk.yellow(`\n⚠ brand.json not found. Run 'g360 bring brand' first.`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let brandConfig;
|
|
47
|
+
try {
|
|
48
|
+
brandConfig = fs.readJsonSync(brandConfigPath);
|
|
49
|
+
} catch {
|
|
50
|
+
console.log(chalk.yellow(`\n⚠ Could not parse brand.json.`));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const brand = brandConfig.brands?.[brandName];
|
|
55
|
+
if (!brand) {
|
|
56
|
+
console.log(chalk.yellow(`\n⚠ Brand "${brandName}" not found in brand.json`));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const skillCandidates = [
|
|
61
|
+
path.join(targetDir, 'skill.json'),
|
|
62
|
+
path.join(targetDir, 'src', 'core', 'skill.json'),
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
let skillPath = null;
|
|
66
|
+
for (const c of skillCandidates) {
|
|
67
|
+
if (fs.existsSync(c)) {
|
|
68
|
+
skillPath = c;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!skillPath) {
|
|
74
|
+
console.log(chalk.yellow(`\n⚠ No skill.json found. Create one with 'g360 init'.`));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (dryRun) {
|
|
79
|
+
console.log(chalk.yellow(`\n📋 DRY RUN - Would update ${skillPath}`));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const skill = fs.readJsonSync(skillPath);
|
|
84
|
+
skill.brand = brandName;
|
|
85
|
+
|
|
86
|
+
if (!skill.guidelines) skill.guidelines = {};
|
|
87
|
+
skill.guidelines.logo = brand.default_logo;
|
|
88
|
+
skill.guidelines.description = brand.description;
|
|
89
|
+
|
|
90
|
+
if (brand.signature) {
|
|
91
|
+
if (!skill.signature) skill.signature = {};
|
|
92
|
+
skill.signature.mode = brand.signature.mode;
|
|
93
|
+
skill.signature.text = brand.signature.text;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (brand.primary_color) {
|
|
97
|
+
if (!skill.colors) skill.colors = {};
|
|
98
|
+
skill.colors.accent = brand.primary_color;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fs.writeJsonSync(skillPath, skill, { spaces: 2 });
|
|
102
|
+
console.log(chalk.green(`\n✅ Brand "${brandName}" applied to ${skillPath}`));
|
|
103
|
+
console.log(chalk.gray(` Logo: ${brand.default_logo}`));
|
|
104
|
+
console.log(chalk.gray(` Signature: ${brand.signature?.text || 'none'}`));
|
|
30
105
|
}
|
|
31
106
|
|
|
32
107
|
async function copyAssets(src, dest, dryRun, force) {
|
|
@@ -36,18 +111,18 @@ async function copyAssets(src, dest, dryRun, force) {
|
|
|
36
111
|
}
|
|
37
112
|
|
|
38
113
|
const progressBar = progress('Copying assets...');
|
|
39
|
-
|
|
114
|
+
|
|
40
115
|
try {
|
|
41
116
|
const items = fs.readdirSync(src);
|
|
42
117
|
for (const item of items) {
|
|
43
118
|
const srcPath = path.join(src, item);
|
|
44
119
|
const destPath = path.join(dest, 'g360', item);
|
|
45
|
-
|
|
120
|
+
|
|
46
121
|
if (fs.statSync(srcPath).isDirectory()) {
|
|
47
122
|
await fs.copy(srcPath, destPath, { overwrite: force });
|
|
48
123
|
}
|
|
49
124
|
}
|
|
50
|
-
|
|
125
|
+
|
|
51
126
|
progressBar.stop();
|
|
52
127
|
console.log(chalk.green('\n✅ Assets copied successfully!\n'));
|
|
53
128
|
} catch (error) {
|
package/src/commands/clean.js
CHANGED
|
@@ -21,14 +21,16 @@ const DEAD_PATTERNS = [
|
|
|
21
21
|
const DUPLICATE_EXTENSIONS = ['.bak', '.orig', '.swp', '.swo', '~'];
|
|
22
22
|
|
|
23
23
|
export async function clean(projectPath, options) {
|
|
24
|
-
const {
|
|
25
|
-
dryRun = false,
|
|
24
|
+
const {
|
|
25
|
+
dryRun = false,
|
|
26
26
|
force = false,
|
|
27
27
|
dead = false,
|
|
28
28
|
duplicates = false,
|
|
29
29
|
orphans = false,
|
|
30
30
|
organize = false,
|
|
31
|
-
all = false
|
|
31
|
+
all = false,
|
|
32
|
+
github = false,
|
|
33
|
+
prePush = false
|
|
32
34
|
} = options;
|
|
33
35
|
|
|
34
36
|
const targetDir = path.join(process.cwd(), projectPath);
|
|
@@ -123,8 +125,53 @@ export async function clean(projectPath, options) {
|
|
|
123
125
|
return;
|
|
124
126
|
}
|
|
125
127
|
|
|
128
|
+
if (github || prePush) {
|
|
129
|
+
console.log(chalk.bold.cyan('\n📦 Modo Pre-Push GitHub\n'));
|
|
130
|
+
console.log(chalk.gray('Limpiando para subir a repositorio remoto...\n'));
|
|
131
|
+
|
|
132
|
+
const gitIgnore = path.join(targetDir, '.gitignore');
|
|
133
|
+
const requiredIgnores = [
|
|
134
|
+
'node_modules/',
|
|
135
|
+
'__pycache__/',
|
|
136
|
+
'*.pyc',
|
|
137
|
+
'.env',
|
|
138
|
+
'dist/',
|
|
139
|
+
'build/',
|
|
140
|
+
'*.log',
|
|
141
|
+
'.cache/',
|
|
142
|
+
'coverage/',
|
|
143
|
+
'*.egg-info/',
|
|
144
|
+
'.pytest_cache/'
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
if (fs.existsSync(gitIgnore)) {
|
|
148
|
+
const currentIgnore = await fs.readFile(gitIgnore, 'utf-8');
|
|
149
|
+
let updatedIgnore = currentIgnore;
|
|
150
|
+
|
|
151
|
+
for (const pattern of requiredIgnores) {
|
|
152
|
+
if (!currentIgnore.includes(pattern)) {
|
|
153
|
+
updatedIgnore += `\n${pattern}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await fs.writeFile(gitIgnore, updatedIgnore);
|
|
158
|
+
console.log(chalk.green(' ✅ .gitignore actualizado'));
|
|
159
|
+
} else {
|
|
160
|
+
await fs.writeFile(gitIgnore, requiredIgnores.join('\n') + '\n');
|
|
161
|
+
console.log(chalk.green(' ✅ .gitignore creado'));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
console.log(chalk.green('\n✅ Repo listo para GitHub!\n'));
|
|
165
|
+
console.log(chalk.gray('Para subir:'));
|
|
166
|
+
console.log(` ${chalk.cyan('git add .')}`);
|
|
167
|
+
console.log(` ${chalk.cyan('git commit -m "clean: preparing for push"')}`);
|
|
168
|
+
console.log(` ${chalk.cyan('git push')}\n`);
|
|
169
|
+
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
126
173
|
console.log(chalk.cyan('\n🚀 Aplicando limpieza...'));
|
|
127
|
-
|
|
174
|
+
|
|
128
175
|
let cleaned = 0;
|
|
129
176
|
|
|
130
177
|
for (const file of issues.dead) {
|
package/src/commands/init.js
CHANGED
|
@@ -5,19 +5,61 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
import { manifest } from '../lib/manifest.js';
|
|
6
6
|
import { progress } from '../lib/progress.js';
|
|
7
7
|
import { setSkill } from './set-skill.js';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
8
9
|
|
|
9
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
|
|
12
|
+
const PORTABLE_TEMPLATES = ['python-flet', 'python-flet-migrate', 'python-cli', 'python-customtkinter'];
|
|
13
|
+
|
|
14
|
+
async function askPortableOption(template) {
|
|
15
|
+
if (!PORTABLE_TEMPLATES.includes(template)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const answers = await inquirer.prompt([
|
|
20
|
+
{
|
|
21
|
+
type: 'confirm',
|
|
22
|
+
name: 'portable',
|
|
23
|
+
message: '¿Deseas crear una versión portable del proyecto? (ejecutable standalone)',
|
|
24
|
+
default: false
|
|
25
|
+
}
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
return answers.portable;
|
|
29
|
+
}
|
|
30
|
+
|
|
11
31
|
export async function init(name, options) {
|
|
12
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
template = 'web-pwa',
|
|
34
|
+
skill = 'corporativo-movil',
|
|
35
|
+
dir = '.',
|
|
36
|
+
dryRun = false,
|
|
37
|
+
force = false,
|
|
38
|
+
portable = null
|
|
39
|
+
} = options;
|
|
40
|
+
|
|
13
41
|
const targetDir = path.join(process.cwd(), dir, name);
|
|
14
|
-
|
|
42
|
+
|
|
15
43
|
console.log(chalk.bold.cyan('\n🚀 G360 Project Initialization\n'));
|
|
16
44
|
console.log(`Project: ${chalk.yellow(name)}`);
|
|
17
45
|
console.log(`Template: ${chalk.blue(template)}`);
|
|
18
46
|
console.log(`Skill: ${chalk.magenta(skill)}`);
|
|
19
47
|
console.log(`Target: ${chalk.gray(targetDir)}\n`);
|
|
20
48
|
|
|
49
|
+
let wantPortable = false;
|
|
50
|
+
|
|
51
|
+
if (portable === true) {
|
|
52
|
+
wantPortable = true;
|
|
53
|
+
console.log(chalk.yellow('📦 Versión portable: SÍ (flag)\n'));
|
|
54
|
+
} else if (portable === false) {
|
|
55
|
+
console.log(chalk.gray('📦 Versión portable: NO\n'));
|
|
56
|
+
} else {
|
|
57
|
+
wantPortable = await askPortableOption(template);
|
|
58
|
+
if (wantPortable) {
|
|
59
|
+
console.log(chalk.yellow('📦 Versión portable: SÍ\n'));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
21
63
|
const templatesPath = path.join(__dirname, '../assets/templates');
|
|
22
64
|
|
|
23
65
|
if (!fs.existsSync(templatesPath)) {
|
|
@@ -49,21 +91,31 @@ export async function init(name, options) {
|
|
|
49
91
|
const progressBar = progress('Creating project...');
|
|
50
92
|
|
|
51
93
|
try {
|
|
52
|
-
// Asegurar que el directorio base existe
|
|
53
94
|
await fs.ensureDir(path.dirname(targetDir));
|
|
54
95
|
|
|
55
96
|
await fs.copy(templateDir, targetDir);
|
|
56
|
-
await manifest.init(targetDir, { name, template, version: '1.0.0' });
|
|
57
|
-
|
|
58
|
-
|
|
97
|
+
await manifest.init(targetDir, { name, template, version: '1.0.0', portable: wantPortable });
|
|
98
|
+
|
|
99
|
+
if (wantPortable) {
|
|
100
|
+
const portableDir = path.join(targetDir, 'portable');
|
|
101
|
+
await fs.ensureDir(portableDir);
|
|
102
|
+
const buildScript = path.join(targetDir, 'build-portable.bat');
|
|
103
|
+
if (fs.existsSync(buildScript)) {
|
|
104
|
+
await fs.copy(buildScript, path.join(portableDir, 'build.bat'));
|
|
105
|
+
}
|
|
106
|
+
console.log(chalk.gray(' 📦 Carpeta portable/ creada para builds\n'));
|
|
107
|
+
}
|
|
108
|
+
|
|
59
109
|
await setSkill(skill, { force: true, verbose: options.verbose, cwd: targetDir });
|
|
60
110
|
|
|
61
|
-
// Crear estructura estándar G360 para auditoría y desarrollo guiado
|
|
62
111
|
await createG360Structure(targetDir, templatesPath);
|
|
63
112
|
|
|
64
113
|
progressBar.stop();
|
|
65
|
-
|
|
114
|
+
|
|
66
115
|
console.log(chalk.green('\n✅ Project created successfully!\n'));
|
|
116
|
+
if (wantPortable) {
|
|
117
|
+
console.log(chalk.yellow('📦 Versión portable habilitada\n'));
|
|
118
|
+
}
|
|
67
119
|
console.log(chalk.gray('Next steps:'));
|
|
68
120
|
console.log(` ${chalk.cyan('cd')} ${name}`);
|
|
69
121
|
console.log(` ${chalk.cyan('g360 bring')}`);
|
package/src/commands/list.js
CHANGED
|
@@ -14,13 +14,15 @@ export async function list(type, options) {
|
|
|
14
14
|
const assets = {
|
|
15
15
|
templates: [],
|
|
16
16
|
components: [],
|
|
17
|
-
skills: []
|
|
17
|
+
skills: [],
|
|
18
|
+
brands: []
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
const templatesPath = path.join(assetsPath, 'templates');
|
|
21
22
|
const componentsPath = path.join(assetsPath, 'components');
|
|
22
|
-
const
|
|
23
|
-
const
|
|
23
|
+
const configPath = path.join(assetsPath, 'config');
|
|
24
|
+
const snippetsPath = path.join(assetsPath, 'snippets');
|
|
25
|
+
const brandPath = path.join(assetsPath, 'brand');
|
|
24
26
|
|
|
25
27
|
if (fs.existsSync(templatesPath)) {
|
|
26
28
|
assets.templates = fs.readdirSync(templatesPath);
|
|
@@ -28,11 +30,53 @@ export async function list(type, options) {
|
|
|
28
30
|
if (fs.existsSync(componentsPath)) {
|
|
29
31
|
assets.components = fs.readdirSync(componentsPath).filter(f => f.endsWith('.jsx') || f.endsWith('.js'));
|
|
30
32
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
|
|
34
|
+
if (fs.existsSync(configPath)) {
|
|
35
|
+
const g360SkillsPath = path.join(configPath, 'g360-skills.json');
|
|
36
|
+
if (fs.existsSync(g360SkillsPath)) {
|
|
37
|
+
try {
|
|
38
|
+
const skillsData = fs.readJsonSync(g360SkillsPath);
|
|
39
|
+
assets.skills = skillsData.skills.map(skill => ({
|
|
40
|
+
name: skill.name,
|
|
41
|
+
description: skill.description,
|
|
42
|
+
device: skill.device
|
|
43
|
+
}));
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.log(chalk.yellow(`Warning: Could not read skills config: ${error.message}`));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (fs.existsSync(snippetsPath)) {
|
|
51
|
+
const snippetsJsonPath = path.join(snippetsPath, 'snippets.json');
|
|
52
|
+
if (fs.existsSync(snippetsJsonPath)) {
|
|
53
|
+
try {
|
|
54
|
+
const snippetsData = fs.readJsonSync(snippetsJsonPath);
|
|
55
|
+
assets.snippets = snippetsData.snippets.map(snippet => ({
|
|
56
|
+
name: snippet.name,
|
|
57
|
+
description: snippet.description,
|
|
58
|
+
language: snippet.language
|
|
59
|
+
}));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.log(chalk.yellow(`Warning: Could not read snippets config: ${error.message}`));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
33
64
|
}
|
|
34
|
-
|
|
35
|
-
|
|
65
|
+
|
|
66
|
+
if (fs.existsSync(brandPath)) {
|
|
67
|
+
const brandConfigPath = path.join(brandPath, 'brand.json');
|
|
68
|
+
if (fs.existsSync(brandConfigPath)) {
|
|
69
|
+
try {
|
|
70
|
+
const brandData = fs.readJsonSync(brandConfigPath);
|
|
71
|
+
assets.brands = Object.entries(brandData.brands || {}).map(([key, val]) => ({
|
|
72
|
+
name: key,
|
|
73
|
+
description: val.description,
|
|
74
|
+
logo: val.default_logo
|
|
75
|
+
}));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.log(chalk.yellow(`Warning: Could not read brand config: ${error.message}`));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
36
80
|
}
|
|
37
81
|
|
|
38
82
|
if (json) {
|
|
@@ -60,12 +104,38 @@ export async function list(type, options) {
|
|
|
60
104
|
|
|
61
105
|
if (!type || type === 'all' || type === 'skills') {
|
|
62
106
|
console.log(chalk.bold.yellow('\n⚡ Skills:'));
|
|
63
|
-
if (assets.
|
|
64
|
-
assets.
|
|
107
|
+
if (assets.skills.length) {
|
|
108
|
+
assets.skills.forEach(skill => {
|
|
109
|
+
console.log(chalk.gray(` - ${skill.name}`));
|
|
110
|
+
console.log(chalk.gray(` ${skill.description}`));
|
|
111
|
+
console.log(chalk.gray(` Device: ${skill.device}`));
|
|
112
|
+
});
|
|
65
113
|
} else {
|
|
66
114
|
console.log(chalk.gray(' No skills found'));
|
|
67
115
|
}
|
|
68
116
|
}
|
|
69
117
|
|
|
118
|
+
if (!type || type === 'all' || type === 'brands') {
|
|
119
|
+
console.log(chalk.bold.yellow('\n🎨 Brands:'));
|
|
120
|
+
if (assets.brands.length) {
|
|
121
|
+
assets.brands.forEach(b => console.log(chalk.gray(` - ${b.name}`)));
|
|
122
|
+
} else {
|
|
123
|
+
console.log(chalk.gray(' No brands found'));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!type || type === 'all' || type === 'snippets') {
|
|
128
|
+
console.log(chalk.bold.yellow('\n📝 Snippets:'));
|
|
129
|
+
if (assets.snippets && assets.snippets.length) {
|
|
130
|
+
assets.snippets.forEach(snippet => {
|
|
131
|
+
console.log(chalk.gray(` - ${snippet.name}`));
|
|
132
|
+
console.log(chalk.gray(` ${snippet.description}`));
|
|
133
|
+
console.log(chalk.gray(` Language: ${snippet.language}`));
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
console.log(chalk.gray(' No snippets found'));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
70
140
|
console.log();
|
|
71
141
|
}
|
|
@@ -21,20 +21,24 @@ export async function signature(command, options) {
|
|
|
21
21
|
|
|
22
22
|
let htmlContent = fs.readFileSync(indexHtmlPath, 'utf8');
|
|
23
23
|
|
|
24
|
-
// Verificar si ya esta instalado
|
|
25
|
-
if (htmlContent.includes('g360-signature') && !force) {
|
|
26
|
-
console.log(chalk.yellow('⚠️ g360-signature ya se encuentra instalado'));
|
|
27
|
-
console.log(chalk.gray('Usa --force para reinstalar'));
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Agregar script CDN antes del cierre del body
|
|
32
24
|
const scriptTag = ' <script type="module" src="https://unpkg.com/g360-signature@latest/index.js"></script>';
|
|
33
25
|
const signatureComponent = `
|
|
34
26
|
<!-- Firma Oficial G360 -->
|
|
35
27
|
<g360-signature mode="powered" style="position: fixed; bottom: 16px; right: 16px; z-index: 99999;"></g360-signature>
|
|
36
28
|
`;
|
|
37
29
|
|
|
30
|
+
// Si --force es true, eliminamos cualquier instancia existente para una reinstalación limpia.
|
|
31
|
+
// De lo contrario, si ya está instalado y no se fuerza, salimos.
|
|
32
|
+
if (force) {
|
|
33
|
+
htmlContent = htmlContent.replace(new RegExp(scriptTag.trim().replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '');
|
|
34
|
+
htmlContent = htmlContent.replace(new RegExp(signatureComponent.trim().replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '');
|
|
35
|
+
htmlContent = htmlContent.replace(/\n\s*\n/g, '\n'); // Limpiar posibles líneas vacías extra
|
|
36
|
+
} else if (htmlContent.includes('g360-signature')) {
|
|
37
|
+
console.log(chalk.yellow('⚠️ g360-signature ya se encuentra instalado'));
|
|
38
|
+
console.log(chalk.gray('Usa --force para reinstalar'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
if (!htmlContent.includes(scriptTag)) {
|
|
39
43
|
htmlContent = htmlContent.replace('</body>', `${scriptTag}\n </body>`);
|
|
40
44
|
}
|