sdd-toolkit 1.1.0 → 1.6.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
@@ -6,201 +6,329 @@ const path = require('path');
6
6
  const { intro, outro, multiselect, spinner, note, select, text } = require('@clack/prompts');
7
7
  const pc = require('picocolors');
8
8
 
9
- // Módulos Internos
9
+ // Internal Modules
10
10
  const { loadAgents } = require('./lib/agents');
11
11
  const { STACK_PROFILES } = require('./lib/profiles');
12
- const {
13
- toGeminiTOML,
14
- toRooConfig,
15
- toKiloMarkdown,
12
+ const { setLocale, t, getLocale } = require('./lib/i18n');
13
+ const {
14
+ toGeminiTOML,
15
+ toRooConfig,
16
+ toKiloMarkdown,
16
17
  toCopilotInstructions,
17
18
  toCursorMDC,
18
19
  toWindsurfRules,
20
+ toClaudeCommand,
19
21
  toPlainSystemPrompt,
20
- toTraeRules
22
+ toTraeRules,
23
+ toOpenCodeAgent
21
24
  } = require('./lib/transformers');
22
25
  const { generateWorkflowGuide } = require('./lib/docs');
26
+ const { view } = require('./commands/view');
23
27
 
24
28
  async function main() {
25
29
  console.clear();
26
- intro(pc.bgMagenta(pc.white(' UNIVERSAL SPEC CLI ')));
27
30
 
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.'));
31
+ const args = process.argv.slice(2);
32
+
33
+ if (args[0] === 'view') {
34
+ await view();
35
+ process.exit(0);
36
+ }
37
+
38
+ const isUpgrade = args.includes('upgrade') || args.includes('--upgrade');
39
+
40
+ // 0. Language Selection
41
+ if (!isUpgrade) {
42
+ intro(pc.bgMagenta(pc.white(' UNIVERSAL SPEC CLI ')));
43
+
44
+ const lang = await select({
45
+ message: 'Select Language / Selecione o Idioma / Seleccione el Idioma',
46
+ options: [
47
+ { value: 'en', label: 'English' },
48
+ { value: 'pt_br', label: 'Português (Brasil)' },
49
+ { value: 'es', label: 'Español' }
50
+ ]
51
+ });
52
+
53
+ if (typeof lang === 'symbol') {
54
+ outro(pc.yellow('Operation cancelled.'));
55
+ process.exit(0);
56
+ }
57
+
58
+ setLocale(lang);
59
+ } else {
60
+ setLocale('en');
61
+ }
62
+
63
+ if (isUpgrade) {
64
+ intro(pc.bgBlue(pc.white(t('INTRO.UPGRADE_TITLE'))));
65
+
66
+ const tools = [];
67
+ if (fs.existsSync(path.join(process.cwd(), '.gemini'))) tools.push('gemini');
68
+ if (fs.existsSync(path.join(process.cwd(), '.roo'))) tools.push('roo');
69
+ if (fs.existsSync(path.join(process.cwd(), '.cline'))) tools.push('cline');
70
+ if (fs.existsSync(path.join(process.cwd(), '.cursor'))) tools.push('cursor');
71
+ if (fs.existsSync(path.join(process.cwd(), '.windsurf'))) tools.push('windsurf');
72
+ if (fs.existsSync(path.join(process.cwd(), '.claude'))) tools.push('claude');
73
+ if (fs.existsSync(path.join(process.cwd(), '.trae'))) tools.push('trae');
74
+ if (fs.existsSync(path.join(process.cwd(), '.kilo'))) tools.push('kilo');
75
+ if (fs.existsSync(path.join(process.cwd(), '.github'))) tools.push('copilot');
76
+ if (fs.existsSync(path.join(process.cwd(), '.opencode'))) tools.push('opencode');
77
+ if (fs.existsSync(path.join(process.cwd(), 'prompts'))) tools.push('web');
78
+
79
+ if (tools.length === 0) {
80
+ note(t('UPGRADE.NO_CONFIG'), t('UPGRADE.NO_CONFIG_TITLE'));
81
+ } else {
82
+ note(t('UPGRADE.DETECTED_TOOLS', tools.join(', ')), t('UPGRADE.DETECTED_TITLE'));
83
+ await processAgentsInstallation(tools, { locale: getLocale() });
84
+ outro(pc.green(t('UPGRADE.SUCCESS')));
85
+ process.exit(0);
86
+ }
32
87
  }
33
88
 
34
- // 2. Feature 5: Seleção de Stack (Profile)
89
+ // 1. Automatic Scaffold
90
+ const s = spinner();
91
+ s.start(t('SCAFFOLD.LOADING'));
92
+
93
+ try {
94
+ const stats = generateWorkflowGuide(process.cwd());
95
+ if (stats.created > 0) {
96
+ s.stop(`${t('SCAFFOLD.SUCCESS')} (${stats.created} new, ${stats.verified} verified)`);
97
+ } else {
98
+ s.stop(t('SCAFFOLD.ALREADY_EXISTS'));
99
+ }
100
+ } catch (e) {
101
+ s.stop(pc.red(t('SCAFFOLD.ERROR')));
102
+ }
103
+
104
+ // 2. Feature 5: Stack Selection
35
105
  const stackOptions = Object.entries(STACK_PROFILES).map(([key, profile]) => ({
36
106
  value: key,
37
107
  label: profile.label
38
108
  }));
39
109
 
40
110
  const stackProfile = await select({
41
- message: 'Qual é o perfil da sua Stack tecnológica?',
111
+ message: t('SETUP.STACK_SELECT'),
42
112
  options: stackOptions,
43
113
  initialValue: 'generic'
44
114
  });
45
115
 
46
- if (typeof stackProfile === 'symbol') { process.exit(0); } // Handle Cancel
116
+ if (typeof stackProfile === 'symbol') {
117
+ outro(pc.yellow(t('GENERAL.CANCELLED')));
118
+ process.exit(0);
119
+ }
47
120
 
48
- // 3. Feature 3: Regras Globais (Opcional)
121
+ // 3. Feature 3: Global Rules
49
122
  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...',
123
+ message: t('SETUP.GLOBAL_RULES'),
124
+ placeholder: t('SETUP.GLOBAL_RULES_HINT'),
52
125
  required: false
53
126
  });
