sdd-toolkit 2.0.2 → 2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-toolkit",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Instalador automatico dos agentes de desenvolvimento",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -6,9 +6,9 @@ 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
- // Internal Modules
10
- const { loadAgents } = require('./lib/agents');
11
- const { setLocale, t, getLocale } = require('./lib/i18n');
9
+ // Internal Modules
10
+ const { loadAgents } = require('./lib/agents');
11
+ const { setLocale, t, getLocale } = require('./lib/i18n');
12
12
  const {
13
13
  toGeminiTOML,
14
14
  toRooConfig,
@@ -19,7 +19,8 @@ const {
19
19
  toClaudeCommand,
20
20
  toPlainSystemPrompt,
21
21
  toTraeRules,
22
- toOpenCodeAgent
22
+ toOpenCodeSkill,
23
+ toAntigravitySkill
23
24
  } = require('./lib/transformers');
24
25
  const { generateWorkflowGuide } = require('./lib/docs');
25
26
  const { view } = require('./commands/view');
@@ -71,11 +72,12 @@ async function main() {
71
72
  if (fs.existsSync(path.join(process.cwd(), '.claude'))) tools.push('claude');
72
73
  if (fs.existsSync(path.join(process.cwd(), '.trae'))) tools.push('trae');
73
74
  if (fs.existsSync(path.join(process.cwd(), '.kilocode'))) tools.push('kilo');
74
- if (fs.existsSync(path.join(process.cwd(), '.github'))) tools.push('copilot');
75
+ if (fs.existsSync(path.join(process.cwd(), '.github'))) tools.push('copilot');
75
76
  if (fs.existsSync(path.join(process.cwd(), '.roo'))) tools.push('roo');
76
77
  if (fs.existsSync(path.join(process.cwd(), '.opencode'))) tools.push('opencode');
77
78
  if (fs.existsSync(path.join(process.cwd(), 'prompts'))) tools.push('web');
78
79
 
80
+ if (fs.existsSync(path.join(process.cwd(), '.antigravity'))) tools.push('antigravity');
79
81
  if (tools.length === 0) {
80
82
  note(t('UPGRADE.NO_CONFIG'), t('UPGRADE.NO_CONFIG_TITLE'));
81
83
  } else {
@@ -99,10 +101,10 @@ async function main() {
99
101
  }
100
102
  } catch (e) {
101
103
  s.stop(pc.red(t('SCAFFOLD.ERROR')));
102
- }
103
-
104
- // 2. Feature 3: Global Rules
105
- const globalRules = await text({
104
+ }
105
+
106
+ // 2. Feature 3: Global Rules
107
+ const globalRules = await text({
106
108
  message: t('SETUP.GLOBAL_RULES'),
107
109
  placeholder: t('SETUP.GLOBAL_RULES_HINT'),
108
110
  required: false
@@ -127,7 +129,8 @@ async function main() {
127
129
  { value: 'kilo', label: t('TOOLS.KILO'), hint: '.kilocode/workflows/*.md' },
128
130
  { value: 'copilot', label: t('TOOLS.COPILOT'), hint: '.github/prompts/*.md' },
129
131
  { value: 'web', label: t('TOOLS.WEB'), hint: 'prompts/*.txt' },
130
- { value: 'opencode', label: t('TOOLS.OPENCODE'), hint: '.opencode/commands/*.md' }
132
+ { value: 'opencode', label: t('TOOLS.OPENCODE'), hint: '.opencode/skills/*' },
133
+ { value: 'antigravity', label: t('TOOLS.ANTIGRAVITY'), hint: '.antigravity/skills/*' }
131
134
  ],
132
135
  required: true,
133
136
  hint: t('SETUP.TOOL_HINT')
@@ -175,17 +178,17 @@ async function processAgentsInstallation(tools, options) {
175
178
  })
176
179
  );
177
180
  },
178
- roo: async (validAgents, options) => {
179
- const targetDir = path.join(process.cwd(), '.roo', 'commands');
180
- await fsp.mkdir(targetDir, { recursive: true });
181
-
182
- await Promise.all(
183
- validAgents.map((agent) => {
184
- const md = toOpenCodeAgent(agent, options);
185
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
186
- })
187
- );
188
- },
181
+ roo: async (validAgents, options) => {
182
+ const targetDir = path.join(process.cwd(), '.roo', 'commands');
183
+ await fsp.mkdir(targetDir, { recursive: true });
184
+
185
+ await Promise.all(
186
+ validAgents.map((agent) => {
187
+ const md = toOpenCodeAgent(agent, options);
188
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
189
+ })
190
+ );
191
+ },
189
192
  cline: async (validAgents, options) => {
190
193
  const targetDir = path.join(process.cwd(), '.cline');
191
194
  await fsp.mkdir(targetDir, { recursive: true });
@@ -212,31 +215,31 @@ async function processAgentsInstallation(tools, options) {
212
215
  })
213
216
  );
214
217
  },
