@qubiit/lmagent 3.1.2 → 3.1.3
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 +80 -31
- package/.agents/docs/getting-started.md +50 -46
- package/.agents/rules/00-master.md +2 -2
- package/.agents/skills/ai-agent-engineer/SKILL.md +15 -3
- package/.agents/skills/api-designer/SKILL.md +13 -3
- package/.agents/skills/architect/SKILL.md +42 -29
- package/.agents/skills/automation-engineer/SKILL.md +14 -3
- package/.agents/skills/backend-engineer/SKILL.md +17 -3
- package/.agents/skills/bmad-methodology/SKILL.md +12 -3
- package/.agents/skills/browser-agent/SKILL.md +12 -3
- package/.agents/skills/code-reviewer/SKILL.md +13 -3
- package/.agents/skills/data-engineer/SKILL.md +14 -3
- package/.agents/skills/devops-engineer/SKILL.md +14 -3
- package/.agents/skills/document-generator/SKILL.md +14 -3
- package/.agents/skills/frontend-engineer/SKILL.md +19 -3
- package/.agents/skills/git-workflow/SKILL.md +12 -3
- package/.agents/skills/mcp-builder/SKILL.md +14 -3
- package/.agents/skills/mobile-engineer/SKILL.md +14 -3
- package/.agents/skills/orchestrator/SKILL.md +14 -3
- package/.agents/skills/performance-engineer/SKILL.md +14 -3
- package/.agents/skills/product-manager/SKILL.md +14 -3
- package/.agents/skills/prompt-engineer/SKILL.md +12 -3
- package/.agents/skills/qa-engineer/SKILL.md +14 -3
- package/.agents/skills/scrum-master/SKILL.md +12 -3
- package/.agents/skills/security-analyst/SKILL.md +14 -3
- package/.agents/skills/seo-auditor/SKILL.md +13 -3
- package/.agents/skills/spec-driven-dev/SKILL.md +14 -3
- package/.agents/skills/supabase-expert/SKILL.md +14 -3
- package/.agents/skills/swe-agent/SKILL.md +16 -3
- package/.agents/skills/systematic-debugger/SKILL.md +13 -3
- package/.agents/skills/tech-lead/SKILL.md +14 -3
- package/.agents/skills/technical-writer/SKILL.md +14 -3
- package/.agents/skills/testing-strategist/SKILL.md +13 -3
- package/.agents/skills/ux-ui-designer/SKILL.md +14 -3
- package/.agents/templates/agent-configs/_generic.md +20 -0
- package/.agents/templates/agent-configs/continuerules.md +17 -0
- package/.agents/templates/agent-configs/goosehints.md +19 -0
- package/.agents/templates/agent-configs/junie-guidelines.md +22 -0
- package/.agents/templates/agent-configs/openclaw.json +17 -0
- package/.agents/templates/agent-configs/openhands-repo.md +21 -0
- package/AGENTS.md +171 -84
- package/CLAUDE.md +2 -2
- package/CONTRIBUTING.md +112 -49
- package/README.md +211 -242
- package/install.js +423 -363
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -10,6 +10,7 @@ const figlet = require('figlet');
|
|
|
10
10
|
const gradient = require('gradient-string');
|
|
11
11
|
|
|
12
12
|
const program = new Command();
|
|
13
|
+
const PKG_VERSION = require('./package.json').version;
|
|
13
14
|
|
|
14
15
|
// Configuración: Directorios fuente del paquete
|
|
15
16
|
const PACKAGE_SKILLS_DIR = path.join(__dirname, '.agents', 'skills');
|
|
@@ -21,9 +22,11 @@ const PACKAGE_DOCS_DIR = path.join(__dirname, '.agents', 'docs');
|
|
|
21
22
|
const PACKAGE_MEMORY_DIR = path.join(__dirname, '.agents', 'memory');
|
|
22
23
|
|
|
23
24
|
// Archivos de proyecto que init copia a la raíz
|
|
25
|
+
// Usan {{VERSION}} como placeholder; se reemplaza dinámicamente al instalar
|
|
24
26
|
const INIT_FILES = [
|
|
25
|
-
{ src: 'CLAUDE.md', desc: 'Instrucciones para Claude Code' },
|
|
26
|
-
{ src: '
|
|
27
|
+
{ src: 'CLAUDE.md', desc: 'Instrucciones para Claude Code / Antigravity', versionTemplate: true },
|
|
28
|
+
{ src: 'GEMINI.md', desc: 'Instrucciones para Gemini CLI / Antigravity', versionTemplate: true },
|
|
29
|
+
{ src: 'AGENTS.md', desc: 'Catálogo de capacidades LMAgent', versionTemplate: false },
|
|
27
30
|
];
|
|
28
31
|
|
|
29
32
|
const INIT_DIRS = [
|
|
@@ -33,322 +36,78 @@ const INIT_DIRS = [
|
|
|
33
36
|
{ src: 'workflows', desc: 'SOPs y Procedimientos' },
|
|
34
37
|
];
|
|
35
38
|
|
|
36
|
-
//
|
|
37
|
-
// Configuración: IDEs y Agentes soportados
|
|
39
|
+
// IDE_CONFIGS: Lista ÚNICA y DEDUPLICADA de todos los agentes soportados
|
|
38
40
|
const IDE_CONFIGS = [
|
|
39
|
-
// --- IDEs
|
|
41
|
+
// --- IDEs Principales (Auto-Detectados) ---
|
|
42
|
+
// Cursor: usa .cursor/rules/*.mdc (formato MDC con frontmatter)
|
|
40
43
|
{ name: 'Cursor', value: 'cursor', rulesDir: '.cursor/rules', skillsDir: '.cursor/skills', workflowsDir: '.cursor/workflows', configFile: '.cursorrules', bridgeFile: 'lmagent.mdc', markerFile: '.cursorrules', forceCopy: true },
|
|
41
|
-
|
|
44
|
+
// Windsurf Wave 8+: usa .windsurf/rules/*.md (directorio, NO .windsurfrules)
|
|
45
|
+
{ name: 'Windsurf', value: 'windsurf', rulesDir: '.windsurf/rules', skillsDir: '.windsurf/skills', workflowsDir: '.windsurf/workflows', configFile: null, bridgeFile: 'lmagent.md', markerFile: '.windsurf', forceCopy: true },
|
|
46
|
+
// Cline: usa .clinerules/ (directorio con .md files)
|
|
42
47
|
{ name: 'Cline', value: 'cline', rulesDir: '.clinerules', skillsDir: '.cline/skills', workflowsDir: '.cline/workflows', configFile: null, bridgeFile: '00-lmagent.md', markerFile: '.clinerules', forceCopy: true },
|
|
43
|
-
|
|
44
|
-
{ name: '
|
|
48
|
+
// Roo Code: usa .roo/rules/ (NO .clinerules, que es de Cline)
|
|
49
|
+
{ name: 'Roo Code', value: 'roo', rulesDir: '.roo/rules', skillsDir: '.roo/skills', workflowsDir: '.roo/workflows', configFile: null, bridgeFile: '00-lmagent.md', markerFile: '.roo', forceCopy: true },
|
|
50
|
+
// GitHub Copilot: usa .github/copilot-instructions.md + .github/instructions/*.md
|
|
51
|
+
{ name: 'VSCode Copilot', value: 'vscode', rulesDir: '.github/instructions', skillsDir: '.github/skills', workflowsDir: '.github/workflows', configFile: '.github/copilot-instructions.md', bridgeFile: null, markerFile: '.vscode' },
|
|
45
52
|
{ name: 'Trae', value: 'trae', rulesDir: '.trae/rules', skillsDir: '.trae/skills', workflowsDir: '.trae/workflows', configFile: null, bridgeFile: 'lmagent.md', markerFile: '.trae', forceCopy: true },
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
{ name: '
|
|
52
|
-
|
|
53
|
-
{ name: '
|
|
54
|
-
{ name: '
|
|
55
|
-
|
|
56
|
-
{ name: '
|
|
57
|
-
{ name: '
|
|
58
|
-
{ name: '
|
|
59
|
-
|
|
60
|
-
{ name: '
|
|
61
|
-
{ name: '
|
|
62
|
-
|
|
63
|
-
{ name: '
|
|
64
|
-
{ name: '
|
|
65
|
-
{ name: '
|
|
66
|
-
|
|
67
|
-
{ name: '
|
|
68
|
-
|
|
69
|
-
{ name: '
|
|
70
|
-
{ name: '
|
|
71
|
-
{ name: '
|
|
72
|
-
{ name: '
|
|
73
|
-
{ name: '
|
|
53
|
+
// Claude Code: usa CLAUDE.md (raíz) + .claude/rules/ + .claude/skills/
|
|
54
|
+
{ name: 'Claude Code', value: 'claude', rulesDir: '.claude/rules', skillsDir: '.claude/skills', workflowsDir: '.claude/workflows', configFile: 'CLAUDE.md', bridgeFile: null, markerFile: '.claude', forceCopy: true },
|
|
55
|
+
{ name: 'Zed', value: 'zed', rulesDir: '.rules', skillsDir: '.rules/skills', workflowsDir: '.rules/workflows', configFile: null, bridgeFile: 'lmagent.md', markerFile: '.zed' },
|
|
56
|
+
|
|
57
|
+
// --- Agentes CLI & Autónomos ---
|
|
58
|
+
{ name: 'Amp / Kimi / Replit', value: 'amp', rulesDir: '.agents/rules', skillsDir: '.agents/skills', workflowsDir: '.agents/workflows', configFile: null, bridgeFile: null, markerFile: '.agents' },
|
|
59
|
+
// Antigravity (Google Deepmind): usa GEMINI.md (raíz) + .agent/skills/ + .agent/rules/
|
|
60
|
+
{ name: 'Antigravity', value: 'antigravity', rulesDir: '.agent/rules', skillsDir: '.agent/skills', workflowsDir: '.agent/workflows', configFile: 'GEMINI.md', bridgeFile: null, markerFile: '.agent' },
|
|
61
|
+
{ name: 'Augment', value: 'augment', rulesDir: '.augment/rules', skillsDir: '.augment/skills', workflowsDir: '.augment/workflows', configFile: null, bridgeFile: null, markerFile: '.augment' },
|
|
62
|
+
// Gemini CLI: usa GEMINI.md (raíz) + .gemini/skills/ (oficial) o .agents/skills/ (fallback)
|
|
63
|
+
{ name: 'Gemini CLI', value: 'gemini', rulesDir: '.gemini/rules', skillsDir: '.gemini/skills', workflowsDir: '.gemini/workflows', configFile: 'GEMINI.md', bridgeFile: null, markerFile: '.gemini' },
|
|
64
|
+
{ name: 'OpenClaw / Envoid', value: 'openclaw', rulesDir: 'rules', skillsDir: 'skills', workflowsDir: 'workflows', configFile: 'openclaw.json', configTemplate: 'openclaw.json', bridgeFile: null, markerFile: 'openclaw.json' },
|
|
65
|
+
{ name: 'CodeBuddy', value: 'codebuddy', rulesDir: '.codebuddy/rules', skillsDir: '.codebuddy/skills', workflowsDir: '.codebuddy/workflows', configFile: null, bridgeFile: null, markerFile: '.codebuddy', forceCopy: true },
|
|
66
|
+
// Codex CLI (OpenAI): usa AGENTS.md en raíz + .codex/ como directorio de config
|
|
67
|
+
{ name: 'Codex', value: 'codex', rulesDir: '.codex', skillsDir: '.codex/skills', workflowsDir: '.codex/workflows', configFile: 'AGENTS.md', bridgeFile: null, markerFile: '.codex' },
|
|
68
|
+
{ name: 'Command Code', value: 'command-code', rulesDir: '.commandcode/rules', skillsDir: '.commandcode/skills', workflowsDir: '.commandcode/workflows', configFile: null, bridgeFile: null, markerFile: '.commandcode' },
|
|
69
|
+
// Continue: soporta .continuerules (raíz) + .continue/rules/ (directorio)
|
|
70
|
+
{ name: 'Continue', value: 'continue', rulesDir: '.continue/rules', skillsDir: '.continue/skills', workflowsDir: '.continue/workflows', configFile: '.continuerules', configTemplate: 'continuerules.md', bridgeFile: '00-lmagent.md', markerFile: '.continue' },
|
|
71
|
+
{ name: 'Crush', value: 'crush', rulesDir: '.crush/rules', skillsDir: '.crush/skills', workflowsDir: '.crush/workflows', configFile: null, bridgeFile: null, markerFile: '.crush' },
|
|
72
|
+
{ name: 'Droid', value: 'droid', rulesDir: '.factory/rules', skillsDir: '.factory/skills', workflowsDir: '.factory/workflows', configFile: null, bridgeFile: null, markerFile: '.factory' },
|
|
73
|
+
// Goose (Block): usa .goosehints en raíz para instrucciones al agente
|
|
74
|
+
{ name: 'Goose', value: 'goose', rulesDir: '.goose', skillsDir: '.goose/skills', workflowsDir: '.goose/workflows', configFile: '.goosehints', configTemplate: 'goosehints.md', bridgeFile: null, markerFile: '.goose' },
|
|
75
|
+
// Junie (JetBrains): usa .junie/guidelines.md como archivo de instrucciones
|
|
76
|
+
{ name: 'Junie', value: 'junie', rulesDir: '.junie', skillsDir: '.junie/skills', workflowsDir: '.junie/workflows', configFile: '.junie/guidelines.md', configTemplate: 'junie-guidelines.md', bridgeFile: null, markerFile: '.junie' },
|
|
77
|
+
{ name: 'iFlow CLI', value: 'iflow', rulesDir: '.iflow/rules', skillsDir: '.iflow/skills', workflowsDir: '.iflow/workflows', configFile: null, bridgeFile: null, markerFile: '.iflow' },
|
|
78
|
+
{ name: 'Kilo Code', value: 'kilo', rulesDir: '.kilocode/rules', skillsDir: '.kilocode/skills', workflowsDir: '.kilocode/workflows', configFile: null, bridgeFile: null, markerFile: '.kilocode' },
|
|
79
|
+
{ name: 'Kiro CLI', value: 'kiro', rulesDir: '.kiro/rules', skillsDir: '.kiro/skills', workflowsDir: '.kiro/workflows', configFile: null, bridgeFile: null, markerFile: '.kiro' },
|
|
80
|
+
{ name: 'Kode', value: 'kode', rulesDir: '.kode/rules', skillsDir: '.kode/skills', workflowsDir: '.kode/workflows', configFile: null, bridgeFile: null, markerFile: '.kode' },
|
|
81
|
+
{ name: 'MCPJam', value: 'mcpjam', rulesDir: '.mcpjam/rules', skillsDir: '.mcpjam/skills', workflowsDir: '.mcpjam/workflows', configFile: null, bridgeFile: null, markerFile: '.mcpjam' },
|
|
82
|
+
{ name: 'Mistral Vibe', value: 'mistral', rulesDir: '.vibe/rules', skillsDir: '.vibe/skills', workflowsDir: '.vibe/workflows', configFile: null, bridgeFile: null, markerFile: '.vibe' },
|
|
83
|
+
{ name: 'Mux', value: 'mux', rulesDir: '.mux/rules', skillsDir: '.mux/skills', workflowsDir: '.mux/workflows', configFile: null, bridgeFile: null, markerFile: '.mux' },
|
|
84
|
+
{ name: 'OpenCode', value: 'opencode', rulesDir: '.opencode/rules', skillsDir: '.opencode/skills', workflowsDir: '.opencode/workflows', configFile: null, bridgeFile: null, markerFile: '.opencode' },
|
|
85
|
+
// OpenHands: usa .openhands/microagents/repo.md para instrucciones del repo
|
|
86
|
+
{ name: 'OpenHands', value: 'openhands', rulesDir: '.openhands/microagents', skillsDir: '.openhands/skills', workflowsDir: '.openhands/workflows', configFile: '.openhands/microagents/repo.md', configTemplate: 'openhands-repo.md', bridgeFile: null, markerFile: '.openhands' },
|
|
87
|
+
{ name: 'Pi', value: 'pi', rulesDir: '.pi/rules', skillsDir: '.pi/skills', workflowsDir: '.pi/workflows', configFile: null, bridgeFile: null, markerFile: '.pi' },
|
|
88
|
+
{ name: 'Qoder', value: 'qoder', rulesDir: '.qoder/rules', skillsDir: '.qoder/skills', workflowsDir: '.qoder/workflows', configFile: null, bridgeFile: null, markerFile: '.qoder' },
|
|
89
|
+
{ name: 'Qwen Code', value: 'qwen', rulesDir: '.qwen/rules', skillsDir: '.qwen/skills', workflowsDir: '.qwen/workflows', configFile: null, bridgeFile: null, markerFile: '.qwen' },
|
|
74
90
|
{ name: 'Trae CN', value: 'trae-cn', rulesDir: '.trae-cn/rules', skillsDir: '.trae-cn/skills', workflowsDir: '.trae-cn/workflows', configFile: null, bridgeFile: 'lmagent.md', markerFile: '.trae-cn' },
|
|
75
|
-
{ name: 'Zencoder', value: 'zencoder', rulesDir: '.zencoder/rules', skillsDir: '.zencoder/skills', workflowsDir: '.zencoder/workflows', configFile: null, markerFile: '.zencoder' },
|
|
76
|
-
{ name: 'Neovate', value: 'neovate', rulesDir: '.neovate/rules', skillsDir: '.neovate/skills', workflowsDir: '.neovate/workflows', configFile: null, markerFile: '.neovate' },
|
|
77
|
-
{ name: 'Pochi', value: 'pochi', rulesDir: '.pochi/rules', skillsDir: '.pochi/skills', workflowsDir: '.pochi/workflows', configFile: null, markerFile: '.pochi' },
|
|
78
|
-
{ name: 'AdaL', value: 'adal', rulesDir: '.adal/rules', skillsDir: '.adal/skills', workflowsDir: '.adal/workflows', configFile: null, markerFile: '.adal' },
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
rulesDir: '.agents/rules',
|
|
84
|
-
skillsDir: '.gemini/skills',
|
|
85
|
-
workflowsDir: '.agents/workflows',
|
|
86
|
-
configFile: '.gemini/config',
|
|
87
|
-
markerFile: '.gemini'
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'Continue',
|
|
91
|
-
value: 'continue',
|
|
92
|
-
rulesDir: '.continue/rules',
|
|
93
|
-
skillsDir: '.continue/skills',
|
|
94
|
-
workflowsDir: '.continue/workflows',
|
|
95
|
-
configFile: '.continue/config.json',
|
|
96
|
-
markerFile: '.continue'
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
name: 'OpenCode',
|
|
100
|
-
value: 'opencode',
|
|
101
|
-
rulesDir: '.agents/rules',
|
|
102
|
-
skillsDir: '.config/opencode/skills',
|
|
103
|
-
workflowsDir: '.agents/workflows',
|
|
104
|
-
configFile: '.opencode/config',
|
|
105
|
-
markerFile: '.opencode'
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
name: 'OpenHands',
|
|
109
|
-
value: 'openhands',
|
|
110
|
-
rulesDir: '.openhands/rules',
|
|
111
|
-
skillsDir: '.openhands/skills',
|
|
112
|
-
workflowsDir: '.openhands/workflows',
|
|
113
|
-
configFile: '.openhands/config',
|
|
114
|
-
markerFile: '.openhands'
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
name: 'Goose',
|
|
118
|
-
value: 'goose',
|
|
119
|
-
rulesDir: '.goose/rules',
|
|
120
|
-
skillsDir: '.goose/skills',
|
|
121
|
-
workflowsDir: '.goose/workflows',
|
|
122
|
-
configFile: '.goose/config',
|
|
123
|
-
markerFile: '.goose'
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: 'Mistral Vibe',
|
|
127
|
-
value: 'vibe',
|
|
128
|
-
rulesDir: '.vibe/rules',
|
|
129
|
-
skillsDir: '.vibe/skills',
|
|
130
|
-
workflowsDir: '.vibe/workflows',
|
|
131
|
-
configFile: '.vibe/config',
|
|
132
|
-
markerFile: '.vibe'
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: 'Zed',
|
|
136
|
-
value: 'zed',
|
|
137
|
-
rulesDir: '.rules',
|
|
138
|
-
skillsDir: '.rules/skills',
|
|
139
|
-
workflowsDir: '.rules/workflows',
|
|
140
|
-
configFile: '.rules/config',
|
|
141
|
-
markerFile: '.zed'
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
name: 'Envoid (OpenClaw / Moltbot)',
|
|
145
|
-
value: 'openclaw',
|
|
146
|
-
rulesDir: 'rules',
|
|
147
|
-
skillsDir: 'skills',
|
|
148
|
-
workflowsDir: 'workflows',
|
|
149
|
-
configFile: 'openclaw.json',
|
|
150
|
-
markerFile: 'openclaw.json'
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
name: 'CodeBuddy',
|
|
154
|
-
value: 'codebuddy',
|
|
155
|
-
rulesDir: '.codebuddy/rules',
|
|
156
|
-
skillsDir: '.codebuddy/skills',
|
|
157
|
-
workflowsDir: '.codebuddy/workflows',
|
|
158
|
-
configFile: '.codebuddy/config',
|
|
159
|
-
markerFile: '.codebuddy',
|
|
160
|
-
forceCopy: true
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
name: 'Command Code',
|
|
164
|
-
value: 'command-code',
|
|
165
|
-
rulesDir: '.commandcode/rules',
|
|
166
|
-
skillsDir: '.commandcode/skills',
|
|
167
|
-
workflowsDir: '.commandcode/workflows',
|
|
168
|
-
configFile: '.commandcode/config',
|
|
169
|
-
markerFile: '.commandcode'
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
name: 'Crush',
|
|
173
|
-
value: 'crush',
|
|
174
|
-
rulesDir: '.crush/rules',
|
|
175
|
-
skillsDir: '.crush/skills',
|
|
176
|
-
workflowsDir: '.crush/workflows',
|
|
177
|
-
configFile: '.crush/config',
|
|
178
|
-
markerFile: '.crush'
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
name: 'Droid',
|
|
182
|
-
value: 'droid',
|
|
183
|
-
rulesDir: '.factory/rules',
|
|
184
|
-
skillsDir: '.factory/skills',
|
|
185
|
-
workflowsDir: '.factory/workflows',
|
|
186
|
-
configFile: '.factory/config',
|
|
187
|
-
markerFile: '.factory'
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
name: 'Junie',
|
|
191
|
-
value: 'junie',
|
|
192
|
-
rulesDir: '.junie/rules',
|
|
193
|
-
skillsDir: '.junie/skills',
|
|
194
|
-
workflowsDir: '.junie/workflows',
|
|
195
|
-
configFile: '.junie/config',
|
|
196
|
-
markerFile: '.junie'
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
name: 'iFlow',
|
|
200
|
-
value: 'iflow',
|
|
201
|
-
rulesDir: '.iflow/rules',
|
|
202
|
-
skillsDir: '.iflow/skills',
|
|
203
|
-
workflowsDir: '.iflow/workflows',
|
|
204
|
-
configFile: '.iflow/config',
|
|
205
|
-
markerFile: '.iflow'
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
name: 'Kilo Code',
|
|
209
|
-
value: 'kilo',
|
|
210
|
-
rulesDir: '.kilocode/rules',
|
|
211
|
-
skillsDir: '.kilocode/skills',
|
|
212
|
-
workflowsDir: '.kilocode/workflows',
|
|
213
|
-
configFile: '.kilocode/config',
|
|
214
|
-
markerFile: '.kilocode'
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
name: 'Kiro',
|
|
218
|
-
value: 'kiro',
|
|
219
|
-
rulesDir: '.kiro/rules',
|
|
220
|
-
skillsDir: '.kiro/skills',
|
|
221
|
-
workflowsDir: '.kiro/workflows',
|
|
222
|
-
configFile: '.kiro/config',
|
|
223
|
-
markerFile: '.kiro'
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
name: 'Kode',
|
|
227
|
-
value: 'kode',
|
|
228
|
-
rulesDir: '.kode/rules',
|
|
229
|
-
skillsDir: '.kode/skills',
|
|
230
|
-
workflowsDir: '.kode/workflows',
|
|
231
|
-
configFile: '.kode/config',
|
|
232
|
-
markerFile: '.kode'
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
name: 'MCPJam',
|
|
236
|
-
value: 'mcpjam',
|
|
237
|
-
rulesDir: '.mcpjam/rules',
|
|
238
|
-
skillsDir: '.mcpjam/skills',
|
|
239
|
-
workflowsDir: '.mcpjam/workflows',
|
|
240
|
-
configFile: '.mcpjam/config',
|
|
241
|
-
markerFile: '.mcpjam'
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
name: 'Mux',
|
|
245
|
-
value: 'mux',
|
|
246
|
-
rulesDir: '.mux/rules',
|
|
247
|
-
skillsDir: '.mux/skills',
|
|
248
|
-
workflowsDir: '.mux/workflows',
|
|
249
|
-
configFile: '.mux/config',
|
|
250
|
-
markerFile: '.mux'
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
name: 'Pi',
|
|
254
|
-
value: 'pi',
|
|
255
|
-
rulesDir: '.pi/rules',
|
|
256
|
-
skillsDir: '.pi/skills',
|
|
257
|
-
workflowsDir: '.pi/workflows',
|
|
258
|
-
configFile: '.pi/config',
|
|
259
|
-
markerFile: '.pi'
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
name: 'Qoder',
|
|
263
|
-
value: 'qoder',
|
|
264
|
-
rulesDir: '.qoder/rules',
|
|
265
|
-
skillsDir: '.qoder/skills',
|
|
266
|
-
workflowsDir: '.qoder/workflows',
|
|
267
|
-
configFile: '.qoder/config',
|
|
268
|
-
markerFile: '.qoder'
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
name: 'Qwen Code',
|
|
272
|
-
value: 'qwen',
|
|
273
|
-
rulesDir: '.qwen/rules',
|
|
274
|
-
skillsDir: '.qwen/skills',
|
|
275
|
-
workflowsDir: '.qwen/workflows',
|
|
276
|
-
configFile: '.qwen/config',
|
|
277
|
-
markerFile: '.qwen'
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
name: 'Trae CN',
|
|
281
|
-
value: 'trae-cn',
|
|
282
|
-
rulesDir: '.trae-cn/rules',
|
|
283
|
-
skillsDir: '.trae-cn/skills',
|
|
284
|
-
workflowsDir: '.trae-cn/workflows',
|
|
285
|
-
configFile: '.trae-cn/config',
|
|
286
|
-
markerFile: '.trae-cn'
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
name: 'Zencoder',
|
|
290
|
-
value: 'zencoder',
|
|
291
|
-
rulesDir: '.zencoder/rules',
|
|
292
|
-
skillsDir: '.zencoder/skills',
|
|
293
|
-
workflowsDir: '.zencoder/workflows',
|
|
294
|
-
configFile: '.zencoder/config',
|
|
295
|
-
markerFile: '.zencoder'
|
|
296
|
-
},
|
|
297
|
-
{
|
|
298
|
-
name: 'Neovate',
|
|
299
|
-
value: 'neovate',
|
|
300
|
-
rulesDir: '.neovate/rules',
|
|
301
|
-
skillsDir: '.neovate/skills',
|
|
302
|
-
workflowsDir: '.neovate/workflows',
|
|
303
|
-
configFile: '.neovate/config',
|
|
304
|
-
markerFile: '.neovate'
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
name: 'Pochi',
|
|
308
|
-
value: 'pochi',
|
|
309
|
-
rulesDir: '.pochi/rules',
|
|
310
|
-
skillsDir: '.pochi/skills',
|
|
311
|
-
workflowsDir: '.pochi/workflows',
|
|
312
|
-
configFile: '.pochi/config',
|
|
313
|
-
markerFile: '.pochi'
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
name: 'AdaL',
|
|
317
|
-
value: 'adal',
|
|
318
|
-
rulesDir: '.adal/rules',
|
|
319
|
-
skillsDir: '.adal/skills',
|
|
320
|
-
workflowsDir: '.adal/workflows',
|
|
321
|
-
configFile: '.adal/config',
|
|
322
|
-
markerFile: '.adal'
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
name: 'Generic/Other',
|
|
326
|
-
value: 'generic',
|
|
327
|
-
rulesDir: '.agents/rules',
|
|
328
|
-
skillsDir: '.agents/skills',
|
|
329
|
-
workflowsDir: '.agents/workflows',
|
|
330
|
-
configFile: 'AGENTS.md',
|
|
331
|
-
markerFile: '.agents'
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
name: 'Custom Path (Manual)',
|
|
335
|
-
value: 'custom',
|
|
336
|
-
rulesDir: '',
|
|
337
|
-
skillsDir: '',
|
|
338
|
-
workflowsDir: '',
|
|
339
|
-
markerFile: ''
|
|
340
|
-
}
|
|
91
|
+
{ name: 'Zencoder', value: 'zencoder', rulesDir: '.zencoder/rules', skillsDir: '.zencoder/skills', workflowsDir: '.zencoder/workflows', configFile: null, bridgeFile: null, markerFile: '.zencoder' },
|
|
92
|
+
{ name: 'Neovate', value: 'neovate', rulesDir: '.neovate/rules', skillsDir: '.neovate/skills', workflowsDir: '.neovate/workflows', configFile: null, bridgeFile: null, markerFile: '.neovate' },
|
|
93
|
+
{ name: 'Pochi', value: 'pochi', rulesDir: '.pochi/rules', skillsDir: '.pochi/skills', workflowsDir: '.pochi/workflows', configFile: null, bridgeFile: null, markerFile: '.pochi' },
|
|
94
|
+
{ name: 'AdaL', value: 'adal', rulesDir: '.adal/rules', skillsDir: '.adal/skills', workflowsDir: '.adal/workflows', configFile: null, bridgeFile: null, markerFile: '.adal' },
|
|
95
|
+
|
|
96
|
+
// --- Opciones Especiales ---
|
|
97
|
+
{ name: 'Generic/Other', value: 'generic', rulesDir: '.agents/rules', skillsDir: '.agents/skills', workflowsDir: '.agents/workflows', configFile: 'AGENTS.md', bridgeFile: null, markerFile: '.agents' },
|
|
98
|
+
{ name: 'Custom Path (Manual)', value: 'custom', rulesDir: '', skillsDir: '', workflowsDir: '', configFile: null, bridgeFile: null, markerFile: '' },
|
|
341
99
|
];
|
|
342
100
|
|
|
343
101
|
program
|
|
344
102
|
.name('lmagent')
|
|
345
103
|
.description('CLI para instalar skills y reglas de LMAgent')
|
|
346
|
-
.version(
|
|
104
|
+
.version(PKG_VERSION);
|
|
347
105
|
|
|
348
106
|
program.command('install')
|
|
349
107
|
.description('Instalar skills, rules y workflows en el IDE del proyecto')
|
|
350
108
|
.option('-f, --force', 'Forzar instalación')
|
|
351
109
|
.option('-y, --yes', 'Instalar todo sin preguntar')
|
|
110
|
+
.option('-g, --global', 'También sincronizar al repositorio global (~/.agents/)')
|
|
352
111
|
.action((options) => {
|
|
353
112
|
runInstall(options);
|
|
354
113
|
});
|
|
@@ -357,6 +116,7 @@ program.command('update')
|
|
|
357
116
|
.description('Actualizar skills y reglas en el proyecto (alias de install)')
|
|
358
117
|
.option('-f, --force', 'Forzar actualización')
|
|
359
118
|
.option('-y, --yes', 'Instalar todo sin preguntar')
|
|
119
|
+
.option('-g, --global', 'También sincronizar al repositorio global (~/.agents/)')
|
|
360
120
|
.action((options) => {
|
|
361
121
|
console.log(chalk.blue('ℹ Iniciando actualización...'));
|
|
362
122
|
runInstall(options);
|
|
@@ -402,19 +162,226 @@ program.command('create-skill')
|
|
|
402
162
|
}
|
|
403
163
|
});
|
|
404
164
|
|
|
165
|
+
program.command('tokens')
|
|
166
|
+
.description('Analizar consumo de tokens del framework instalado en el proyecto')
|
|
167
|
+
.option('--json', 'Salida en formato JSON')
|
|
168
|
+
.option('--report', 'Generar reporte en .agents/token-report.md')
|
|
169
|
+
.action((options) => {
|
|
170
|
+
const { execSync } = require('child_process');
|
|
171
|
+
const scriptPath = path.join(__dirname, 'scripts', 'token-analyzer.js');
|
|
172
|
+
const args = [options.json ? '--json' : '', options.report ? '--report' : ''].filter(Boolean).join(' ');
|
|
173
|
+
try {
|
|
174
|
+
execSync(`node "${scriptPath}" ${args}`, { stdio: 'inherit' });
|
|
175
|
+
} catch (e) {
|
|
176
|
+
process.exit(e.status || 1);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
program.command('skills')
|
|
181
|
+
.description('Gestionar skills externos desde GitHub (compatible con el estándar skills.sh)')
|
|
182
|
+
.argument('<action>', 'Acción: add')
|
|
183
|
+
.argument('<source>', 'Repositorio GitHub: owner/repo o URL completa')
|
|
184
|
+
.option('--skill <name>', 'Nombre específico del skill a instalar (opcional)')
|
|
185
|
+
.action(async (action, source, opts) => {
|
|
186
|
+
if (action !== 'add') {
|
|
187
|
+
console.error(chalk.red(`❌ Acción desconocida: ${action}. Usa: lmagent skills add <owner/repo>`));
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
const { execSync } = require('child_process');
|
|
191
|
+
const repoSlug = source.replace('https://github.com/', '').replace(/\.git$/, '');
|
|
192
|
+
const [owner, repo] = repoSlug.split('/');
|
|
193
|
+
if (!owner || !repo) {
|
|
194
|
+
console.error(chalk.red('❌ Formato inválido. Usa: lmagent skills add owner/repo'));
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
const tmpDir = path.join(os.tmpdir(), `lmagent-skill-${Date.now()}`);
|
|
198
|
+
const targetSkillsDir = path.join(process.cwd(), '.agents', 'skills');
|
|
199
|
+
console.log(chalk.cyan(`📦 Descargando skill desde github.com/${owner}/${repo}...`));
|
|
200
|
+
try {
|
|
201
|
+
execSync(`git clone --depth 1 https://github.com/${owner}/${repo} "${tmpDir}"`, { stdio: 'pipe' });
|
|
202
|
+
const skillsPath = fs.existsSync(path.join(tmpDir, 'skills')) ? path.join(tmpDir, 'skills') : tmpDir;
|
|
203
|
+
const items = fs.readdirSync(skillsPath).filter(i => {
|
|
204
|
+
const p = path.join(skillsPath, i);
|
|
205
|
+
return fs.statSync(p).isDirectory() && fs.existsSync(path.join(p, 'SKILL.md'));
|
|
206
|
+
});
|
|
207
|
+
if (items.length === 0) {
|
|
208
|
+
console.log(chalk.yellow('⚠️ No se encontraron skills con SKILL.md en el repositorio.'));
|
|
209
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const toInstall = opts.skill ? items.filter(i => i.includes(opts.skill)) : items;
|
|
213
|
+
if (!fs.existsSync(targetSkillsDir)) fs.mkdirSync(targetSkillsDir, { recursive: true });
|
|
214
|
+
for (const skill of toInstall) {
|
|
215
|
+
const src = path.join(skillsPath, skill);
|
|
216
|
+
const dest = path.join(targetSkillsDir, skill);
|
|
217
|
+
copyRecursiveSync(src, dest, true);
|
|
218
|
+
console.log(` ${chalk.green('✔')} ${skill}/`);
|
|
219
|
+
}
|
|
220
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
221
|
+
console.log(chalk.green(`✨ ${toInstall.length} skill(s) instalado(s) en .agents/skills/`));
|
|
222
|
+
console.log(chalk.dim(' Ejecuta `lmagent install` para sincronizarlos a tu agente.'));
|
|
223
|
+
} catch (e) {
|
|
224
|
+
console.error(chalk.red(`❌ Error al instalar skill: ${e.message}`));
|
|
225
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_) { }
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
program.command('uninstall')
|
|
231
|
+
.description('Eliminar todos los archivos instalados por LMAgent del proyecto')
|
|
232
|
+
.option('-f, --force', 'No pedir confirmación, eliminar directamente')
|
|
233
|
+
.option('--all', 'También eliminar entry points raíz (CLAUDE.md, GEMINI.md, AGENTS.md)')
|
|
234
|
+
.action(async (options) => {
|
|
235
|
+
console.clear();
|
|
236
|
+
const branding = figlet.textSync('LMAGENT', { font: 'ANSI Shadow' });
|
|
237
|
+
console.log(gradient.pastel.multiline(branding));
|
|
238
|
+
console.log(gradient.cristal(' Uninstall - Limpieza\n'));
|
|
239
|
+
|
|
240
|
+
const projectRoot = process.cwd();
|
|
241
|
+
|
|
242
|
+
// Detectar qué agentes están instalados en el proyecto
|
|
243
|
+
const installedIdes = IDE_CONFIGS.filter(ide => {
|
|
244
|
+
if (ide.value === 'custom' || ide.value === 'generic') return false;
|
|
245
|
+
const markerInProject = ide.markerFile && fs.existsSync(path.join(projectRoot, ide.markerFile));
|
|
246
|
+
const rulesDirInProject = ide.rulesDir && fs.existsSync(path.join(projectRoot, ide.rulesDir));
|
|
247
|
+
const skillsDirInProject = ide.skillsDir && fs.existsSync(path.join(projectRoot, ide.skillsDir));
|
|
248
|
+
return markerInProject || rulesDirInProject || skillsDirInProject;
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
if (installedIdes.length === 0) {
|
|
252
|
+
console.log(chalk.yellow('⚠️ No se detectó ningún agente instalado en este proyecto.'));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
console.log(chalk.bold('🔍 Agentes detectados en este proyecto:\n'));
|
|
257
|
+
for (const ide of installedIdes) {
|
|
258
|
+
const parts = [];
|
|
259
|
+
if (ide.rulesDir && fs.existsSync(path.join(projectRoot, ide.rulesDir))) parts.push(chalk.gray(ide.rulesDir));
|
|
260
|
+
if (ide.skillsDir && fs.existsSync(path.join(projectRoot, ide.skillsDir))) parts.push(chalk.gray(ide.skillsDir));
|
|
261
|
+
if (ide.configFile && fs.existsSync(path.join(projectRoot, ide.configFile))) parts.push(chalk.gray(ide.configFile));
|
|
262
|
+
console.log(` ${chalk.cyan('•')} ${chalk.bold(ide.name)}: ${parts.join(', ')}`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Entry points raíz
|
|
266
|
+
const rootFiles = ['CLAUDE.md', 'GEMINI.md', 'AGENTS.md', '.cursorrules', '.windsurfrules', '.continuerules', '.goosehints'];
|
|
267
|
+
const existingRootFiles = rootFiles.filter(f => fs.existsSync(path.join(projectRoot, f)));
|
|
268
|
+
|
|
269
|
+
if (options.all && existingRootFiles.length > 0) {
|
|
270
|
+
console.log(chalk.bold('\n📄 Entry points raíz que también se eliminarán:'));
|
|
271
|
+
for (const f of existingRootFiles) {
|
|
272
|
+
console.log(` ${chalk.red('•')} ${f}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
console.log('');
|
|
277
|
+
|
|
278
|
+
if (!options.force) {
|
|
279
|
+
const { confirm } = await inquirer.prompt([{
|
|
280
|
+
type: 'confirm',
|
|
281
|
+
name: 'confirm',
|
|
282
|
+
message: chalk.red(`⚠️ ¿Eliminar todos los archivos de LMAgent de este proyecto? Esta acción no se puede deshacer.`),
|
|
283
|
+
default: false
|
|
284
|
+
}]);
|
|
285
|
+
if (!confirm) {
|
|
286
|
+
console.log(chalk.gray('Cancelado.'));
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
console.log('');
|
|
292
|
+
let removed = 0;
|
|
293
|
+
let errors = 0;
|
|
294
|
+
|
|
295
|
+
// Eliminar directorios y archivos de cada agente
|
|
296
|
+
for (const ide of installedIdes) {
|
|
297
|
+
const toRemove = [];
|
|
298
|
+
|
|
299
|
+
// Directorios del agente (skills, rules, workflows) — solo si son específicos del agente
|
|
300
|
+
// No eliminar directorios genéricos como .github, rules/, skills/ que pueden tener otros usos
|
|
301
|
+
const agentSpecificDirs = [ide.skillsDir, ide.workflowsDir];
|
|
302
|
+
if (ide.rulesDir && !['rules', '.github/instructions'].includes(ide.rulesDir)) {
|
|
303
|
+
agentSpecificDirs.push(ide.rulesDir);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Determinar el directorio raíz del agente (ej: .cursor, .windsurf, .claude)
|
|
307
|
+
const agentRootDir = ide.markerFile && !ide.markerFile.includes('.') ? null
|
|
308
|
+
: ide.rulesDir ? ide.rulesDir.split('/')[0] : null;
|
|
309
|
+
if (agentRootDir && agentRootDir.startsWith('.') && fs.existsSync(path.join(projectRoot, agentRootDir))) {
|
|
310
|
+
// Eliminar el directorio raíz completo del agente
|
|
311
|
+
toRemove.push({ path: path.join(projectRoot, agentRootDir), type: 'dir', label: agentRootDir + '/' });
|
|
312
|
+
} else {
|
|
313
|
+
// Eliminar subdirectorios individualmente
|
|
314
|
+
for (const dir of agentSpecificDirs) {
|
|
315
|
+
if (dir && fs.existsSync(path.join(projectRoot, dir))) {
|
|
316
|
+
toRemove.push({ path: path.join(projectRoot, dir), type: 'dir', label: dir + '/' });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Archivos de configuración específicos del agente (markerFile si es un archivo)
|
|
322
|
+
if (ide.markerFile && ide.markerFile.includes('.') && fs.existsSync(path.join(projectRoot, ide.markerFile))) {
|
|
323
|
+
const markerStat = fs.statSync(path.join(projectRoot, ide.markerFile));
|
|
324
|
+
if (markerStat.isFile()) {
|
|
325
|
+
toRemove.push({ path: path.join(projectRoot, ide.markerFile), type: 'file', label: ide.markerFile });
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
for (const item of toRemove) {
|
|
330
|
+
try {
|
|
331
|
+
if (item.type === 'dir') {
|
|
332
|
+
fs.rmSync(item.path, { recursive: true, force: true });
|
|
333
|
+
} else {
|
|
334
|
+
fs.unlinkSync(item.path);
|
|
335
|
+
}
|
|
336
|
+
console.log(` ${chalk.red('✘')} ${ide.name}: ${chalk.gray(item.label)} eliminado`);
|
|
337
|
+
removed++;
|
|
338
|
+
} catch (e) {
|
|
339
|
+
console.error(` ${chalk.red('❌')} Error eliminando ${item.label}: ${e.message}`);
|
|
340
|
+
errors++;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Eliminar entry points raíz si --all
|
|
346
|
+
if (options.all) {
|
|
347
|
+
for (const f of existingRootFiles) {
|
|
348
|
+
try {
|
|
349
|
+
fs.unlinkSync(path.join(projectRoot, f));
|
|
350
|
+
console.log(` ${chalk.red('✘')} ${chalk.gray(f)} eliminado`);
|
|
351
|
+
removed++;
|
|
352
|
+
} catch (e) {
|
|
353
|
+
console.error(` ${chalk.red('❌')} Error eliminando ${f}: ${e.message}`);
|
|
354
|
+
errors++;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
console.log('');
|
|
360
|
+
if (errors === 0) {
|
|
361
|
+
console.log(gradient.pastel(`\n✨ Limpieza completada. ${removed} elemento(s) eliminado(s).\n`));
|
|
362
|
+
if (!options.all) {
|
|
363
|
+
console.log(chalk.dim(' 💡 Usa `lmagent uninstall --all` para también eliminar CLAUDE.md, GEMINI.md y AGENTS.md.'));
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
console.log(chalk.yellow(`\n⚠️ ${removed} eliminado(s), ${errors} error(es).\n`));
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
405
370
|
if (process.argv.length === 2) {
|
|
406
371
|
runInstall({});
|
|
407
372
|
} else {
|
|
408
373
|
program.parse();
|
|
409
374
|
}
|
|
410
375
|
|
|
376
|
+
|
|
411
377
|
// Helper for Windows-proof path comparison
|
|
412
378
|
function arePathsEqual(p1, p2) {
|
|
413
379
|
if (!p1 || !p2) return false;
|
|
414
380
|
return path.resolve(p1).toLowerCase() === path.resolve(p2).toLowerCase();
|
|
415
381
|
}
|
|
416
382
|
|
|
417
|
-
// Helper to deploy AGENTS.md
|
|
383
|
+
// Helper to deploy AGENTS.md, CLAUDE.md y GEMINI.md to project root
|
|
384
|
+
// Los archivos con versionTemplate:true tienen {{VERSION}} que se reemplaza dinámicamente
|
|
418
385
|
async function deployCorePillars(options, projectRoot) {
|
|
419
386
|
console.log(chalk.bold('\n🚀 Desplegando Pilares de Inteligencia (Contexto Root):'));
|
|
420
387
|
for (const file of INIT_FILES) {
|
|
@@ -427,18 +394,22 @@ async function deployCorePillars(options, projectRoot) {
|
|
|
427
394
|
shouldCopy = true;
|
|
428
395
|
console.log(` ${chalk.green('✔')} ${file.src} (Creado en la raíz)`);
|
|
429
396
|
} else {
|
|
430
|
-
|
|
397
|
+
// Si ya existe pero tiene versión vieja, actualizar automáticamente
|
|
398
|
+
const existingContent = fs.readFileSync(destPath, 'utf8');
|
|
399
|
+
const hasOldVersion = existingContent.includes('{{VERSION}}') ||
|
|
400
|
+
(file.versionTemplate && !existingContent.includes(`v${PKG_VERSION}`));
|
|
401
|
+
|
|
402
|
+
if (options.force || hasOldVersion) {
|
|
431
403
|
shouldCopy = true;
|
|
432
|
-
|
|
404
|
+
const reason = hasOldVersion ? 'Actualizando versión' : 'Sobrescribiendo por --force';
|
|
405
|
+
console.log(` ${chalk.yellow('✎')} ${file.src} (${reason})`);
|
|
433
406
|
} else if (options.yes) {
|
|
434
|
-
|
|
435
|
-
// PERO informamos.
|
|
436
|
-
console.log(` ${chalk.blue('ℹ')} ${file.src} ya existe (Manteniendo versión local)`);
|
|
407
|
+
console.log(` ${chalk.blue('ℹ')} ${file.src} ya existe v${PKG_VERSION} (OK)`);
|
|
437
408
|
} else {
|
|
438
409
|
const answer = await inquirer.prompt([{
|
|
439
410
|
type: 'confirm',
|
|
440
411
|
name: 'overwrite',
|
|
441
|
-
message: `⚠️ ${file.src} ya existe
|
|
412
|
+
message: `⚠️ ${file.src} ya existe. ¿Deseas actualizarlo?`,
|
|
442
413
|
default: false
|
|
443
414
|
}]);
|
|
444
415
|
shouldCopy = answer.overwrite;
|
|
@@ -447,7 +418,12 @@ async function deployCorePillars(options, projectRoot) {
|
|
|
447
418
|
}
|
|
448
419
|
|
|
449
420
|
if (shouldCopy) {
|
|
450
|
-
fs.
|
|
421
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
422
|
+
// Inyectar versión dinámica si el archivo usa template
|
|
423
|
+
if (file.versionTemplate) {
|
|
424
|
+
content = content.replace(/\{\{VERSION\}\}/g, PKG_VERSION);
|
|
425
|
+
}
|
|
426
|
+
fs.writeFileSync(destPath, content, 'utf8');
|
|
451
427
|
}
|
|
452
428
|
}
|
|
453
429
|
}
|
|
@@ -464,20 +440,21 @@ async function runInstall(options) {
|
|
|
464
440
|
const globalAgentDir = path.join(userHome, '.agents');
|
|
465
441
|
const globalSkillsDir = path.join(globalAgentDir, 'skills');
|
|
466
442
|
const globalRulesDir = path.join(globalAgentDir, 'rules');
|
|
467
|
-
const globalWorkflowsDir = path.join(globalAgentDir, 'workflows');
|
|
468
|
-
|
|
469
|
-
//
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
443
|
+
const globalWorkflowsDir = path.join(globalAgentDir, 'workflows');
|
|
444
|
+
|
|
445
|
+
// Sync global SOLO si se pasa --global explícitamente (evita doble lectura de contexto)
|
|
446
|
+
if (options.global) {
|
|
447
|
+
console.log(chalk.blue('🌐 Sincronizando al repositorio global (~/.agents/)...'));
|
|
448
|
+
try {
|
|
449
|
+
if (!fs.existsSync(globalAgentDir)) fs.mkdirSync(globalAgentDir, { recursive: true });
|
|
450
|
+
if (fs.existsSync(PACKAGE_SKILLS_DIR)) copyRecursiveSync(PACKAGE_SKILLS_DIR, globalSkillsDir, true);
|
|
451
|
+
if (fs.existsSync(PACKAGE_RULES_DIR)) copyRecursiveSync(PACKAGE_RULES_DIR, globalRulesDir, true);
|
|
452
|
+
if (fs.existsSync(PACKAGE_WORKFLOWS_DIR)) copyRecursiveSync(PACKAGE_WORKFLOWS_DIR, globalWorkflowsDir, true);
|
|
453
|
+
if (fs.existsSync(PACKAGE_MEMORY_DIR)) copyRecursiveSync(PACKAGE_MEMORY_DIR, path.join(globalAgentDir, 'memory'), true);
|
|
454
|
+
console.log(chalk.green('✔ Repositorio global sincronizado.'));
|
|
455
|
+
} catch (e) {
|
|
456
|
+
console.error(chalk.red(`❌ Error al sincronizar repositorio global: ${e.message}`));
|
|
457
|
+
}
|
|
481
458
|
}
|
|
482
459
|
|
|
483
460
|
await deployCorePillars(options, projectRoot);
|
|
@@ -510,10 +487,6 @@ async function runInstall(options) {
|
|
|
510
487
|
console.log(chalk.cyan('🔹 Configuración de Instalación'));
|
|
511
488
|
console.log(chalk.gray('================================================================'));
|
|
512
489
|
|
|
513
|
-
console.log(chalk.gray('================================================================'));
|
|
514
|
-
console.log(chalk.cyan('🔹 Configuración de Instalación'));
|
|
515
|
-
console.log(chalk.gray('================================================================'));
|
|
516
|
-
|
|
517
490
|
// UX OPTIMIZATION: "Project First" & Windows Compat
|
|
518
491
|
// 1. Detect Environment
|
|
519
492
|
const isWindows = os.platform() === 'win32';
|
|
@@ -527,21 +500,65 @@ async function runInstall(options) {
|
|
|
527
500
|
console.log('');
|
|
528
501
|
|
|
529
502
|
// 3. Auto-Detect IDEs
|
|
503
|
+
// Mapa de rutas de instalación global por agente (donde el IDE instala sus archivos en ~/)
|
|
504
|
+
// HOME_PATHS: rutas de instalación global de cada agente en el sistema del usuario
|
|
505
|
+
// Cubre los 37 agentes soportados. Se verifica si alguna de las rutas existe en ~/
|
|
506
|
+
const HOME_PATHS = {
|
|
507
|
+
// IDEs principales
|
|
508
|
+
'cursor': ['.cursor'],
|
|
509
|
+
'windsurf': ['.windsurf'],
|
|
510
|
+
'cline': ['.vscode/extensions', '.cline'],
|
|
511
|
+
'roo': ['.vscode/extensions', '.roo'],
|
|
512
|
+
'vscode': ['.vscode'],
|
|
513
|
+
'trae': ['.trae'],
|
|
514
|
+
'trae-cn': ['.trae-cn', '.trae'],
|
|
515
|
+
'claude': ['.claude'],
|
|
516
|
+
'zed': ['.config/zed', '.zed'],
|
|
517
|
+
// Agentes CLI & autónomos
|
|
518
|
+
'antigravity': ['.gemini/antigravity'],
|
|
519
|
+
'gemini': ['.gemini'],
|
|
520
|
+
'augment': ['.augment'],
|
|
521
|
+
'continue': ['.continue'],
|
|
522
|
+
'codex': ['.codex'],
|
|
523
|
+
'goose': ['.config/goose', '.goose'],
|
|
524
|
+
'junie': ['.junie'],
|
|
525
|
+
'kilo': ['.kilocode'],
|
|
526
|
+
'kiro': ['.kiro'],
|
|
527
|
+
'opencode': ['.opencode'],
|
|
528
|
+
'openhands': ['.openhands'],
|
|
529
|
+
'amp': ['.agents'],
|
|
530
|
+
'zencoder': ['.zencoder'],
|
|
531
|
+
'codebuddy': ['.codebuddy'],
|
|
532
|
+
'crush': ['.crush'],
|
|
533
|
+
'droid': ['.factory'],
|
|
534
|
+
'mux': ['.mux'],
|
|
535
|
+
'qwen': ['.qwen'],
|
|
536
|
+
// Agentes menores / nicho
|
|
537
|
+
'openclaw': ['.config/openclaw', '.openclaw'],
|
|
538
|
+
'command-code': ['.commandcode'],
|
|
539
|
+
'iflow': ['.iflow'],
|
|
540
|
+
'kode': ['.kode'],
|
|
541
|
+
'mcpjam': ['.mcpjam'],
|
|
542
|
+
'mistral': ['.vibe', '.mistral'],
|
|
543
|
+
'pi': ['.pi'],
|
|
544
|
+
'qoder': ['.qoder'],
|
|
545
|
+
'neovate': ['.neovate'],
|
|
546
|
+
'pochi': ['.pochi'],
|
|
547
|
+
'adal': ['.adal'],
|
|
548
|
+
};
|
|
549
|
+
|
|
530
550
|
const detectedIdes = IDE_CONFIGS.filter(ide => {
|
|
531
|
-
if (ide.value === 'custom') return false;
|
|
551
|
+
if (ide.value === 'custom' || ide.value === 'generic') return false;
|
|
532
552
|
|
|
533
|
-
// Check Project Root
|
|
534
|
-
const
|
|
535
|
-
|
|
553
|
+
// Check Project Root: usar markerFile primero (más preciso), luego rulesDir como fallback
|
|
554
|
+
const markerInProject = ide.markerFile && fs.existsSync(path.join(projectRoot, ide.markerFile));
|
|
555
|
+
const rulesDirInProject = ide.rulesDir && fs.existsSync(path.join(projectRoot, ide.rulesDir));
|
|
556
|
+
const skillsDirInProject = ide.skillsDir && fs.existsSync(path.join(projectRoot, ide.skillsDir));
|
|
557
|
+
const inProject = markerInProject || rulesDirInProject || skillsDirInProject;
|
|
536
558
|
|
|
537
|
-
// Check User Home
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
(ide.value === 'cursor' && fs.existsSync(path.join(userHome, '.cursor'))) ||
|
|
541
|
-
(ide.value === 'windsurf' && fs.existsSync(path.join(userHome, '.windsurf'))) ||
|
|
542
|
-
(ide.value === 'trae' && fs.existsSync(path.join(userHome, '.trae'))) ||
|
|
543
|
-
(ide.value === 'cline' && fs.existsSync(path.join(userHome, '.cline'))) ||
|
|
544
|
-
(ide.value === 'roo' && fs.existsSync(path.join(userHome, '.roo')));
|
|
559
|
+
// Check User Home: usar mapa explícito de rutas de instalación global
|
|
560
|
+
const homePaths = HOME_PATHS[ide.value] || [];
|
|
561
|
+
const inHome = homePaths.some(p => fs.existsSync(path.join(userHome, p)));
|
|
545
562
|
|
|
546
563
|
return inProject || inHome;
|
|
547
564
|
});
|
|
@@ -670,6 +687,16 @@ async function runInstall(options) {
|
|
|
670
687
|
options.installMemory = memoryAnswer.memory;
|
|
671
688
|
}
|
|
672
689
|
|
|
690
|
+
// Opción global: sincronizar también a ~/.agents/
|
|
691
|
+
console.log('');
|
|
692
|
+
const globalAnswer = await inquirer.prompt([{
|
|
693
|
+
type: 'confirm',
|
|
694
|
+
name: 'global',
|
|
695
|
+
message: '🌐 ¿También sincronizar al repositorio global (~/.agents/)? (Útil para Gemini CLI, Codex y agentes CLI)',
|
|
696
|
+
default: false
|
|
697
|
+
}]);
|
|
698
|
+
if (globalAnswer.global) options.global = true;
|
|
699
|
+
|
|
673
700
|
console.log('');
|
|
674
701
|
const { confirm } = await inquirer.prompt([{
|
|
675
702
|
type: 'confirm',
|
|
@@ -729,11 +756,28 @@ async function runInstall(options) {
|
|
|
729
756
|
const relativeCatalogPath = getRelLink(ide.configFile, 'AGENTS.md');
|
|
730
757
|
const relativeContextPath = getRelLink(ide.configFile, 'CLAUDE.md');
|
|
731
758
|
|
|
732
|
-
//
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
759
|
+
// Usar template específico del agente si existe, si no usar contenido genérico
|
|
760
|
+
const AGENT_CONFIGS_TEMPLATE_DIR = path.join(__dirname, '.agents', 'templates', 'agent-configs');
|
|
761
|
+
const templateFile = ide.configTemplate
|
|
762
|
+
? path.join(AGENT_CONFIGS_TEMPLATE_DIR, ide.configTemplate)
|
|
763
|
+
: path.join(AGENT_CONFIGS_TEMPLATE_DIR, '_generic.md');
|
|
764
|
+
|
|
765
|
+
let content;
|
|
766
|
+
if (fs.existsSync(templateFile) && !ide.configFile.endsWith('.json')) {
|
|
767
|
+
// Usar template del archivo, inyectando VERSION
|
|
768
|
+
content = fs.readFileSync(templateFile, 'utf8')
|
|
769
|
+
.replace(/\{\{VERSION\}\}/g, PKG_VERSION)
|
|
770
|
+
.replace(/\{\{MAJOR\}\}/g, PKG_VERSION.split('.')[0]);
|
|
771
|
+
} else if (ide.configFile.endsWith('.json') && fs.existsSync(templateFile)) {
|
|
772
|
+
// JSON: usar template y reemplazar VERSION
|
|
773
|
+
content = fs.readFileSync(templateFile, 'utf8')
|
|
774
|
+
.replace(/\{\{VERSION\}\}/g, PKG_VERSION)
|
|
775
|
+
.replace(/\{\{MAJOR\}\}/g, PKG_VERSION.split('.')[0]);
|
|
776
|
+
} else {
|
|
777
|
+
// Fallback: contenido genérico dinámico
|
|
778
|
+
content = `
|
|
779
|
+
# 🤖 LMAgent Framework v${PKG_VERSION}
|
|
780
|
+
> Contexto Activo: Este proyecto utiliza el estándar LMAgent V${PKG_VERSION.split('.')[0]}.
|
|
737
781
|
|
|
738
782
|
## 🚨 SOURCE OF TRUTH (CEREBRO)
|
|
739
783
|
**TU CONTEXTO Y REGLAS VIVEN AQUÍ 👉 [AGENTS.md](${relativeCatalogPath})**
|
|
@@ -753,7 +797,9 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
|
|
|
753
797
|
|
|
754
798
|
!! SYSTEM NOTE: Read AGENTS.md to understand how to execute these roles. !!
|
|
755
799
|
`;
|
|
756
|
-
|
|
800
|
+
}
|
|
801
|
+
// If file exists, check if we need to append
|
|
802
|
+
try {
|
|
757
803
|
if (fs.existsSync(configPath)) {
|
|
758
804
|
// Check if it's a directory (Edge case: Cline legacy folders)
|
|
759
805
|
if (fs.statSync(configPath).isDirectory()) {
|
|
@@ -785,9 +831,16 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
|
|
|
785
831
|
console.log(` ${bootstrapStatus === 'CREATED' ? chalk.green('✔') : chalk.blue('ℹ')} ${ide.name} Bootstrap: ${bootstrapStatus}`);
|
|
786
832
|
}
|
|
787
833
|
|
|
788
|
-
// 4.1 Generate Bridge Rule
|
|
789
|
-
|
|
790
|
-
|
|
834
|
+
// 4.1 Generate Bridge Rule
|
|
835
|
+
// Si el agente NO tiene configFile, necesita un archivo puente en rulesDir para auto-invocarse.
|
|
836
|
+
// Si tampoco tiene bridgeFile definido, usamos '00-lmagent.md' como default genérico.
|
|
837
|
+
const bridgeFile = ide.bridgeFile || (ide.rulesDir && !ide.configFile ? '00-lmagent.md' : null);
|
|
838
|
+
const needsBridge = bridgeFile && !ide.configFile;
|
|
839
|
+
// Garantizar que rulesDir existe siempre (para que el agente pueda detectar la instalación)
|
|
840
|
+
if (ide.rulesDir && !fs.existsSync(path.join(targetRoot, ide.rulesDir))) {
|
|
841
|
+
fs.mkdirSync(path.join(targetRoot, ide.rulesDir), { recursive: true });
|
|
842
|
+
}
|
|
843
|
+
if (ide.rulesDir && needsBridge) {
|
|
791
844
|
const bridgePath = path.join(targetRoot, ide.rulesDir, bridgeFile);
|
|
792
845
|
const relativeBridgeToRoot = path.join(ide.rulesDir, bridgeFile);
|
|
793
846
|
const relContext = getRelLink(relativeBridgeToRoot, 'CLAUDE.md');
|
|
@@ -805,7 +858,7 @@ globs: **/*
|
|
|
805
858
|
|
|
806
859
|
# 🤖 LMAgent Bridge Rule
|
|
807
860
|
|
|
808
|
-
Este proyecto está potenciado por **LMAgent
|
|
861
|
+
Este proyecto está potenciado por **LMAgent v${PKG_VERSION}**.
|
|
809
862
|
|
|
810
863
|
## 🚨 SOURCE OF TRUTH (CEREBRO)
|
|
811
864
|
**TU CONTEXTO Y REGLAS VIVEN AQUÍ 👉 [AGENTS.md](${relCatalog})**
|
|
@@ -829,7 +882,7 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
|
|
|
829
882
|
// Standard Markdown (Universal & Cline/Windsurf)
|
|
830
883
|
bridgeContent = `# 🤖 LMAgent Framework Entry Point
|
|
831
884
|
|
|
832
|
-
Este proyecto utiliza **LMAgent
|
|
885
|
+
Este proyecto utiliza **LMAgent v${PKG_VERSION}**.
|
|
833
886
|
|
|
834
887
|
## 🚨 SOURCE OF TRUTH (CEREBRO)
|
|
835
888
|
**TU CONTEXTO Y REGLAS VIVEN AQUÍ 👉 [AGENTS.md](${relCatalog})**
|
|
@@ -958,15 +1011,18 @@ Use estos comandos para activar su rol. Para detalles, consulte \`AGENTS.md\`.
|
|
|
958
1011
|
console.log(chalk.gray('================================================================'));
|
|
959
1012
|
console.log(chalk.bold.green('🎉 ¡Todo listo! Aquí tienes cómo usar tus nuevos superpoderes:'));
|
|
960
1013
|
console.log('');
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
console.log(chalk.
|
|
1014
|
+
|
|
1015
|
+
// Mensaje dinámico según agentes instalados
|
|
1016
|
+
const ideNames = targetIdes.map(i => i.name).join(', ');
|
|
1017
|
+
console.log(chalk.cyan(`🤖 Agentes configurados: ${chalk.bold(ideNames)}`));
|
|
1018
|
+
console.log('');
|
|
1019
|
+
console.log(chalk.white(' 1. Abre tu agente en este proyecto — leerá el contexto automáticamente.'));
|
|
1020
|
+
console.log(chalk.white(' 2. Usa los triggers para activar un rol específico:'));
|
|
1021
|
+
console.log(chalk.gray(' /dev → Backend | /front → Frontend | /arch → Arquitecto'));
|
|
1022
|
+
console.log(chalk.gray(' /fix → Debugger | /pm → Product | /orch → Orchestrator'));
|
|
965
1023
|
console.log('');
|
|
966
|
-
console.log(chalk.
|
|
967
|
-
console.log(chalk.
|
|
968
|
-
console.log(chalk.white(' 2. Escribe tu petición en lenguaje natural.'));
|
|
969
|
-
console.log(chalk.gray(' Ej: "Analiza la base de datos" (El agente buscará y usará backend-engineer/data-engineer)'));
|
|
1024
|
+
console.log(chalk.dim(' 💡 Ejecuta `lmagent doctor` para verificar la instalación.'));
|
|
1025
|
+
console.log(chalk.dim(' 💡 Ejecuta `lmagent tokens` para ver el consumo de tokens del framework.'));
|
|
970
1026
|
console.log(chalk.gray('================================================================'));
|
|
971
1027
|
}
|
|
972
1028
|
|
|
@@ -1181,7 +1237,9 @@ async function runInit(options) {
|
|
|
1181
1237
|
|
|
1182
1238
|
if (fs.existsSync(srcPath)) {
|
|
1183
1239
|
if (!fs.existsSync(destPath)) {
|
|
1184
|
-
fs.
|
|
1240
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1241
|
+
if (file.versionTemplate) content = content.replace(/\{\{VERSION\}\}/g, PKG_VERSION);
|
|
1242
|
+
fs.writeFileSync(destPath, content, 'utf8');
|
|
1185
1243
|
console.log(` ${chalk.green('✔')} ${file.src} (Created)`);
|
|
1186
1244
|
} else {
|
|
1187
1245
|
// Exists: Ask to overwrite (unless force/yes)
|
|
@@ -1199,7 +1257,9 @@ async function runInit(options) {
|
|
|
1199
1257
|
}
|
|
1200
1258
|
|
|
1201
1259
|
if (shouldOverwrite) {
|
|
1202
|
-
fs.
|
|
1260
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1261
|
+
if (file.versionTemplate) content = content.replace(/\{\{VERSION\}\}/g, PKG_VERSION);
|
|
1262
|
+
fs.writeFileSync(destPath, content, 'utf8');
|
|
1203
1263
|
console.log(` ${chalk.yellow('✎')} ${file.src} (Overwritten)`);
|
|
1204
1264
|
} else {
|
|
1205
1265
|
console.log(` ${chalk.gray('SKIP')} ${file.src} (Kept existing)`);
|
|
@@ -1266,7 +1326,7 @@ DEBUG=true
|
|
|
1266
1326
|
}
|
|
1267
1327
|
|
|
1268
1328
|
// Resumen
|
|
1269
|
-
console.log(gradient.pastel.multiline(
|
|
1329
|
+
console.log(gradient.pastel.multiline(`\n✨ Proyecto inicializado con LMAgent v${PKG_VERSION} ✨`));
|
|
1270
1330
|
console.log('');
|
|
1271
1331
|
console.log(chalk.cyan('Próximos pasos:'));
|
|
1272
1332
|
console.log(` 1. ${chalk.bold('lmagent install')} - Instalar skills/rules/workflows en tu IDE`);
|