sdd-toolkit 1.1.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js CHANGED
@@ -1,207 +1,284 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require('fs');
4
- const fsp = require('fs/promises');
5
- const path = require('path');
6
- const { intro, outro, multiselect, spinner, note, select, text } = require('@clack/prompts');
7
- const pc = require('picocolors');
8
-
9
- // Módulos Internos
10
- const { loadAgents } = require('./lib/agents');
11
- const { STACK_PROFILES } = require('./lib/profiles');
12
- const {
13
- toGeminiTOML,
14
- toRooConfig,
15
- toKiloMarkdown,
16
- toCopilotInstructions,
17
- toCursorMDC,
18
- toWindsurfRules,
19
- toPlainSystemPrompt,
20
- toTraeRules
21
- } = require('./lib/transformers');
22
- const { generateWorkflowGuide } = require('./lib/docs');
23
-
24
- async function main() {
25
- console.clear();
26
- intro(pc.bgMagenta(pc.white(' UNIVERSAL SPEC CLI ')));
27
-
28
- // 1. Scaffold Automático (Sempre executa)
29
- const created = generateWorkflowGuide(process.cwd());
30
- if (created) {
31
- console.log(pc.green('✔ Estrutura de pastas (docs/) verificada.'));
32
- }
33
-
34
- // 2. Feature 5: Seleção de Stack (Profile)
35
- const stackOptions = Object.entries(STACK_PROFILES).map(([key, profile]) => ({
36
- value: key,
37
- label: profile.label
38
- }));
39
-
40
- const stackProfile = await select({
41
- message: 'Qual é o perfil da sua Stack tecnológica?',
42
- options: stackOptions,
43
- initialValue: 'generic'
44
- });
45
-
46
- if (typeof stackProfile === 'symbol') { process.exit(0); } // Handle Cancel
47
-
48
- // 3. Feature 3: Regras Globais (Opcional)
49
- const globalRules = await text({
50
- message: 'Deseja adicionar alguma Regra Global para TODOS os agentes?',
51
- placeholder: 'Ex: Responda sempre em pt-BR; Use Conventional Commits...',
52
- required: false
53
- });
54
-
55
- if (typeof globalRules === 'symbol') { process.exit(0); } // Handle Cancel
56
-
57
- // 4. Seleção de Ferramentas (Múltipla escolha)
58
- const tools = await multiselect({
59
- message: 'Para quais ferramentas você deseja instalar os Agentes?',
60
- options: [
61
- { value: 'gemini', label: 'Gemini CLI', hint: '.gemini/commands/dev' },
62
- { value: 'roo', label: 'Roo Code', hint: '.roo/ & custom_modes.json' },
63
- { value: 'cline', label: 'Cline', hint: '.cline/ & custom_modes.json' },
64
- { value: 'cursor', label: 'Cursor', hint: '.cursor/rules/*.mdc' },
65
- { value: 'windsurf', label: 'Windsurf', hint: '.windsurfrules' },
66
- { value: 'trae', label: 'Trae IDE', hint: '.trae/instructions.md' },
67
- { value: 'kilo', label: 'Kilo Code', hint: '.kilo/prompts/*.md' },
68
- { value: 'copilot', label: 'GitHub Copilot', hint: '.github/copilot-instructions.md' },
69
- { value: 'web', label: 'OpenAI / Claude', hint: 'prompts/*.txt' },
70
- { value: 'opencode', label: 'OpenCode', hint: '.opencode/*.md' },
71
- ],
72
- required: true,
73
- hint: 'Espaço para selecionar, Enter para confirmar'
74
- });
75
-
76
- if (!tools || tools.length === 0) {
77
- outro('Nenhuma ferramenta selecionada. Operação cancelada.');
78
- process.exit(0);
79
- }
80
-
81
- await processAgentsInstallation(tools, { stackProfile, globalRules });
82
-
83
- outro(pc.green('Configuração concluída com sucesso! 🚀'));
84
- }
85
-
86
- async function processAgentsInstallation(tools, options) {
87
- const s = spinner();
88
- s.start('Carregando definições...');
89
-
90
- try {
91
- const validAgents = await loadAgents(options);
92
-
93
- if (validAgents.length === 0) {
94
- s.stop('Nenhum agente válido encontrado.');
95
- return;
96
- }
97
-
98
- s.message(`Instalando agentes para: ${tools.join(', ')}...`);
99
-
100
- // Itera sobre cada ferramenta selecionada
101
- for (const tool of tools) {
102
-
103
- // Instalação Específica por Ferramenta
104
- if (tool === 'gemini') {
105
- const targetDir = path.join(process.cwd(), '.gemini', 'commands', 'dev');
106
- await fsp.mkdir(targetDir, { recursive: true });
107
-
108
- await Promise.all(validAgents.map(agent => {
109
- const toml = toGeminiTOML(agent);
110
- const fileName = `${agent.originalName}.toml`;
111
- return fsp.writeFile(path.join(targetDir, fileName), toml);
112
- }));
113
- }
114
- else if (tool === 'roo' || tool === 'cline') {
115
- const configDir = tool === 'roo' ? '.roo' : '.cline';
116
- const targetDir = path.join(process.cwd(), configDir);
117
- await fsp.mkdir(targetDir, { recursive: true });
118
-
119
- await Promise.all(validAgents.map(agent => {
120
- const md = toKiloMarkdown(agent);
121
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
122
- }));
123
-
124
- const modes = validAgents.map(agent => toRooConfig(agent, agent.slug));
125
- const jsonContent = JSON.stringify({ customModes: modes }, null, 2);
126
- const fileName = `${tool}_custom_modes.json`;
127
- await fsp.writeFile(path.join(process.cwd(), fileName), jsonContent);
128
- }
129
- else if (tool === 'kilo') {
130
- const targetDir = path.join(process.cwd(), '.kilo', 'prompts');
131
- await fsp.mkdir(targetDir, { recursive: true });
132
-
133
- await Promise.all(validAgents.map(agent => {
134
- const md = toKiloMarkdown(agent);
135
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
136
- }));
137
- }
138
- else if (tool === 'copilot') {
139
- const githubDir = path.join(process.cwd(), '.github');
140
- const agentsDir = path.join(githubDir, 'agents');
141
- await fsp.mkdir(agentsDir, { recursive: true });
142
-
143
- await Promise.all(validAgents.map(agent => {
144
- const md = toCopilotInstructions(agent);
145
- return fsp.writeFile(path.join(agentsDir, `${agent.slug}.md`), md);
146
- }));
147
-
148
- const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
149
- const mainInstructions = toCopilotInstructions(mainAgent);
150
- await fsp.writeFile(path.join(githubDir, 'copilot-instructions.md'), mainInstructions);
151
- }
152
- else if (tool === 'cursor') {
153
- const rulesDir = path.join(process.cwd(), '.cursor', 'rules');
154
- await fsp.mkdir(rulesDir, { recursive: true });
155
-
156
- await Promise.all(validAgents.map(agent => {
157
- const mdc = toCursorMDC(agent);
158
- return fsp.writeFile(path.join(rulesDir, `${agent.slug}.mdc`), mdc);
159
- }));
160
- }
161
- else if (tool === 'windsurf') {
162
- const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
163
- const rules = toWindsurfRules(mainAgent);
164
- await fsp.writeFile(path.join(process.cwd(), '.windsurfrules'), rules);
165
- }
166
- else if (tool === 'trae') {
167
- const traeDir = path.join(process.cwd(), '.trae');
168
- await fsp.mkdir(traeDir, { recursive: true });
169
-
170
- const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
171
- const rules = toTraeRules(mainAgent);
172
- await fsp.writeFile(path.join(traeDir, 'instructions.md'), rules);
173
- }
174
- else if (tool === 'web') {
175
- const targetDir = path.join(process.cwd(), 'prompts');
176
- await fsp.mkdir(targetDir, { recursive: true });
177
-
178
- await Promise.all(validAgents.map(agent => {
179
- const txt = toPlainSystemPrompt(agent);
180
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.txt`), txt);
181
- }));
182
- }
183
- else if (tool === 'opencode') {
184
- const targetDir = path.join(process.cwd(), '.opencode');
185
- await fsp.mkdir(targetDir, { recursive: true });
186
-
187
- await Promise.all(validAgents.map(agent => {
188
- const md = toKiloMarkdown(agent);
189
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
190
- }));
191
- }
192
- }
193
-
194
- s.stop('Instalação finalizada!');
195
-
196
- // Feedback consolidado
197
- if (tools.includes('roo') || tools.includes('cline')) {
198
- note('Lembre-se de configurar os Custom Modes no settings.json para Roo/Cline.', 'Aviso');
199
- }
200
-
201
- } catch (e) {
202
- s.stop('Falha');
203
- console.error(pc.red(e.message));
204
- }
205
- }
206
-
207
- main().catch(console.error);
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const fsp = require('fs/promises');
5
+ const path = require('path');
6
+ const { intro, outro, multiselect, spinner, note, select, text } = require('@clack/prompts');
7
+ const pc = require('picocolors');
8
+
9
+ // Internal Modules
10
+ const { loadAgents } = require('./lib/agents');
11
+ const { STACK_PROFILES } = require('./lib/profiles');
12
+ const { setLocale, t, getLocale } = require('./lib/i18n');
13
+ const {
14
+ toGeminiTOML,
15
+ toRooConfig,
16
+ toKiloMarkdown,
17
+ toCopilotInstructions,
18
+ toCursorMDC,
19
+ toWindsurfRules,
20
+ toPlainSystemPrompt,
21
+ toTraeRules
22
+ } = require('./lib/transformers');
23
+ const { generateWorkflowGuide } = require('./lib/docs');
24
+
25
+ async function main() {
26
+ console.clear();
27
+
28
+ const args = process.argv.slice(2);
29
+ const isUpgrade = args.includes('upgrade') || args.includes('--upgrade');
30
+
31
+ // 0. Language Selection (Always first unless forced upgrade silent mode - but upgrade has interaction)
32
+ // We show this before Upgrade title to ensure upgrade messages are localized too if possible
33
+ // But typically flags like --lang would be better. For now, interactive.
34
+
35
+ if (!isUpgrade) {
36
+ intro(pc.bgMagenta(pc.white(' UNIVERSAL SPEC CLI ')));
37
+
38
+ const lang = await select({
39
+ message: 'Select Language / Selecione o Idioma / Seleccione el Idioma',
40
+ options: [
41
+ { value: 'en', label: 'English' },
42
+ { value: 'pt_br', label: 'Português (Brasil)' },
43
+ { value: 'es', label: 'Español' }
44
+ ]
45
+ });
46
+
47
+ if (typeof lang === 'symbol') {
48
+ outro(pc.yellow('Operation cancelled.'));
49
+ process.exit(0);
50
+ }
51
+
52
+ setLocale(lang);
53
+ } else {
54
+ // Default EN for upgrade for now
55
+ setLocale('en');
56
+ }
57
+
58
+ if (isUpgrade) {
59
+ intro(pc.bgBlue(pc.white(t('INTRO.UPGRADE_TITLE'))));
60
+
61
+ // Detecção de Ferramentas Existentes
62
+ const tools = [];
63
+ if (fs.existsSync(path.join(process.cwd(), '.gemini'))) tools.push('gemini');
64
+ if (fs.existsSync(path.join(process.cwd(), '.roo'))) tools.push('roo');
65
+ if (fs.existsSync(path.join(process.cwd(), '.cline'))) tools.push('cline');
66
+ if (fs.existsSync(path.join(process.cwd(), '.cursor'))) tools.push('cursor');
67
+ if (fs.existsSync(path.join(process.cwd(), '.windsurfrules'))) tools.push('windsurf');
68
+ if (fs.existsSync(path.join(process.cwd(), '.trae'))) tools.push('trae');
69
+ if (fs.existsSync(path.join(process.cwd(), '.kilo'))) tools.push('kilo');
70
+ if (fs.existsSync(path.join(process.cwd(), '.github'))) tools.push('copilot'); // Assume copilot se .github existir
71
+ if (fs.existsSync(path.join(process.cwd(), '.opencode'))) tools.push('opencode');
72
+ if (fs.existsSync(path.join(process.cwd(), 'prompts'))) tools.push('web');
73
+
74
+ if (tools.length === 0) {
75
+ note(t('UPGRADE.NO_CONFIG'), t('UPGRADE.NO_CONFIG_TITLE'));
76
+ } else {
77
+ note(t('UPGRADE.DETECTED_TOOLS', tools.join(', ')), t('UPGRADE.DETECTED_TITLE'));
78
+ await processAgentsInstallation(tools, { locale: getLocale() });
79
+ outro(pc.green(t('UPGRADE.SUCCESS')));
80
+ process.exit(0);
81
+ }
82
+ }
83
+
84
+ // 1. Automatic Scaffold
85
+ const s = spinner();
86
+ s.start(t('SCAFFOLD.LOADING'));
87
+
88
+ try {
89
+ const stats = generateWorkflowGuide(process.cwd());
90
+ if (stats.created > 0) {
91
+ s.stop(`${t('SCAFFOLD.SUCCESS')} (${stats.created} new, ${stats.verified} verified)`);
92
+ } else {
93
+ s.stop(t('SCAFFOLD.ALREADY_EXISTS'));
94
+ }
95
+ } catch (e) {
96
+ s.stop(pc.red(t('SCAFFOLD.ERROR')));
97
+ }
98
+
99
+ // 2. Feature 5: Stack Selection (Profile)
100
+ const stackOptions = Object.entries(STACK_PROFILES).map(([key, profile]) => ({
101
+ value: key,
102
+ label: profile.label
103
+ }));
104
+
105
+ const stackProfile = await select({
106
+ message: t('SETUP.STACK_SELECT'),
107
+ options: stackOptions,
108
+ initialValue: 'generic'
109
+ });
110
+
111
+ if (typeof stackProfile === 'symbol') {
112
+ outro(pc.yellow(t('GENERAL.CANCELLED')));
113
+ process.exit(0);
114
+ }
115
+
116
+ // 3. Feature 3: Global Rules (Optional)
117
+ const globalRules = await text({
118
+ message: t('SETUP.GLOBAL_RULES'),
119
+ placeholder: t('SETUP.GLOBAL_RULES_HINT'),
120
+ required: false
121
+ });
122
+
123
+ if (typeof globalRules === 'symbol') {
124
+ outro(pc.yellow(t('GENERAL.CANCELLED')));
125
+ process.exit(0);
126
+ }
127
+
128
+ // 4. Tool Selection (Multiple choice)
129
+ const tools = await multiselect({
130
+ message: t('SETUP.TOOL_SELECT'),
131
+ options: [
132
+ { value: 'gemini', label: t('TOOLS.GEMINI'), hint: '.gemini/commands/dev' },
133
+ { value: 'roo', label: t('TOOLS.ROO'), hint: '.roo/ & custom_modes.json' },
134
+ { value: 'cline', label: t('TOOLS.CLINE'), hint: '.cline/ & custom_modes.json' },
135
+ { value: 'cursor', label: t('TOOLS.CURSOR'), hint: '.cursor/rules/*.mdc' },
136
+ { value: 'windsurf', label: t('TOOLS.WINDSURF'), hint: '.windsurfrules' },
137
+ { value: 'trae', label: t('TOOLS.TRAE'), hint: '.trae/instructions.md' },
138
+ { value: 'kilo', label: t('TOOLS.KILO'), hint: '.kilo/prompts/*.md' },
139
+ { value: 'copilot', label: t('TOOLS.COPILOT'), hint: '.github/copilot-instructions.md' },
140
+ { value: 'web', label: t('TOOLS.WEB'), hint: 'prompts/*.txt' },
141
+ { value: 'opencode', label: t('TOOLS.OPENCODE'), hint: '.opencode/*.md' },
142
+ ],
143
+ required: true,
144
+ hint: t('SETUP.TOOL_HINT')
145
+ });
146
+
147
+ if (typeof tools === 'symbol') {
148
+ outro(pc.yellow(t('GENERAL.CANCELLED')));
149
+ process.exit(0);
150
+ }
151
+
152
+ if (!tools || tools.length === 0) {
153
+ outro(t('SETUP.NO_TOOLS'));
154
+ process.exit(0);
155
+ }
156
+
157
+ // Pass locale to installation process
158
+ await processAgentsInstallation(tools, { stackProfile, globalRules, locale: getLocale() });
159
+
160
+ outro(pc.green(t('SETUP.SUCCESS')));
161
+ }
162
+
163
+ async function processAgentsInstallation(tools, options) {
164
+ const s = spinner();
165
+ s.start(t('INSTALL.LOADING'));
166
+
167
+ try {
168
+ const validAgents = await loadAgents(options);
169
+
170
+ if (validAgents.length === 0) {
171
+ s.stop(t('INSTALL.NO_AGENTS'));
172
+ return;
173
+ }
174
+
175
+ s.message(t('INSTALL.INSTALLING', tools.join(', ')));
176
+
177
+ // Iterate over each selected tool
178
+ for (const tool of tools) {
179
+
180
+ // Tool-Specific Installation
181
+ if (tool === 'gemini') {
182
+ const targetDir = path.join(process.cwd(), '.gemini', 'commands', 'dev');
183
+ await fsp.mkdir(targetDir, { recursive: true });
184
+
185
+ await Promise.all(validAgents.map(agent => {
186
+ const toml = toGeminiTOML(agent, options);
187
+ const fileName = `${agent.originalName}.toml`;
188
+ return fsp.writeFile(path.join(targetDir, fileName), toml);
189
+ }));
190
+ }
191
+ else if (tool === 'roo' || tool === 'cline') {
192
+ const configDir = tool === 'roo' ? '.roo' : '.cline';
193
+ const targetDir = path.join(process.cwd(), configDir);
194
+ await fsp.mkdir(targetDir, { recursive: true });
195
+
196
+ await Promise.all(validAgents.map(agent => {
197
+ const md = toKiloMarkdown(agent, options);
198
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
199
+ }));
200
+
201
+ const modes = validAgents.map(agent => toRooConfig(agent, agent.slug, options));
202
+ const jsonContent = JSON.stringify({ customModes: modes }, null, 2);
203
+ const fileName = `${tool}_custom_modes.json`;
204
+ await fsp.writeFile(path.join(process.cwd(), fileName), jsonContent);
205
+ }
206
+ else if (tool === 'kilo') {
207
+ const targetDir = path.join(process.cwd(), '.kilo', 'prompts');
208
+ await fsp.mkdir(targetDir, { recursive: true });
209
+
210
+ await Promise.all(validAgents.map(agent => {
211
+ const md = toKiloMarkdown(agent, options);
212
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
213
+ }));
214
+ }
215
+ else if (tool === 'copilot') {
216
+ const githubDir = path.join(process.cwd(), '.github');
217
+ const agentsDir = path.join(githubDir, 'agents');
218
+ await fsp.mkdir(agentsDir, { recursive: true });
219
+
220
+ await Promise.all(validAgents.map(agent => {
221
+ const md = toCopilotInstructions(agent, options);
222
+ return fsp.writeFile(path.join(agentsDir, `${agent.slug}.md`), md);
223
+ }));
224
+
225
+ const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
226
+ const mainInstructions = toCopilotInstructions(mainAgent, options);
227
+ await fsp.writeFile(path.join(githubDir, 'copilot-instructions.md'), mainInstructions);
228
+ }
229
+ else if (tool === 'cursor') {
230
+ const rulesDir = path.join(process.cwd(), '.cursor', 'rules');
231
+ await fsp.mkdir(rulesDir, { recursive: true });
232
+
233
+ await Promise.all(validAgents.map(agent => {
234
+ const mdc = toCursorMDC(agent, options);
235
+ return fsp.writeFile(path.join(rulesDir, `${agent.slug}.mdc`), mdc);
236
+ }));
237
+ }
238
+ else if (tool === 'windsurf') {
239
+ const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
240
+ const rules = toWindsurfRules(mainAgent, options);
241
+ await fsp.writeFile(path.join(process.cwd(), '.windsurfrules'), rules);
242
+ }
243
+ else if (tool === 'trae') {
244
+ const traeDir = path.join(process.cwd(), '.trae');
245
+ await fsp.mkdir(traeDir, { recursive: true });
246
+
247
+ const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
248
+ const rules = toTraeRules(mainAgent, options);
249
+ await fsp.writeFile(path.join(traeDir, 'instructions.md'), rules);
250
+ }
251
+ else if (tool === 'web') {
252
+ const targetDir = path.join(process.cwd(), 'prompts');
253
+ await fsp.mkdir(targetDir, { recursive: true });
254
+
255
+ await Promise.all(validAgents.map(agent => {
256
+ const txt = toPlainSystemPrompt(agent, options);
257
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.txt`), txt);
258
+ }));
259
+ }
260
+ else if (tool === 'opencode') {
261
+ const targetDir = path.join(process.cwd(), '.opencode');
262
+ await fsp.mkdir(targetDir, { recursive: true });
263
+
264
+ await Promise.all(validAgents.map(agent => {
265
+ const md = toKiloMarkdown(agent, options);
266
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
267
+ }));
268
+ }
269
+ }
270
+
271
+ s.stop(t('INSTALL.FINISHED'));
272
+
273
+ // Consolidated feedback
274
+ if (tools.includes('roo') || tools.includes('cline')) {
275
+ note(t('INSTALL.ROO_WARNING'), t('INSTALL.ROO_WARNING_TITLE'));
276
+ }
277
+
278
+ } catch (e) {
279
+ s.stop(pc.red(`${t('INSTALL.FAILED')}: ${e.message}`));
280
+ process.exit(1);
281
+ }
282
+ }
283
+
284
+ main().catch(console.error);
package/src/lib/agents.js CHANGED
@@ -6,45 +6,45 @@ const { STACK_PROFILES } = require('./profiles');
6
6
  const pc = require('picocolors');