215
- claude: async (validAgents, options) => {
216
- const targetDir = path.join(process.cwd(), '.claude', 'commands', 'agents');
217
- await fsp.mkdir(targetDir, { recursive: true });
218
-
219
- await Promise.all(
220
- validAgents.map((agent) => {
221
- const md = toClaudeCommand(agent, options);
222
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
223
- })
224
- );
225
- },
226
- cursor: async (validAgents, options) => {
227
- const commandsDir = path.join(process.cwd(), '.cursor', 'commands');
228
- await fsp.mkdir(commandsDir, { recursive: true });
229
-
230
- await Promise.all(
231
- validAgents.map((agent) => {
232
- const mdc = toCursorMDC(agent, options);
233
- return fsp.writeFile(path.join(commandsDir, `${agent.slug}.mdc`), mdc);
234
- })
235
- );
236
- },
237
- kilo: async (validAgents, options) => {
238
- const targetDir = path.join(process.cwd(), '.kilocode', 'workflows');
239
- await fsp.mkdir(targetDir, { recursive: true });
218
+ claude: async (validAgents, options) => {
219
+ const targetDir = path.join(process.cwd(), '.claude', 'commands', 'agents');
220
+ await fsp.mkdir(targetDir, { recursive: true });
221
+
222
+ await Promise.all(
223
+ validAgents.map((agent) => {
224
+ const md = toClaudeCommand(agent, options);
225
+ return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
226
+ })
227
+ );
228
+ },
229
+ cursor: async (validAgents, options) => {
230
+ const commandsDir = path.join(process.cwd(), '.cursor', 'commands');
231
+ await fsp.mkdir(commandsDir, { recursive: true });
232
+
233
+ await Promise.all(
234
+ validAgents.map((agent) => {
235
+ const mdc = toCursorMDC(agent, options);
236
+ return fsp.writeFile(path.join(commandsDir, `${agent.slug}.mdc`), mdc);
237
+ })
238
+ );
239
+ },
240
+ kilo: async (validAgents, options) => {
241
+ const targetDir = path.join(process.cwd(), '.kilocode', 'workflows');
242
+ await fsp.mkdir(targetDir, { recursive: true });
240
243
 
241
244
  await Promise.all(
242
245
  validAgents.map((agent) => {
@@ -245,22 +248,22 @@ async function processAgentsInstallation(tools, options) {
245
248
  })
246
249
  );
247
250
  },
248
- copilot: async (validAgents, options) => {
249
- const githubDir = path.join(process.cwd(), '.github');
250
- const promptsDir = path.join(githubDir, 'prompts');
251
- await fsp.mkdir(promptsDir, { recursive: true });
252
-
253
- await Promise.all(
254
- validAgents.map((agent) => {
255
- const md = toCopilotInstructions(agent, options);
256
- return fsp.writeFile(path.join(promptsDir, `${agent.slug}.md`), md);
257
- })
258
- );
259
-
260
- const mainAgent = validAgents.find((a) => a.slug.includes('coder')) || validAgents[0];
261
- const mainInstructions = toCopilotInstructions(mainAgent, options);
262
- await fsp.writeFile(path.join(githubDir, 'prompts.md'), mainInstructions);
263
- },
251
+ copilot: async (validAgents, options) => {
252
+ const githubDir = path.join(process.cwd(), '.github');
253
+ const promptsDir = path.join(githubDir, 'prompts');
254
+ await fsp.mkdir(promptsDir, { recursive: true });
255
+
256
+ await Promise.all(
257
+ validAgents.map((agent) => {
258
+ const md = toCopilotInstructions(agent, options);
259
+ return fsp.writeFile(path.join(promptsDir, `${agent.slug}.md`), md);
260
+ })
261
+ );
262
+
263
+ const mainAgent = validAgents.find((a) => a.slug.includes('coder')) || validAgents[0];
264
+ const mainInstructions = toCopilotInstructions(mainAgent, options);
265
+ await fsp.writeFile(path.join(githubDir, 'prompts.md'), mainInstructions);
266
+ },
264
267
  trae: async (validAgents, options) => {
265
268
  const traeDir = path.join(process.cwd(), '.trae');
266
269
  await fsp.mkdir(traeDir, { recursive: true });
@@ -280,51 +283,43 @@ async function processAgentsInstallation(tools, options) {
280
283
  })
281
284
  );
282
285
  },
