sdd-toolkit 1.0.0 → 1.1.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/README.md +133 -133
- package/definitions/dev.coder.yaml +59 -59
- package/package.json +40 -40
- package/src/index.js +207 -183
- package/src/lib/agents.js +125 -68
- package/src/lib/docs.js +104 -104
- package/src/lib/profiles.js +186 -0
- package/src/lib/schema.js +13 -13
- package/src/lib/transformers.js +199 -199
package/src/index.js
CHANGED
|
@@ -1,183 +1,207 @@
|
|
|
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 } = require('@clack/prompts');
|
|
7
|
-
const pc = require('picocolors');
|
|
8
|
-
|
|
9
|
-
// Módulos Internos
|
|
10
|
-
const { loadAgents } = require('./lib/agents');
|
|
11
|
-
const {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
return fsp.writeFile(path.join(targetDir,
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
|
-
else if (tool === '
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
await fsp.mkdir(
|
|
118
|
-
|
|
119
|
-
await Promise.all(validAgents.map(agent => {
|
|
120
|
-
const md =
|
|
121
|
-
return fsp.writeFile(path.join(
|
|
122
|
-
}));
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
await
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
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);
|
package/src/lib/agents.js
CHANGED
|
@@ -1,68 +1,125 @@
|
|
|
1
|
-
const fs = require('fs/promises');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const yaml = require('js-yaml');
|
|
4
|
-
const { AgentSchema } = require('./schema');
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
1
|
+
const fs = require('fs/promises');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const yaml = require('js-yaml');
|
|
4
|
+
const { AgentSchema } = require('./schema');
|
|
5
|
+
const { STACK_PROFILES } = require('./profiles');
|
|
6
|
+
const pc = require('picocolors');
|
|
7
|
+
|
|
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
|
|
11
|
+
*
|
|
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
|
|
16
|
+
*/
|
|
17
|
+
async function loadAgents(options = {}) {
|
|
18
|
+
const definitionsDir = path.join(__dirname, '..', '..', 'definitions');
|
|
19
|
+
const localDefinitionsDir = path.join(process.cwd(), '.sdd', 'agents');
|
|
20
|
+
|
|
21
|
+
// Verifica diretório padrão
|
|
22
|
+
try {
|
|
23
|
+
await fs.access(definitionsDir);
|
|
24
|
+
} catch {
|
|
25
|
+
throw new Error(`Pasta de definições padrão não encontrada: ${definitionsDir}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Identifica arquivos padrão
|
|
29
|
+
const files = await fs.readdir(definitionsDir);
|
|
30
|
+
const yamlFiles = files.filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
31
|
+
|
|
32
|
+
// Verifica se existe diretório de sobrescrita local
|
|
33
|
+
let hasLocalOverrides = false;
|
|
34
|
+
try {
|
|
35
|
+
await fs.access(localDefinitionsDir);
|
|
36
|
+
hasLocalOverrides = true;
|
|
37
|
+
} catch {
|
|
38
|
+
// Ignora se não existir
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Leitura e processamento em paralelo
|
|
42
|
+
const results = await Promise.all(yamlFiles.map(async (file) => {
|
|
43
|
+
try {
|
|
44
|
+
let content;
|
|
45
|
+
let source = 'default';
|
|
46
|
+
|
|
47
|
+
// Feature 2: Sobrescrita Local
|
|
48
|
+
if (hasLocalOverrides) {
|
|
49
|
+
try {
|
|
50
|
+
const localPath = path.join(localDefinitionsDir, file);
|
|
51
|
+
await fs.access(localPath);
|
|
52
|
+
content = await fs.readFile(localPath, 'utf8');
|
|
53
|
+
source = 'local';
|
|
54
|
+
} catch {
|
|
55
|
+
// Arquivo local não existe, usa padrão
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!content) {
|
|
60
|
+
content = await fs.readFile(path.join(definitionsDir, file), 'utf8');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const raw = yaml.load(content);
|
|
64
|
+
|
|
65
|
+
const parsed = AgentSchema.safeParse(raw);
|
|
66
|
+
if (!parsed.success) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
file,
|
|
70
|
+
error: 'Validação do Schema falhou',
|
|
71
|
+
details: parsed.error.format()
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const agent = parsed.data;
|
|
76
|
+
|
|
77
|
+
// Normaliza o slug
|
|
78
|
+
agent.slug = file.replace(/\.ya?ml$/, '').replace(/\./g, '-');
|
|
79
|
+
agent.originalName = file.replace(/\.ya?ml$/, '');
|
|
80
|
+
agent.source = source; // Metadata útil para logs
|
|
81
|
+
|
|
82
|
+
// Feature 5: Injeção de Regras de Stack
|
|
83
|
+
if (options.stackProfile && STACK_PROFILES[options.stackProfile]) {
|
|
84
|
+
const stackRules = STACK_PROFILES[options.stackProfile].rules;
|
|
85
|
+
if (stackRules && stackRules.length > 0) {
|
|
86
|
+
agent.rules = [...agent.rules, ...stackRules];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Feature 3: Injeção de Regras Globais
|
|
91
|
+
if (options.globalRules && typeof options.globalRules === 'string') {
|
|
92
|
+
const customRules = options.globalRules
|
|
93
|
+
.split('\n')
|
|
94
|
+
.map(r => r.trim())
|
|
95
|
+
.filter(r => r.length > 0);
|
|
96
|
+
|
|
97
|
+
if (customRules.length > 0) {
|
|
98
|
+
agent.rules = [...agent.rules, ...customRules];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { success: true, agent };
|
|
103
|
+
|
|
104
|
+
} catch (e) {
|
|
105
|
+
return { success: false, file, error: e.message };
|
|
106
|
+
}
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
// Separa sucessos e falhas
|
|
110
|
+
const validAgents = [];
|
|
111
|
+
const errors = [];
|
|
112
|
+
|
|
113
|
+
results.forEach(res => {
|
|
114
|
+
if (res.success) {
|
|
115
|
+
validAgents.push(res.agent);
|
|
116
|
+
} else {
|
|
117
|
+
errors.push(res);
|
|
118
|
+
console.warn(pc.yellow(`⚠️ Ignorando ${res.file}: ${res.error}`));
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return validAgents;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = { loadAgents };
|