54
127
 
55
- if (typeof globalRules === 'symbol') { process.exit(0); } // Handle Cancel
128
+ if (typeof globalRules === 'symbol') {
129
+ outro(pc.yellow(t('GENERAL.CANCELLED')));
130
+ process.exit(0);
131
+ }
56
132
 
57
- // 4. Seleção de Ferramentas (Múltipla escolha)
133
+ // 4. Tool Selection
58
134
  const tools = await multiselect({
59
- message: 'Para quais ferramentas você deseja instalar os Agentes?',
135
+ message: t('SETUP.TOOL_SELECT'),
60
136
  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' },
137
+ { value: 'gemini', label: t('TOOLS.GEMINI'), hint: '.gemini/commands/dev' },
138
+ { value: 'roo', label: t('TOOLS.ROO'), hint: '.roo/ & custom_modes.json' },
139
+ { value: 'cline', label: t('TOOLS.CLINE'), hint: '.cline/ & custom_modes.json' },
140
+ { value: 'cursor', label: t('TOOLS.CURSOR'), hint: '.cursor/rules/*.mdc' },
141
+ { value: 'windsurf', label: t('TOOLS.WINDSURF'), hint: '.windsurf/workflows/*.md' },
142
+ { value: 'claude', label: 'Claude Code', hint: '.claude/commands/openspec/*.md' },
143
+ { value: 'trae', label: t('TOOLS.TRAE'), hint: '.trae/instructions.md' },
144
+ { value: 'kilo', label: t('TOOLS.KILO'), hint: '.kilo/prompts/*.md' },
145
+ { value: 'copilot', label: t('TOOLS.COPILOT'), hint: '.github/copilot-instructions.md' },
146
+ { value: 'web', label: t('TOOLS.WEB'), hint: 'prompts/*.txt' },
147
+ { value: 'opencode', label: t('TOOLS.OPENCODE'), hint: '.opencode/*.md' }
71
148
  ],
72
149
  required: true,
73
- hint: 'Espaço para selecionar, Enter para confirmar'
150
+ hint: t('SETUP.TOOL_HINT')
74
151
  });
75
152
 
153
+ if (typeof tools === 'symbol') {
154
+ outro(pc.yellow(t('GENERAL.CANCELLED')));
155
+ process.exit(0);
156
+ }
157
+
76
158
  if (!tools || tools.length === 0) {
77
- outro('Nenhuma ferramenta selecionada. Operação cancelada.');
159
+ outro(t('SETUP.NO_TOOLS'));
78
160
  process.exit(0);
79
161
  }
80
162
 