283
- opencode: async (validAgents, options) => {
284
- const targetDir = path.join(process.cwd(), '.opencode', 'commands');
285
- await fsp.mkdir(targetDir, { recursive: true });
286
-
287
- await Promise.all(
288
- validAgents.map((agent) => {
289
- const md = toOpenCodeAgent(agent, options);
290
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
291
- })
292
- );
293
-
294
- // Generate AGENTS.md with interaction rules and agent location
295
- const agentsMdPath = path.join(process.cwd(), 'AGENTS.md');
296
- let agentsMdContent = `# Interaction Rules
297
-
298
- - Always respond to the user in the language they initially interact in; if they interact in English, respond in English, if they interact in Portuguese, respond in Portuguese.
299
- - If possible, display reasoning in the user's language as well.
300
- - Be didactic when explaining things, focus on providing complete responses and not just summaries.
301
- - Whenever possible, provide examples to illustrate concepts.
302
-
303
- # Allowed Commands
304
-
305
- - Never execute rm or rm -rf commands without confirming with the user.
306
- - Whenever possible, use more specific commands instead of generic ones.
307
- - Be cautious when using commands that may affect critical systems, such as shutdown or reboot.
308
- - For commands that may affect files or directories, always confirm with the user before executing.
309
- - Never execute commands that require administrative privileges (sudo, admin) without explicit permission from the user.
310
- - Avoid running background processes or daemons unless explicitly requested.
311
- - Be cautious when using commands that alter network settings, firewall configurations, or external connections.
312
- - Always quote file paths that contain spaces to avoid interpretation errors.
313
- - For package installation commands (npm install, pip install, etc.), confirm that the user has control over dependencies and versions.
314
- - Avoid irreversible git operations (such as force push or reset --hard) without confirmation.
315
-
316
- # Agent Location
317
-
318
- Custom agents are located in .opencode/commands/`;
319
-
320
- let userRules = '';
321
- if (options.globalRules && options.globalRules.trim()) {
322
- userRules = '\n\n# User Specified Rules\n\n' + options.globalRules.split('\n').filter(line => line.trim()).map(line => '- ' + line.trim()).join('\n');
323
- }
324
- agentsMdContent += userRules;
325
-
326
- await fsp.writeFile(agentsMdPath, agentsMdContent);
327
- }
286
+ opencode: async (validAgents, options) => {
287
+ const skillsDir = path.join(process.cwd(), '.opencode', 'skills');
288
+
289
+ // Ensure base directory exists
290
+ await fsp.mkdir(skillsDir, { recursive: true });
291
+
292
+ await Promise.all(
293
+ validAgents.map(async (agent) => {
294
+ // Create specific folder for the skill: .opencode/skills/[agent-slug]/
295
+ // Ensure compatibility with naming rules (lowercase, alphanumeric, single hyphens)
296
+ const skillName = agent.slug.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
297
+ const agentSkillDir = path.join(skillsDir, skillName);
298
+
299
+ await fsp.mkdir(agentSkillDir, { recursive: true });
300
+
301
+ const skillContent = toOpenCodeSkill(agent, options);
302
+ return fsp.writeFile(path.join(agentSkillDir, 'SKILL.md'), skillContent);
303
+ })
304
+ );
305
+ },
306
+ antigravity: async (validAgents, options) => {
307
+ const skillsDir = path.join(process.cwd(), '.antigravity', 'skills');
308
+
309
+ // Ensure base directory exists (though we will mkdir for each agent)
310
+ await fsp.mkdir(skillsDir, { recursive: true });
311
+
312
+ await Promise.all(
313
+ validAgents.map(async (agent) => {
314
+ // Create specific folder for the skill: .antigravity/skills/[agent-slug]/
315
+ const agentSkillDir = path.join(skillsDir, agent.slug);
316
+ await fsp.mkdir(agentSkillDir, { recursive: true });
317
+
318
+ const skillContent = toAntigravitySkill(agent, options);
319
+ return fsp.writeFile(path.join(agentSkillDir, 'SKILL.md'), skillContent);
320
+ })
321
+ );
322
+ }
328
323
  };
329
324
 
