@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.
- package/.agents/docs/commands.md +1 -1
- package/.agents/docs/getting-started.md +9 -9
- package/.agents/rules/00-master.md +2 -2
- package/.agents/skills/ai-agent-engineer/SKILL.md +1 -1
- package/.agents/skills/api-designer/SKILL.md +1 -1
- package/.agents/skills/architect/SKILL.md +1 -1
- package/.agents/skills/automation-engineer/SKILL.md +1 -1
- package/.agents/skills/backend-engineer/SKILL.md +1 -1
- package/.agents/skills/bmad-methodology/SKILL.md +1 -1
- package/.agents/skills/browser-agent/SKILL.md +1 -1
- package/.agents/skills/code-reviewer/SKILL.md +1 -1
- package/.agents/skills/data-engineer/SKILL.md +1 -1
- package/.agents/skills/devops-engineer/SKILL.md +1 -1
- package/.agents/skills/document-generator/SKILL.md +1 -1
- package/.agents/skills/frontend-engineer/SKILL.md +1 -1
- package/.agents/skills/git-workflow/SKILL.md +1 -1
- package/.agents/skills/mcp-builder/SKILL.md +1 -1
- package/.agents/skills/mobile-engineer/SKILL.md +1 -1
- package/.agents/skills/orchestrator/SKILL.md +1 -1
- package/.agents/skills/performance-engineer/SKILL.md +1 -1
- package/.agents/skills/product-manager/SKILL.md +1 -1
- package/.agents/skills/prompt-engineer/SKILL.md +1 -1
- package/.agents/skills/qa-engineer/SKILL.md +1 -1
- package/.agents/skills/scrum-master/SKILL.md +1 -1
- package/.agents/skills/security-analyst/SKILL.md +1 -1
- package/.agents/skills/seo-auditor/SKILL.md +1 -1
- package/.agents/skills/spec-driven-dev/SKILL.md +1 -1
- package/.agents/skills/supabase-expert/SKILL.md +1 -1
- package/.agents/skills/swe-agent/SKILL.md +1 -1
- package/.agents/skills/systematic-debugger/SKILL.md +1 -1
- package/.agents/skills/tech-lead/SKILL.md +1 -1
- package/.agents/skills/technical-writer/SKILL.md +1 -1
- package/.agents/skills/testing-strategist/SKILL.md +1 -1
- package/.agents/skills/ux-ui-designer/SKILL.md +1 -1
- package/AGENTS.md +1 -1
- package/CONTRIBUTING.md +3 -3
- package/README.md +19 -19
- package/install.js +40 -23
- package/package.json +4 -2
- package/scripts/create_skill.js +300 -0
- package/scripts/fix_descriptions.js +51 -0
- package/scripts/token-analyzer.js +275 -0
- 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
|
|
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ó
|
|
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
|
|
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.
|
|
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();
|