@qubiit/lmagent 3.1.3 → 3.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.agents/docs/commands.md +1 -1
  2. package/.agents/docs/getting-started.md +9 -9
  3. package/.agents/rules/00-master.md +2 -2
  4. package/.agents/skills/ai-agent-engineer/SKILL.md +1 -1
  5. package/.agents/skills/api-designer/SKILL.md +1 -1
  6. package/.agents/skills/architect/SKILL.md +1 -1
  7. package/.agents/skills/automation-engineer/SKILL.md +1 -1
  8. package/.agents/skills/backend-engineer/SKILL.md +1 -1
  9. package/.agents/skills/bmad-methodology/SKILL.md +1 -1
  10. package/.agents/skills/browser-agent/SKILL.md +1 -1
  11. package/.agents/skills/code-reviewer/SKILL.md +1 -1
  12. package/.agents/skills/data-engineer/SKILL.md +1 -1
  13. package/.agents/skills/devops-engineer/SKILL.md +1 -1
  14. package/.agents/skills/document-generator/SKILL.md +1 -1
  15. package/.agents/skills/frontend-engineer/SKILL.md +1 -1
  16. package/.agents/skills/git-workflow/SKILL.md +1 -1
  17. package/.agents/skills/mcp-builder/SKILL.md +1 -1
  18. package/.agents/skills/mobile-engineer/SKILL.md +1 -1
  19. package/.agents/skills/orchestrator/SKILL.md +1 -1
  20. package/.agents/skills/performance-engineer/SKILL.md +1 -1
  21. package/.agents/skills/product-manager/SKILL.md +1 -1
  22. package/.agents/skills/prompt-engineer/SKILL.md +1 -1
  23. package/.agents/skills/qa-engineer/SKILL.md +1 -1
  24. package/.agents/skills/scrum-master/SKILL.md +1 -1
  25. package/.agents/skills/security-analyst/SKILL.md +1 -1
  26. package/.agents/skills/seo-auditor/SKILL.md +1 -1
  27. package/.agents/skills/spec-driven-dev/SKILL.md +1 -1
  28. package/.agents/skills/supabase-expert/SKILL.md +1 -1
  29. package/.agents/skills/swe-agent/SKILL.md +1 -1
  30. package/.agents/skills/systematic-debugger/SKILL.md +1 -1
  31. package/.agents/skills/tech-lead/SKILL.md +1 -1
  32. package/.agents/skills/technical-writer/SKILL.md +1 -1
  33. package/.agents/skills/testing-strategist/SKILL.md +1 -1
  34. package/.agents/skills/ux-ui-designer/SKILL.md +1 -1
  35. package/AGENTS.md +1 -1
  36. package/CONTRIBUTING.md +3 -3
  37. package/README.md +19 -19
  38. package/install.js +40 -23
  39. package/package.json +4 -2
  40. package/scripts/create_skill.js +300 -0
  41. package/scripts/fix_descriptions.js +51 -0
  42. package/scripts/token-analyzer.js +275 -0
  43. package/scripts/validate_skills.js +285 -0