330
325
  for (const tool of tools) {
@@ -51,7 +51,8 @@ const EN = {
51
51
  KILO: 'Kilo Code',
52
52
  COPILOT: 'GitHub Copilot',
53
53
  WEB: 'OpenAI / Claude',
54
- OPENCODE: 'OpenCode',
54
+ OPENCODE: 'OpenCode (Skills)',
55
+ ANTIGRAVITY: 'Antigravity (Skills)',
55
56
  },
56
57
  LANGUAGE_RULES: {
57
58
  EN: 'Always reply in English unless told otherwise.',
@@ -124,7 +125,8 @@ const PT_BR = {
124
125
  KILO: 'Kilo Code',
125
126
  COPILOT: 'GitHub Copilot',
126
127
  WEB: 'OpenAI / Claude',
127
- OPENCODE: 'OpenCode',
128
+ OPENCODE: 'OpenCode (Skills)',
129
+ ANTIGRAVITY: 'Antigravity (Skills)',
128
130
  },
129
131
  LANGUAGE_RULES: {
130
132
  EN: 'Always reply in English unless told otherwise.',
@@ -197,7 +199,8 @@ const ES = {
197
199
  KILO: 'Kilo Code',
198
200
  COPILOT: 'GitHub Copilot',
199
201
  WEB: 'OpenAI / Claude',
200
- OPENCODE: 'OpenCode',
202
+ OPENCODE: 'OpenCode (Skills)',
203
+ ANTIGRAVITY: 'Antigravity (Skills)',
201
204
  },
202
205
  LANGUAGE_RULES: {
203
206
  EN: 'Always reply in English unless told otherwise.',
@@ -252,44 +252,34 @@ ${allRules.length > 0 ? '## Constraints\n' + allRules.map(r => `- ${r}`).join('\
252
252
  `;
253
253
  }
254
254
 
255
+
255
256
  /**
256
- * Converte para OpenCode Agent (.opencode/agent/*.md)
257
+ * Converte para OpenCode Skill (SKILL.md)
258
+ * Ref: https://opencode.ai/docs/skills/
257
259
  */
258
- function toOpenCodeAgent(agent, options = {}) {
260
+ function toOpenCodeSkill(agent, options = {}) {
259
261
  const languageRule = getLanguageRule(options.locale);
260
262
  const allRules = [languageRule, ...(agent.rules || [])];
261
263
 
262
- // Configurar permissões baseado no tipo de agente
263
- const isReadOnly = agent.slug.includes('review') || agent.slug.includes('audit') || agent.name.includes('Architect') || agent.role.includes('QA') || agent.role.includes('Review');
264
- const tools = {
265
- write: !isReadOnly,
266
- edit: !isReadOnly,
267
- bash: !isReadOnly
268
- };
269
-
270
- const frontmatter = {
271
- description: agent.description || agent.role,
272
- mode: 'subagent',
273
- temperature: 0.3,
274
- tools
275
- };
276
-
277
- const frontmatterStr = Object.entries(frontmatter)
278
- .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
279
- .join('\n');
264
+ // Ensure slug is compliant (lowercase, alphanumeric, single hyphens)
265
+ const skillName = agent.slug.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
280
266
 
281
267
  return `---
282
- ${frontmatterStr}
268
+ name: ${skillName}
269
+ description: ${agent.description || agent.role}
270
+ license: MIT
271
+ compatibility: opencode
272
+ metadata:
273
+ role: ${agent.role}
283
274
  ---
284
-
285
275
  # ${agent.name} ${agent.emoji}
286
276
 
287
277
  **Role**: ${agent.role}
288
278
 
279
+ ## Instructions
289
280
  ${agent.systemPrompt.trim()}
290
281
 
291
- ## Rules
292
- ${allRules.map(rule => `- ${rule}`).join('\n')}
282
+ ${allRules.length > 0 ? '## Rules & Guidelines\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
293
283
  `;
294
284
  }
295
285
 
@@ -312,6 +302,29 @@ ${allRules.length > 0 ? '## Constraints\n' + allRules.map(r => `- ${r}`).join('\
312
302
  `;
313
303
  }
314
304
 
305
+
306
+ /**
307
+ * Converte para Antigravity Skill (SKILL.md)
308
+ */
309
+ function toAntigravitySkill(agent, options = {}) {
310
+ const languageRule = getLanguageRule(options.locale);
311
+ const allRules = [languageRule, ...(agent.rules || [])];
312
+
313
+ return `---
314
+ name: ${agent.name}
315
+ description: ${agent.description || agent.role}
316
+ ---
317
+ # ${agent.name} ${agent.emoji}
318
+
319
+ **Role**: ${agent.role}
320
+
321
+ ## Instructions
322
+ ${agent.systemPrompt.trim()}
323
+
324
+ ${allRules.length > 0 ? '## Rules & Guidelines\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
325
+ `;
326
+ }
327
+
315
328
  module.exports = {
316
329
  toGeminiTOML,
317
330
  toRooConfig,
@@ -321,6 +334,7 @@ module.exports = {
321
334
  toWindsurfRules,
322
335
  toClaudeCommand,
323
336
  toPlainSystemPrompt,
324
- toOpenCodeAgent,
325
- toTraeRules
337
+ toOpenCodeSkill,
338
+ toTraeRules,
339
+ toAntigravitySkill
326
340
  };