7
7
 
8
8
  /**
9
- * Carrega e valida todas as definições de agentes da pasta definitions
10
- * Suporta sobrescrita local (.sdd/agents) e injeção de regras
9
+ * Loads and validates all agent definitions from the definitions folder.
10
+ * Supports local override (sdd-toolkit/agents) and rule injection.
11
11
  *
12
12
  * @param {Object} options
13
- * @param {string} options.stackProfile - Chave do perfil de stack (ex: 'frontend-react')
14
- * @param {string} options.globalRules - Regras globais separadas por quebra de linha
15
- * @returns {Promise<Array>} Lista de agentes validados
13
+ * @param {string} options.stackProfile - Stack profile key (e.g., 'frontend-react')
14
+ * @param {string} options.globalRules - Global rules separated by newlines
15
+ * @returns {Promise<Array>} List of validated agents
16
16
  */
17
17
  async function loadAgents(options = {}) {
18
18
  const definitionsDir = path.join(__dirname, '..', '..', 'definitions');
19
- const localDefinitionsDir = path.join(process.cwd(), '.sdd', 'agents');
19
+ const localDefinitionsDir = path.join(process.cwd(), 'sdd-toolkit', 'agents');
20
20
 
21
- // Verifica diretório padrão
21
+ // Check default directory
22
22
  try {
23
23
  await fs.access(definitionsDir);
24
24
  } catch {
25
- throw new Error(`Pasta de definições padrão não encontrada: ${definitionsDir}`);
25
+ throw new Error(`Default definitions folder not found: ${definitionsDir}`);
26
26
  }
27
27
 
28
- // Identifica arquivos padrão
28
+ // Identify default files
29
29
  const files = await fs.readdir(definitionsDir);
30
30
  const yamlFiles = files.filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
31
31
 
32
- // Verifica se existe diretório de sobrescrita local
32
+ // Check if local override directory exists
33
33
  let hasLocalOverrides = false;
34
34
  try {
35
35
  await fs.access(localDefinitionsDir);
36
36
  hasLocalOverrides = true;
37
37
  } catch {
38
- // Ignora se não existir
38
+ // Ignore if it doesn't exist
39
39
  }
40
40
 
41
- // Leitura e processamento em paralelo
41
+ // Parallel reading and processing
42
42
  const results = await Promise.all(yamlFiles.map(async (file) => {
43
43
  try {
44
44
  let content;
45
45
  let source = 'default';
46
46
 
47
- // Feature 2: Sobrescrita Local
47
+ // Feature 2: Local Override
48
48
  if (hasLocalOverrides) {
49
49
  try {
50
50
  const localPath = path.join(localDefinitionsDir, file);
@@ -52,7 +52,7 @@ async function loadAgents(options = {}) {
52
52
  content = await fs.readFile(localPath, 'utf8');
53
53
  source = 'local';
54
54
  } catch {
55
- // Arquivo local não existe, usa padrão
55
+ // Local file doesn't exist, use default
56
56
  }
57
57
  }
58
58
 
@@ -67,19 +67,19 @@ async function loadAgents(options = {}) {
67
67
  return {
68
68
  success: false,
69
69
  file,
70
- error: 'Validação do Schema falhou',
70
+ error: 'Schema validation failed',
71
71
  details: parsed.error.format()
72
72
  };
73
73
  }
74
74
 
75
75
  const agent = parsed.data;
76
76
 
77
- // Normaliza o slug
77
+ // Normalize slug
78
78
  agent.slug = file.replace(/\.ya?ml$/, '').replace(/\./g, '-');
79
79
  agent.originalName = file.replace(/\.ya?ml$/, '');
80
- agent.source = source; // Metadata útil para logs
80
+ agent.source = source; // Useful metadata for logs
81
81
 
82
- // Feature 5: Injeção de Regras de Stack
82
+ // Feature 5: Stack Rules Injection
83
83
  if (options.stackProfile && STACK_PROFILES[options.stackProfile]) {
84
84
  const stackRules = STACK_PROFILES[options.stackProfile].rules;
85
85
  if (stackRules && stackRules.length > 0) {
@@ -87,7 +87,7 @@ async function loadAgents(options = {}) {
87
87
  }
88
88
  }
89
89
 
90
- // Feature 3: Injeção de Regras Globais
90
+ // Feature 3: Global Rules Injection
91
91
  if (options.globalRules && typeof options.globalRules === 'string') {
92
92
  const customRules = options.globalRules
93
93
  .split('\n')
@@ -106,7 +106,7 @@ async function loadAgents(options = {}) {
106
106
  }
107
107
  }));
108
108
 
109
- // Separa sucessos e falhas
109
+ // Separate successes and failures
110
110
  const validAgents = [];
111
111
  const errors = [];
112
112
 
@@ -115,7 +115,7 @@ async function loadAgents(options = {}) {
115
115
  validAgents.push(res.agent);
116
116
  } else {
117
117
  errors.push(res);
118
- console.warn(pc.yellow(`⚠️ Ignorando ${res.file}: ${res.error}`));
118
+ console.warn(pc.yellow(`⚠️ Skipping ${res.file}: ${res.error}`));
119
119
  }
120
120
  });
121
121