package/install.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
@@ -40,7 +40,7 @@ const INIT_DIRS = [
40
40
  const IDE_CONFIGS = [
41
41
  // --- IDEs Principales (Auto-Detectados) ---
42
42
  // Cursor: usa .cursor/rules/*.mdc (formato MDC con frontmatter)
43
- { name: 'Cursor', value: 'cursor', rulesDir: '.cursor/rules', skillsDir: '.cursor/skills', workflowsDir: '.cursor/workflows', configFile: '.cursorrules', bridgeFile: 'lmagent.mdc', markerFile: '.cursorrules', forceCopy: true },
43
+ { name: 'Cursor', value: 'cursor', rulesDir: '.cursor/rules', skillsDir: '.cursor/rules/skills', workflowsDir: '.cursor/workflows', configFile: '.cursorrules', bridgeFile: 'lmagent.mdc', markerFile: '.cursorrules', forceCopy: true },
44
44
  // Windsurf Wave 8+: usa .windsurf/rules/*.md (directorio, NO .windsurfrules)
45
45
  { name: 'Windsurf', value: 'windsurf', rulesDir: '.windsurf/rules', skillsDir: '.windsurf/skills', workflowsDir: '.windsurf/workflows', configFile: null, bridgeFile: 'lmagent.md', markerFile: '.windsurf', forceCopy: true },
46
46
  // Cline: usa .clinerules/ (directorio con .md files)
@@ -902,12 +902,26 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
902
902
  `;
903
903
  }
904
904
 
905
+ // CLEANUP: Legacy Cursor Skills Directory
906
+ // Since we moved skills to .cursor/rules/skills, we must remove .cursor/skills to avoid duplicates
907
+ if (ide.value === 'cursor') {
908
+ const legacySkillsDir = path.join(targetRoot, '.cursor/skills');
909
+ if (fs.existsSync(legacySkillsDir)) {
910
+ try {
911
+ fs.rmSync(legacySkillsDir, { recursive: true, force: true });
912
+ console.log(` ${chalk.yellow('🗑 Eliminado directorio obsoleto:')} .cursor / skills(Movido a.cursor / rules / skills)`);
913
+ } catch (e) {
914
+ console.error(chalk.red(` ⚠️ No se pudo eliminar.cursor / skills: ${e.message} `));
915
+ }
916
+ }
917
+ }
918
+
905
919
  try {
906
920
  if (!fs.existsSync(path.dirname(bridgePath))) fs.mkdirSync(path.dirname(bridgePath), { recursive: true });
907
921
  fs.writeFileSync(bridgePath, bridgeContent);
908
- console.log(` ${chalk.green('✔')} ${ide.name} Bridge Rule: ${bridgeFile}`);
922
+ console.log(` ${chalk.green('✔')} ${ide.name} Bridge Rule: ${bridgeFile} `);
909
923
  } catch (e) {
910
- console.error(chalk.red(` ❌ Error creating bridge for ${ide.name}: ${e.message}`));
924
+ console.error(chalk.red(` ❌ Error creating bridge for ${ide.name}: ${e.message} `));
911
925
  }
912
926
  }
913
927
  // 2. Install RULES (Files)
@@ -918,7 +932,7 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
918
932
  if (arePathsEqual(targetDir, globalRulesDir)) {
919
933
  console.log(chalk.blue(` ℹ ${ide.name}: Rules updated via Global Sync`));
920
934
  } else {
921
- console.log(chalk.bold(`\nInstalling Rules to ${chalk.cyan(targetDir)}:`));
935
+ console.log(chalk.bold(`\nInstalling Rules to ${chalk.cyan(targetDir)}: `));
922
936
 
923
937
  try {
924
938
  if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true });
@@ -935,7 +949,7 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
935
949
  const legacyPath = path.join(targetDir, legacy);
936
950
  if (fs.existsSync(legacyPath)) {
937
951
  fs.unlinkSync(legacyPath);
938
- console.log(` ${chalk.yellow('🗑 Eliminado regla obsoleta:')} ${legacy}`);
952
+ console.log(` ${chalk.yellow('🗑 Eliminado regla obsoleta:')} ${legacy} `);
939
953
  }
940
954
  }
941
955
 
@@ -945,11 +959,11 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
945
959
 
946
960
  if (fs.existsSync(srcVal)) {
947
961
  await applyFile(srcVal, destVal, currentInstallMethod);
948
- console.log(` ${chalk.blue('✔')} ${rule}`);
962
+ console.log(` ${chalk.blue('✔')} ${rule} `);
949
963
  }
950
964
  }
951
965
  } catch (e) {
952
- console.error(chalk.red(`❌ Error installing rules for ${ide.name}: ${e.message}`));
966
+ console.error(chalk.red(`❌ Error installing rules for ${ide.name}: ${e.message} `));
953
967
  }
954
968
  }
955
969
  }
@@ -962,7 +976,7 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
962
976
  if (arePathsEqual(targetDir, globalWorkflowsDir)) {
963
977
  console.log(chalk.blue(` ℹ ${ide.name}: Workflows updated via Global Sync`));
964
978
  } else {
965
- console.log(chalk.bold(`\nInstalling Workflows to ${chalk.cyan(targetDir)}:`));
979
+ console.log(chalk.bold(`\nInstalling Workflows to ${chalk.cyan(targetDir)}: `));
966
980
 
967
981
  try {
968
982
  if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true });
@@ -973,11 +987,11 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
973
987
 
974
988
  if (fs.existsSync(srcVal)) {
975
989
  await applyFile(srcVal, destVal, currentInstallMethod);
976
- console.log(` ${chalk.magenta('✔')} ${wf}`);
990
+ console.log(` ${chalk.magenta('✔')} ${wf} `);
977
991
  }
978
992
  }
979
993
  } catch (e) {
980
- console.error(chalk.red(`❌ Error installing workflows for ${ide.name}: ${e.message}`));
994
+ console.error(chalk.red(`❌ Error installing workflows for ${ide.name}: ${e.message} `));
981
995
  }
982
996
  }
983
997
  }
@@ -992,16 +1006,16 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
992
1006
  const targetDir = path.join(targetRoot, parentDir, 'memory');
993
1007
 
994
1008
  if (arePathsEqual(targetDir, path.join(globalAgentDir, 'memory'))) {
995
- // console.log(chalk.blue(` ℹ ${ide.name}: Memory updated via Global Sync`));
1009
+ // console.log(chalk.blue(` ℹ ${ ide.name }: Memory updated via Global Sync`));
996
1010
  } else {
997
- // console.log(chalk.bold(`\nInstalling Memory to ${chalk.cyan(targetDir)}:`));
1011
+ // console.log(chalk.bold(`\nInstalling Memory to ${ chalk.cyan(targetDir) }: `));
998
1012
  try {
999
1013
  if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true });
1000
1014
  // Copy all contents of memory
1001
1015
  copyRecursiveSync(SOURCE_MEMORY, targetDir, true); // Always copy/overwrite for now, or use applyFile for items if we want symlinks
1002
- console.log(` ${chalk.cyan('✔')} Memory (Context) optimized.`);
1016
+ console.log(` ${chalk.cyan('✔')} Memory(Context) optimized.`);
1003
1017
  } catch (e) {
1004
- console.error(chalk.red(`❌ Error installing memory for ${ide.name}: ${e.message}`));
1018
+ console.error(chalk.red(`❌ Error installing memory for ${ide.name}: ${e.message} `));
1005
1019
  }
1006
1020
  }
1007
1021
  }
@@ -1014,7 +1028,7 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
1014
1028
 
1015
1029
  // Mensaje dinámico según agentes instalados
1016
1030
  const ideNames = targetIdes.map(i => i.name).join(', ');
1017
- console.log(chalk.cyan(`🤖 Agentes configurados: ${chalk.bold(ideNames)}`));
1031
+ console.log(chalk.cyan(`🤖 Agentes configurados: ${chalk.bold(ideNames)} `));
1018
1032
  console.log('');
1019
1033
  console.log(chalk.white(' 1. Abre tu agente en este proyecto — leerá el contexto automáticamente.'));
1020
1034
  console.log(chalk.white(' 2. Usa los triggers para activar un rol específico:'));
@@ -1032,7 +1046,7 @@ async function applyFile(source, dest, method) {
1032
1046
 
1033
1047
  // Case-insensitive check for Windows compatibility
1034
1048
  if (srcPath.toLowerCase() === destPath.toLowerCase()) {
1035
- // console.log(chalk.gray(` (Skipping self-install: ${path.basename(source)})`));
1049
+ // console.log(chalk.gray(` (Skipping self - install: ${ path.basename(source) })`));
1036
1050
  return;
1037
1051
  }
1038
1052
  if (fs.existsSync(dest) || (fs.existsSync(path.dirname(dest)) && fs.readdirSync(path.dirname(dest)).includes(path.basename(dest)))) {
@@ -1065,11 +1079,11 @@ async function applyFile(source, dest, method) {
1065
1079
  }
1066
1080
  const isWindows = os.platform() === 'win32';
1067
1081
  const msg = isWindows && !isDir
1068
- ? `(Symlink falló [Requiere Admin/DevMode en Win]. Copiado.)`
1082
+ ? `(Symlink falló[Requiere Admin / DevMode en Win].Copiado.)`
1069
1083
  : `(Symlink falló, se usó copia)`;
1070
- console.log(chalk.yellow(` ${msg}`));
1084
+ console.log(chalk.yellow(` ${msg} `));
1071
1085
  } catch (err) {
1072
- console.error(chalk.red(` Error copiando ${path.basename(dest)}: ${err.message}`));
1086
+ console.error(chalk.red(` Error copiando ${path.basename(dest)}: ${err.message} `));
1073
1087
  }
1074
1088
  }
1075
1089
  } else {
@@ -1086,7 +1100,7 @@ function copyRecursiveSync(src, dest, overwrite) {
1086
1100
  try {
1087
1101
  fs.cpSync(src, dest, { recursive: true, force: overwrite, errorOnExist: false });
1088
1102
  } catch (e) {
1089
- console.error(chalk.red(`Error copying (cpSync) ${path.basename(src)}: ${e.message}`));
1103
+ console.error(chalk.red(`Error copying(cpSync) ${path.basename(src)}: ${e.message} `));
1090
1104
  // Fallback manual implementation just in case
1091
1105
  if (fs.existsSync(src)) {
1092
1106
  const stat = fs.statSync(src);
@@ -1145,7 +1159,7 @@ async function runInit(options) {
1145
1159
 
1146
1160
  const projectRoot = process.cwd();
1147
1161
  const targetRoot = projectRoot; // Fix for ReferenceError in runInit
1148
- console.log(chalk.cyan(`📦 Inicializando proyecto LMAgent en: ${chalk.bold(projectRoot)}\n`));
1162
+ console.log(chalk.cyan(`📦 Inicializando proyecto LMAgent en: ${chalk.bold(projectRoot)} \n`));
1149
1163
 
1150
1164
  // Verificar si ya está inicializado
1151
1165
  const agentsExists = fs.existsSync(path.join(projectRoot, 'AGENTS.md'));
@@ -1176,7 +1190,7 @@ async function runInit(options) {
1176
1190
  name: 'files',
1177
1191
  message: 'Archivos de entry point a copiar:',
1178
1192
  choices: INIT_FILES.map(f => ({
1179
- name: `${f.src} - ${f.desc}`,
1193
+ name: `${f.src} - ${f.desc} `,
1180
1194
  value: f.src,
1181
1195
  checked: true
1182
1196
  }))
@@ -1495,3 +1509,6 @@ function getAllItemsFlat(dir) {
1495
1509
  return results;
1496
1510
  }
1497
1511
 
1512
+
1513
+ // Execute CLI
1514
+ program.parse(process.argv);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "3.1.3",
6
+ "version": "3.1.7",
7
7
  "files": [
8
8
  "install.js",
9
9
  "README.md",
@@ -11,7 +11,8 @@
11
11
  "AGENTS.md",
12
12
  "CLAUDE.md",
13
13
  "CONTRIBUTING.md",
14
- ".agents"
14
+ ".agents",
15
+ "scripts"
15
16
  ],
16
17
  "engines": {
17
18
  "node": ">=22.0.0"
@@ -74,6 +75,7 @@
74
75
  "author": "Leandro Martín Alvarez (QuBiit)",
75
76
  "license": "MIT",
76
77
  "dependencies": {
78
+ "@qubiit/lmagent": "file:qubiit-lmagent-3.1.6.tgz",
77
79
  "boxen": "^8.0.1",
78
80
  "chalk": "^4.1.2",
79
81
  "commander": "^13.1.0",
@@ -0,0 +1,300 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * LMAgent Skill Generator — v3.0.13
5
+ *
6
+ * Genera la estructura completa de un nuevo skill interactivamente.
7
+ *
8
+ * Uso:
9
+ * node scripts/create_skill.js # Interactivo
10
+ * node scripts/create_skill.js --name "My Skill" # Semi-automático
11
+ */
12
+
13
+ import { mkdirSync, writeFileSync, existsSync } from 'fs';
14
+ import { join, resolve, dirname } from 'path';
15
+ import { fileURLToPath } from 'url';
16
+ import { createInterface } from 'readline';
17
+
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = dirname(__filename);
20
+ const ROOT = resolve(__dirname, '..');
21
+ const SKILLS_DIR = join(ROOT, 'skills');
22
+
23
+ // ─── Colores ──────────────────────────────────────────────────
24
+ const c = {
25
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
26
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
27
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
28
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
29
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
30
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
31
+ };
32
+
33
+ // ─── Prompt interactivo ───────────────────────────────────────
34
+ function createPrompt() {
35
+ const rl = createInterface({
36
+ input: process.stdin,
37
+ output: process.stdout,
38
+ });
39
+
40
+ return {
41
+ ask: (question, defaultValue = '') => {
42
+ return new Promise((resolve) => {
43
+ const suffix = defaultValue ? ` ${c.dim(`(${defaultValue})`)}` : '';
44
+ rl.question(` ${c.cyan('?')} ${question}${suffix}: `, (answer) => {
45
+ resolve(answer.trim() || defaultValue);
46
+ });
47
+ });
48
+ },
49
+ askList: (question, hint = 'separar con comas') => {
50
+ return new Promise((resolve) => {
51
+ rl.question(` ${c.cyan('?')} ${question} ${c.dim(`(${hint})`)}: `, (answer) => {
52
+ const items = answer.split(',').map(s => s.trim()).filter(Boolean);
53
+ resolve(items);
54
+ });
55
+ });
56
+ },
57
+ askYesNo: (question, defaultValue = true) => {
58
+ return new Promise((resolve) => {
59
+ const hint = defaultValue ? 'S/n' : 's/N';
60
+ rl.question(` ${c.cyan('?')} ${question} ${c.dim(`(${hint})`)}: `, (answer) => {
61
+ if (!answer.trim()) return resolve(defaultValue);
62
+ resolve(['s', 'si', 'sí', 'y', 'yes'].includes(answer.trim().toLowerCase()));
63
+ });
64
+ });
65
+ },
66
+ close: () => rl.close(),
67
+ };
68
+ }
69
+
70
+ // ─── Generar slug del nombre ──────────────────────────────────
71
+ function slugify(name) {
72
+ return name
73
+ .toLowerCase()
74
+ .replace(/[áàäâ]/g, 'a')
75
+ .replace(/[éèëê]/g, 'e')
76
+ .replace(/[íìïî]/g, 'i')
77
+ .replace(/[óòöô]/g, 'o')
78
+ .replace(/[úùüû]/g, 'u')
79
+ .replace(/ñ/g, 'n')
80
+ .replace(/[^a-z0-9]+/g, '-')
81
+ .replace(/^-|-$/g, '');
82
+ }
83
+
84
+ // ─── Generar SKILL.md ─────────────────────────────────────────
85
+ function generateSkillMd(data) {
86
+ const expertise = data.expertise.map(e => ` - ${e}`).join('\n');
87
+ const activatesOn = data.activatesOn.map(a => ` - ${a}`).join('\n');
88
+ const triggers = data.triggers.map(t => ` - ${t}`).join('\n');
89
+
90
+ return `---
91
+ name: ${data.name}
92
+ description: ${data.description}
93
+ role: ${data.role}
94
+ type: ${data.type}
95
+ version: 3.0.0
96
+ icon: ${data.icon}
97
+ expertise:
98
+ ${expertise}
99
+ activates_on:
100
+ ${activatesOn}
101
+ triggers:
102
+ ${triggers}
103
+ ---
104
+
105
+ # ${data.name} Persona
106
+
107
+ ## 🧠 System Prompt
108
+ > **Instrucciones para el LLM**: Copia este bloque en tu system prompt o contexto inicial.
109
+
110
+ \`\`\`markdown
111
+ Eres **${data.name}**, un experto en ${data.role.toLowerCase()}.
112
+ Tu objetivo es **[DEFINIR OBJETIVO PRINCIPAL EN MAYÚSCULAS]**.
113
+ Tu tono es **[Adjetivo 1, Adjetivo 2, Adjetivo 3]**.
114
+
115
+ **Principios Core:**
116
+ 1. **[Principio 1]**: [Descripción]
117
+ 2. **[Principio 2]**: [Descripción]
118
+ 3. **[Principio 3]**: [Descripción]
119
+ 4. **[Principio 4]**: [Descripción]
120
+
121
+ **Restricciones:**
122
+ - NUNCA [restricción 1].
123
+ - SIEMPRE [restricción 2].
124
+ - SIEMPRE [restricción 3].
125
+ - NUNCA [restricción 4].
126
+ \`\`\`
127
+
128
+ ## 🔄 Arquitectura Cognitiva (Cómo Pensar)
129
+
130
+ ### 1. Fase de Análisis
131
+ Antes de actuar, pregúntate:
132
+ - **Input**: ¿Qué se necesita?
133
+ - **Contexto**: ¿Qué restricciones existen?
134
+ - **Riesgo**: ¿Qué puede salir mal?
135
+ - **Salida**: ¿Cuál es el resultado esperado?
136
+
137
+ ### 2. Fase de Diseño
138
+ - Definir **estructura** del entregable.
139
+ - Planear **enfoque** paso a paso.
140
+ - Identificar **dependencias** y **bloqueantes**.
141
+
142
+ ### 3. Fase de Ejecución
143
+ - Implementar según el plan.
144
+ - Verificar en cada paso.
145
+ - Documentar decisiones.
146
+
147
+ ### 4. Auto-Corrección
148
+ Antes de finalizar, verifica:
149
+ - "¿Cumple con los criterios de aceptación?"
150
+ - "¿Sigue los patrones del proyecto?"
151
+ - "¿Es mantenible y documentado?"
152
+
153
+ ---
154
+
155
+ ## Rol
156
+
157
+ ${data.description}
158
+
159
+ ## Responsabilidades
160
+
161
+ 1. **[Responsabilidad 1]**: [Detalle]
162
+ 2. **[Responsabilidad 2]**: [Detalle]
163
+ 3. **[Responsabilidad 3]**: [Detalle]
164
+ 4. **[Responsabilidad 4]**: [Detalle]
165
+ 5. **[Responsabilidad 5]**: [Detalle]
166
+
167
+ ## Stack Técnico
168
+
169
+ \`\`\`
170
+ [Tecnología 1] → [Propósito]
171
+ [Tecnología 2] → [Propósito]
172
+ [Tecnología 3] → [Propósito]
173
+ \`\`\`
174
+
175
+ ## Interacción con Otros Roles
176
+
177
+ | Rol | Colaboración |
178
+ |-----|-------------|
179
+ | [Rol 1] | [Cómo colaboran] |
180
+ | [Rol 2] | [Cómo colaboran] |
181
+ | [Rol 3] | [Cómo colaboran] |
182
+
183
+ ---
184
+
185
+ ## 🛠️ Herramientas Preferidas
186
+
187
+ | Herramienta | Cuándo Usarla |
188
+ |-------------|---------------|
189
+ | \`view_file\` | [Cuándo] |
190
+ | \`run_command\` | [Cuándo] |
191
+ | \`grep_search\` | [Cuándo] |
192
+ | \`write_to_file\` | [Cuándo] |
193
+
194
+ ## 📋 Definition of Done
195
+
196
+ Antes de considerar una tarea terminada, verifica TODO:
197
+
198
+ ### Calidad
199
+ - [ ] [Criterio 1]
200
+ - [ ] [Criterio 2]
201
+ - [ ] [Criterio 3]
202
+
203
+ ### Documentación
204
+ - [ ] [Criterio de documentación 1]
205
+ - [ ] [Criterio de documentación 2]
206
+
207
+ ---
208
+
209
+ *Skill version: 2.7 | LMAgent Framework*
210
+ `;
211
+ }
212
+
213
+ // ─── Main ─────────────────────────────────────────────────────
214
+ async function main() {
215
+ console.log(c.bold('\n🛠️ LMAgent Skill Generator v3.0.0\n'));
216
+
217
+ const prompt = createPrompt();
218
+
219
+ try {
220
+ // Obtener datos del skill
221
+ const name = await prompt.ask('Nombre del skill', '');
222
+ if (!name) {
223
+ console.log(c.red('\n❌ El nombre es obligatorio.\n'));
224
+ process.exit(1);
225
+ }
226
+
227
+ const slug = slugify(name);
228
+ const skillDir = join(SKILLS_DIR, slug);
229
+
230
+ if (existsSync(skillDir)) {
231
+ console.log(c.red(`\n❌ Ya existe un skill en: ${skillDir}\n`));
232
+ process.exit(1);
233
+ }
234
+
235
+ const description = await prompt.ask('Descripción breve', '');
236
+ const role = await prompt.ask('Rol del skill', `Experto en ${name}`);
237
+ const icon = await prompt.ask('Icono (emoji)', '🔧');
238
+ const type = await prompt.ask('Tipo (agent_persona / methodology)', 'agent_persona');
239
+ const expertise = await prompt.askList('Áreas de expertise');
240
+ const activatesOn = await prompt.askList('Cuándo se activa (contextos)');
241
+
242
+ const triggerSuggestion = `/${slug.split('-')[0]}`;
243
+ const triggersRaw = await prompt.askList('Triggers (con /)', `ej: ${triggerSuggestion}`);
244
+ const triggers = triggersRaw.length > 0 ? triggersRaw : [triggerSuggestion];
245
+
246
+ const createDirs = await prompt.askYesNo('¿Crear subdirectorios (scripts/, references/, assets/)?', false);
247
+
248
+ // Confirmar
249
+ console.log(c.bold('\n📋 Resumen:'));
250
+ console.log(` Nombre: ${c.cyan(name)}`);
251
+ console.log(` Slug: ${c.dim(slug)}`);
252
+ console.log(` Descripción: ${description}`);
253
+ console.log(` Rol: ${role}`);
254
+ console.log(` Icono: ${icon}`);
255
+ console.log(` Tipo: ${type}`);
256
+ console.log(` Expertise: ${expertise.join(', ')}`);
257
+ console.log(` Activa en: ${activatesOn.join(', ')}`);
258
+ console.log(` Triggers: ${triggers.join(', ')}`);
259
+ console.log(` Extra dirs: ${createDirs ? 'Sí' : 'No'}`);
260
+
261
+ const confirm = await prompt.askYesNo('\n¿Crear skill?', true);
262
+ if (!confirm) {
263
+ console.log(c.yellow('\n⚠️ Cancelado.\n'));
264
+ process.exit(0);
265
+ }
266
+
267
+ // Crear estructura
268
+ mkdirSync(skillDir, { recursive: true });
269
+
270
+ if (createDirs) {
271
+ mkdirSync(join(skillDir, 'scripts'), { recursive: true });
272
+ mkdirSync(join(skillDir, 'references'), { recursive: true });
273
+ mkdirSync(join(skillDir, 'assets'), { recursive: true });
274
+ }
275
+
276
+ // Generar SKILL.md
277
+ const skillMd = generateSkillMd({
278
+ name,
279
+ description,
280
+ role,
281
+ icon,
282
+ type,
283
+ expertise,
284
+ activatesOn,
285
+ triggers,
286
+ });
287
+
288
+ writeFileSync(join(skillDir, 'SKILL.md'), skillMd, 'utf-8');
289
+
290
+ console.log(c.green(`\n✅ Skill creado exitosamente en: ${skillDir}`));
291
+ console.log(c.dim(' Editá SKILL.md para completar las secciones con placeholders [...]'));
292
+ console.log(c.dim(' Ejecutá: node scripts/validate_skills.js ' + slug + ' para validar'));
293
+ console.log('');
294
+
295
+ } finally {
296
+ prompt.close();
297
+ }
298
+ }
299
+
300
+ main().catch(console.error);
@@ -0,0 +1,51 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const skillsDir = path.join(__dirname, '..', '.agents', 'skills');
5
+
6
+ function fixDescriptions() {
7
+ if (!fs.existsSync(skillsDir)) {
8
+ console.error('Skills directory not found:', skillsDir);
9
+ process.exit(1);
10
+ }
11
+
12
+ const skills = fs.readdirSync(skillsDir);
13
+ let updated = 0;
14
+
15
+ skills.forEach(skill => {
16
+ const skillPath = path.join(skillsDir, skill, 'SKILL.md');
17
+ if (fs.existsSync(skillPath)) {
18
+ let content = fs.readFileSync(skillPath, 'utf8');
19
+
20
+ // Regex to find description line
21
+ // Captures "description: value" where value is NOT double-quoted
22
+ // Note: This is a simple heuristic. It assumes description is on one line.
23
+ const regex = /^description: ([^"].*)$/m;
24
+
25
+ const match = content.match(regex);
26
+
27
+ if (match) {
28
+ const originalDescription = match[1].trim();
29
+ // Escape existing quotes if any (though regex excludes starting quote)
30
+ const escapedDescription = originalDescription.replace(/"/g, '\\"');
31
+ const newLine = `description: "${escapedDescription}"`;
32
+
33
+ content = content.replace(match[0], newLine);
34
+ fs.writeFileSync(skillPath, content, 'utf8');
35
+ console.log(`✅ Fixed ${skill}: ${originalDescription.substring(0, 30)}...`);
36
+ updated++;
37
+ } else {
38
+ // Check if it's already quoted
39
+ if (/^description: ".*"$/m.test(content)) {
40
+ console.log(`👌 ${skill} already quoted.`);
41
+ } else {
42
+ console.log(`⚠️ ${skill} description format not matching expected pattern.`);
43
+ }
44
+ }
45
+ }
46
+ });
47
+
48
+ console.log(`\nFixed ${updated} skills.`);
49
+ }
50
+
51
+ fixDescriptions();