81
- await processAgentsInstallation(tools, { stackProfile, globalRules });
163
+ await processAgentsInstallation(tools, { stackProfile, globalRules, locale: getLocale() });
82
164
 
83
- outro(pc.green('Configuração concluída com sucesso! 🚀'));
165
+ outro(pc.green(t('SETUP.SUCCESS')));
84
166
  }
85
167
 
86
168
  async function processAgentsInstallation(tools, options) {
87
169
  const s = spinner();
88
- s.start('Carregando definições...');
170
+ s.start(t('INSTALL.LOADING'));
89
171
 
90
172
  try {
91
173
  const validAgents = await loadAgents(options);
92
174
 
93
175
  if (validAgents.length === 0) {
94
- s.stop('Nenhum agente válido encontrado.');
176
+ s.stop(t('INSTALL.NO_AGENTS'));
95
177
  return;
96
178
  }
97
179
 
98
- s.message(`Instalando agentes para: ${tools.join(', ')}...`);
180
+ s.message(t('INSTALL.INSTALLING', tools.join(', ')));
99
181
 
100
- // Itera sobre cada ferramenta selecionada
101
- for (const tool of tools) {
102
-
103
- // Instalação Específica por Ferramenta
104
- if (tool === 'gemini') {
182
+ const toolHandlers = {
183
+ gemini: async (validAgents, options) => {
105
184
  const targetDir = path.join(process.cwd(), '.gemini', 'commands', 'dev');
106
185
  await fsp.mkdir(targetDir, { recursive: true });
107
186
 
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);
187
+ await Promise.all(
188
+ validAgents.map((agent) => {
189
+ const toml = toGeminiTOML(agent, options);
190
+ const fileName = `${agent.originalName}.toml`;
191
+ return fsp.writeFile(path.join(targetDir, fileName), toml);
192
+ })
193
+ );
194
+ },
195
+ roo: async (validAgents, options) => {
196
+ const targetDir = path.join(process.cwd(), '.roo');
117
197
  await fsp.mkdir(targetDir, { recursive: true });
118
198
 
119
- await Promise.all(validAgents.map(agent => {
120
- const md = toKiloMarkdown(agent);
121
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
122
- }));
199
+ await Promise.all(
200
+ validAgents.map((agent) => {
201
+ const md = toKiloMarkdown(agent, options);
202
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
203
+ })
204
+ );
123
205
 
124
- const modes = validAgents.map(agent => toRooConfig(agent, agent.slug));
206
+ const modes = validAgents.map((agent) => toRooConfig(agent, agent.slug, options));
125
207
  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') {
208
+ await fsp.writeFile(path.join(process.cwd(), 'roo_custom_modes.json'), jsonContent);
209
+ },
210
+ cline: async (validAgents, options) => {
211
+ const targetDir = path.join(process.cwd(), '.cline');
212
+ await fsp.mkdir(targetDir, { recursive: true });
213
+
214
+ await Promise.all(
215
+ validAgents.map((agent) => {
216
+ const md = toKiloMarkdown(agent, options);
217
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
218
+ })
219
+ );
220
+
221
+ const modes = validAgents.map((agent) => toRooConfig(agent, agent.slug, options));
222
+ const jsonContent = JSON.stringify({ customModes: modes }, null, 2);
223
+ await fsp.writeFile(path.join(process.cwd(), 'cline_custom_modes.json'), jsonContent);
224
+ },
225
+ windsurf: async (validAgents, options) => {
226
+ const targetDir = path.join(process.cwd(), '.windsurf', 'workflows');
227
+ await fsp.mkdir(targetDir, { recursive: true });
228
+
229
+ await Promise.all(
230
+ validAgents.map((agent) => {
231
+ const md = toWindsurfRules(agent, options);
232
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
233
+ })
234
+ );
235
+ },
236
+ claude: async (validAgents, options) => {
237
+ const targetDir = path.join(process.cwd(), '.claude', 'commands', 'openspec');
238
+ await fsp.mkdir(targetDir, { recursive: true });
239
+
240
+ await Promise.all(
241
+ validAgents.map((agent) => {
242
+ const md = toClaudeCommand(agent, options);
243
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
244
+ })
245
+ );
246
+ },
247
+ cursor: async (validAgents, options) => {
248
+ const rulesDir = path.join(process.cwd(), '.cursor', 'rules');
249
+ await fsp.mkdir(rulesDir, { recursive: true });
250
+
251
+ await Promise.all(
252
+ validAgents.map((agent) => {
253
+ const mdc = toCursorMDC(agent, options);
254
+ return fsp.writeFile(path.join(rulesDir, `${agent.slug}.mdc`), mdc);
255
+ })
256
+ );
257
+ },
258
+ kilo: async (validAgents, options) => {
130
259
  const targetDir = path.join(process.cwd(), '.kilo', 'prompts');
131
260
  await fsp.mkdir(targetDir, { recursive: true });
132
261
 
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') {
262
+ await Promise.all(
263
+ validAgents.map((agent) => {
264
+ const md = toKiloMarkdown(agent, options);
265
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
266
+ })
267
+ );
268
+ },
269
+ copilot: async (validAgents, options) => {
139
270
  const githubDir = path.join(process.cwd(), '.github');
140
271
  const agentsDir = path.join(githubDir, 'agents');
141
272
  await fsp.mkdir(agentsDir, { recursive: true });
142
273
 
143
- await Promise.all(validAgents.map(agent => {
144
- const md = toCopilotInstructions(agent);
145
- return fsp.writeFile(path.join(agentsDir, `${agent.slug}.md`), md);
146
- }));
274
+ await Promise.all(
275
+ validAgents.map((agent) => {
276
+ const md = toCopilotInstructions(agent, options);
277
+ return fsp.writeFile(path.join(agentsDir, `${agent.slug}.md`), md);
278
+ })
279
+ );
147
280
 
148
- const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
149
- const mainInstructions = toCopilotInstructions(mainAgent);
281
+ const mainAgent = validAgents.find((a) => a.slug.includes('coder')) || validAgents[0];
282
+ const mainInstructions = toCopilotInstructions(mainAgent, options);
150
283
  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') {
284
+ },
285
+ trae: async (validAgents, options) => {
167
286
  const traeDir = path.join(process.cwd(), '.trae');
168
287
  await fsp.mkdir(traeDir, { recursive: true });
169
-
170
- const mainAgent = validAgents.find(a => a.slug.includes('coder')) || validAgents[0];
171
- const rules = toTraeRules(mainAgent);
288
+
289
+ const mainAgent = validAgents.find((a) => a.slug.includes('coder')) || validAgents[0];
290
+ const rules = toTraeRules(mainAgent, options);
172
291
  await fsp.writeFile(path.join(traeDir, 'instructions.md'), rules);
173
- }
174
- else if (tool === 'web') {
292
+ },
293
+ web: async (validAgents, options) => {
175
294
  const targetDir = path.join(process.cwd(), 'prompts');
176
295
  await fsp.mkdir(targetDir, { recursive: true });
177
296
 
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');
297
+ await Promise.all(
298
+ validAgents.map((agent) => {
299
+ const txt = toPlainSystemPrompt(agent, options);
300
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.txt`), txt);
301
+ })
302
+ );
303
+ },
304
+ opencode: async (validAgents, options) => {
305
+ const targetDir = path.join(process.cwd(), '.opencode', 'agent');
185
306
  await fsp.mkdir(targetDir, { recursive: true });
186
307
 
187
- await Promise.all(validAgents.map(agent => {
188
- const md = toKiloMarkdown(agent);
189
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
190
- }));
308
+ await Promise.all(
309
+ validAgents.map((agent) => {
310
+ const md = toOpenCodeAgent(agent, options);
311
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
312
+ })
313
+ );
314
+ }
315
+ };
316
+
317
+ for (const tool of tools) {
318
+ const handler = toolHandlers[tool];
319
+ if (handler) {
320
+ await handler(validAgents, options);
191
321
  }
192
322
  }
193
-
194
- s.stop('Instalação finalizada!');
195
-
196
- // Feedback consolidado
323
+
324
+ s.stop(t('INSTALL.FINISHED'));
325
+
197
326
  if (tools.includes('roo') || tools.includes('cline')) {
198
- note('Lembre-se de configurar os Custom Modes no settings.json para Roo/Cline.', 'Aviso');
327
+ note(t('INSTALL.ROO_WARNING'), t('INSTALL.ROO_WARNING_TITLE'));
199
328
  }
200
-
201
329
  } catch (e) {
202
- s.stop('Falha');
203
- console.error(pc.red(e.message));
330
+ s.stop(pc.red(`${t('INSTALL.FAILED')}: ${e.message}`));
331
+ process.exit(1);
204
332
  }
205
333
  }
206
334
 
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