sdd-toolkit 2.1.0 → 3.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.
@@ -0,0 +1,136 @@
1
+ # SKILL.md — Feature Templates
2
+
3
+ ---
4
+ name: feature-templates
5
+ description: Standard templates for creating feature structures
6
+ ---
7
+
8
+ ## Objective
9
+ This skill contains templates for creating feature structures in SDD Toolkit.
10
+
11
+ ---
12
+
13
+ ## Directory Structure
14
+
15
+ ```
16
+ .sdd-toolkit/features/[feature-slug]/
17
+ ├── index.md # Overview + roadmap
18
+ ├── state.md # Progress + context + files
19
+ ├── MT01.md # Milestone 1
20
+ ├── MT02.md # Milestone 2 (if needed)
21
+ └── ...
22
+ ```
23
+
24
+ ---
25
+
26
+ ## Template: index.md
27
+
28
+ ```markdown
29
+ # 🚀 Feature: [Name]
30
+
31
+ ## Overview
32
+ - **Objective:** [Brief description of this feature's value]
33
+ - **Linked Requirements:** [FR-XXX, FR-YYY]
34
+
35
+ ## Roadmap
36
+ - **MT01:** [Milestone Name]
37
+ - **MT02:** [Milestone Name]
38
+
39
+ ## Dependencies
40
+ - **Depends on:** [other features or "None"]
41
+ - **Blocks:** [other features or "None"]
42
+
43
+ ## Notes
44
+ [Additional context or important decisions]
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Template: state.md
50
+
51
+ ```markdown
52
+ # 📊 Feature: [Name] - State
53
+
54
+ ## Progress
55
+ | Milestone | Status | Tasks |
56
+ |-----------|--------|-------|
57
+ | MT01 | ⏳ Not Started | 0/X |
58
+ | MT02 | ⏳ Not Started | 0/Y |
59
+
60
+ ## Current Work
61
+ - **Last Task:** None
62
+ - **Current Task:** MT01-task 1 (awaiting start)
63
+ - **Next Task:** MT01-task 2
64
+
65
+ ## Technical Context
66
+ ### Created Files
67
+ No files created yet.
68
+
69
+ ### Decisions Made
70
+ | Date | Type | Description |
71
+ |------|------|-------------|
72
+ | - | - | No decisions recorded |
73
+
74
+ ## Known Issues
75
+ No issues reported.
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Template: MTxx.md (Milestone)
81
+
82
+ ```markdown
83
+ # 🏁 MT01: [Milestone Name]
84
+
85
+ **Objective:** [What will be delivered and tested at the end of this stage]
86
+
87
+ ## Tasks
88
+
89
+ ### MT01-task 1 — [Title]
90
+ - **Description:** [What should be done]
91
+ - **Reference:** [FR-XXX / BR-YYY]
92
+ - **DoD:** [Definition of Done - verifiable result]
93
+ - **Status:** ⏳ Not Started
94
+
95
+ ### MT01-task 2 — [Title]
96
+ - **Description:** [What should be done]
97
+ - **Reference:** [FR-XXX / BR-YYY]
98
+ - **DoD:** [Definition of Done - verifiable result]
99
+ - **Status:** ⏳ Not Started
100
+
101
+ ## Milestone Acceptance Criteria
102
+ - [ ] All tasks completed
103
+ - [ ] Code reviewed by QA Engineer
104
+ - [ ] Tests passing (if applicable)
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Creation Rules
110
+
111
+ ### Naming Convention
112
+ | Element | Format | Example |
113
+ |---------|--------|---------|
114
+ | Feature slug | `kebab-case` | `user-authentication` |
115
+ | Milestone | `MTXX` | `MT01`, `MT02` |
116
+ | Task | `MTXX-task Y` | `MT01-task 1` |
117
+ | Hotfix | `fix-[name]` | `fix-login-bug` |
118
+ | Refactor | `refactor-[name]` | `refactor-api-layer` |
119
+
120
+ ### Limits
121
+ - **Maximum 5 tasks per milestone** — If exceeded, create new milestone
122
+ - **Maximum 4-5 milestones per feature** — If exceeded, split the feature
123
+ - **Each task must have verifiable DoD** — No DoD = poorly defined task
124
+
125
+ ### Sequence
126
+ Tasks within a milestone should be in **logical build order**:
127
+ 1. Setup/Configuration first
128
+ 2. Business logic after
129
+ 3. Tests last (or together with logic, if TDD)
130
+
131
+ ---
132
+
133
+ ## Notes
134
+ - This skill is used by Feature Manager when creating new features
135
+ - Templates can be adapted as needed for the project
136
+ - Always update `.sdd-toolkit/context.md` after creating a feature
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: handover-protocol
3
+ description: Standardized closure and handover protocol between SDD Toolkit agents. Use when completing a phase and needing to direct to the next agent.
4
+ ---
5
+
6
+ # Handover Protocol
7
+
8
+ This skill standardizes the transition between SDD Toolkit agents, ensuring consistency and traceability in communication.
9
+
10
+ ## When to Use
11
+
12
+ - When completing a work phase (scope, requirements, feature, code, review, release)
13
+ - When passing context to the next agent in the chain
14
+ - When finishing a task and needing to indicate next steps
15
+
16
+ ## Handover Structure
17
+
18
+ When finishing, you MUST use this format:
19
+
20
+ ```markdown
21
+ > "🏷️ **[Artifact Name] successfully documented.**"
22
+ >
23
+ > **File Created/Updated:** `[file path]`
24
+ >
25
+ > **Summary:** [1-2 lines of what was done]
26
+ >
27
+ > **Next Step:** Use `/[command]` to start the next phase.
28
+ >
29
+ > **Handover to:** [Next Agent Name] ([emoji])
30
+ ```
31
+
32
+ ## Handover Map (Standard Flow)
33
+
34
+ | Current Agent | Next Agent | Command |
35
+ |---------------|------------|---------|
36
+ | Project Architect 🏛️ | Requirements Engineer 📝 | `/sdd.requirements` |
37
+ | Requirements Engineer 📝 | Feature Manager ✨ | `/sdd.feature` |
38
+ | Feature Manager ✨ | Coder 💻 | `/sdd.coder [Task_ID]` |
39
+ | Coder 💻 | QA Engineer 🔍 | `/sdd.review [Task_ID]` |
40
+ | QA Engineer 🔍 (Approved) | Release Manager 📦 | `/sdd.log` or next task |
41
+ | QA Engineer 🔍 (Rejected) | Coder 💻 | `/sdd.coder [Task_ID]` (fix) |
42
+
43
+ ## Rules
44
+
45
+ 1. **Never finish without handover** — The user must know exactly what to do next.
46
+ 2. **Use consistent emojis** — Each agent has their fixed emoji.
47
+ 3. **Cite the created file** — Always include the path of the generated artifact.
48
+ 4. **Be concise** — Handover is not a summary; it's direction.
49
+
50
+ ## Usage Example
51
+
52
+ ```markdown
53
+ > "🏛️ **Project scope successfully documented.**"
54
+ >
55
+ > **File Created:** `.sdd-toolkit/project.md`
56
+ >
57
+ > **Summary:** Defined conceptual scope for NBA Stats Collector v1.0.0 project.
58
+ >
59
+ > **Next Step:** Use `/sdd.requirements` to detail functional requirements.
60
+ >
61
+ > **Handover to:** Requirements Engineer 📝
62
+ ```
@@ -0,0 +1,124 @@
1
+ # SKILL.md — Stack Interview
2
+
3
+ ---
4
+ name: stack-interview
5
+ description: Interview protocol for tech stack definition
6
+ ---
7
+
8
+ ## Objective
9
+ This skill guides the interview with the user to define the project's tech stack in a structured but unbiased manner.
10
+
11
+ ---
12
+
13
+ ## When to Use
14
+ - Tech stack is not defined in `.sdd-toolkit/requirements.md`
15
+ - User requests stack change
16
+ - Brownfield project needs to document existing stack
17
+
18
+ ---
19
+
20
+ ## Interview Principles
21
+
22
+ ### Be Collaborative (Not Imposing)
23
+ Stack definition is a **joint decision**. You're not just an answer collector, nor a technology dictator.
24
+
25
+ **Your role:**
26
+ 1. **Listen** to the user's preference
27
+ 2. **Evaluate** if the choice is adequate for the project scope (consult `project.md`)
28
+ 3. **Discuss** pros and cons when there are legitimate concerns
29
+ 4. **Arrive together** at a decision that makes sense for both
30
+
31
+ **Examples of collaborative dialogue:**
32
+ - ✅ "You mentioned MongoDB. Considering the project has many relationships between entities (per project.md), a relational database like PostgreSQL could help. What do you think? Is there a specific reason for NoSQL?"
33
+ - ✅ "I understand you want to use React. Makes sense! For this project with many forms, have you considered any form management solution? No need to decide now, just for us to keep in mind."
34
+ - ❌ "MongoDB is not adequate. Use PostgreSQL." (imposing)
35
+ - ❌ "Ok, MongoDB." (too passive)
36
+
37
+ ### Be Agnostic (But Informed)
38
+ - **DO NOT** list specific options as a choice menu
39
+ - **ASK** openly: "Which framework do you plan to use?"
40
+ - **EVALUATE** the response considering the project scope
41
+ - **DISCUSS** if you identify possible challenges, but **RESPECT** the user's final decision
42
+
43
+ ### Be Efficient
44
+ - Group related questions when possible
45
+ - Maximum of 4-5 question rounds
46
+ - If user doesn't know, mark as "TBD" (to be defined)
47
+
48
+ ---
49
+
50
+ ## Interview Script
51
+
52
+ ### Round 1: Frontend
53
+ > "Let's define the tech stack. Starting with **Frontend**:
54
+ > 1. Which framework/library do you plan to use? (or 'none' if server-side)
55
+ > 2. How do you plan to style? (Pure CSS, Tailwind, Styled Components, etc.)
56
+ > 3. Will you need state management? If so, which solution?"
57
+
58
+ ### Round 2: Backend
59
+ > "Now for **Backend**:
60
+ > 1. Which programming language?
61
+ > 2. Which framework (if any)?
62
+ > 3. What API style? (REST, GraphQL, gRPC)
63
+ > 4. How will authentication work? (JWT, OAuth, sessions, etc.)"
64
+
65
+ ### Round 3: Data
66
+ > "About **Database**:
67
+ > 1. Which primary database?
68
+ > 2. Will you use any ORM? Which one?
69
+ > 3. How will you manage migrations?"
70
+
71
+ ### Round 4: Infrastructure (Optional)
72
+ > "Finally, **Infrastructure** (can skip if you don't know yet):
73
+ > 1. Will you use containers (Docker)?
74
+ > 2. Which CI/CD platform?
75
+ > 3. Where do you plan to host?"
76
+
77
+ ---
78
+
79
+ ## Response Handling
80
+
81
+ | User Response | Action |
82
+ |---------------|--------|
83
+ | Specific technology | Document as defined |
84
+ | "I don't know yet" / "TBD" | Document as "TBD" |
85
+ | "None" / "Not applicable" | Document as "N/A" |
86
+ | Unknown technology | Accept and document (don't question) |
87
+
88
+ ---
89
+
90
+ ## Output Format
91
+
92
+ After the interview, document in `requirements.md`:
93
+
94
+ ```markdown
95
+ ## 1. Tech Stack
96
+
97
+ ### Frontend
98
+ - **Framework:** [response or TBD]
99
+ - **Styling:** [response or TBD]
100
+ - **State:** [response or N/A]
101
+
102
+ ### Backend
103
+ - **Language:** [response]
104
+ - **Framework:** [response or None]
105
+ - **API:** [REST / GraphQL / gRPC]
106
+ - **Auth:** [response or TBD]
107
+
108
+ ### Data
109
+ - **Database:** [response or TBD]
110
+ - **ORM:** [response or None]
111
+ - **Migrations:** [response or TBD]
112
+
113
+ ### Infrastructure
114
+ - **Containers:** [response or TBD]
115
+ - **CI/CD:** [response or TBD]
116
+ - **Hosting:** [response or TBD]
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Notes
122
+ - This skill is called by the Requirements Engineer when the stack is not defined
123
+ - Never suggest specific technologies — let the user decide
124
+ - If the project is brownfield, also use the `detect-manifest` skill to validate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-toolkit",
3
- "version": "2.1.0",
3
+ "version": "3.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
@@ -9,21 +9,9 @@ const pc = require('picocolors');
9
9
  // Internal Modules
10
10
  const { loadAgents } = require('./lib/agents');
11
11
  const { setLocale, t, getLocale } = require('./lib/i18n');
12
- const {
13
- toGeminiTOML,
14
- toRooConfig,
15
- toKiloMarkdown,
16
- toCopilotInstructions,
17
- toCursorMDC,
18
- toWindsurfRules,
19
- toClaudeCommand,
20
- toPlainSystemPrompt,
21
- toTraeRules,
22
- toOpenCodeSkill,
23
- toAntigravitySkill
24
- } = require('./lib/transformers');
25
12
  const { generateWorkflowGuide } = require('./lib/docs');
26
13
  const { view } = require('./commands/view');
14
+ const handlers = require('./lib/handlers');
27
15
 
28
16
  async function main() {
29
17
  console.clear();
@@ -68,20 +56,30 @@ async function main() {
68
56
  if (fs.existsSync(path.join(process.cwd(), '.roo'))) tools.push('roo');
69
57
  if (fs.existsSync(path.join(process.cwd(), '.cline'))) tools.push('cline');
70
58
  if (fs.existsSync(path.join(process.cwd(), '.cursor'))) tools.push('cursor');
71
- if (fs.existsSync(path.join(process.cwd(), '.windsurf'))) tools.push('windsurf');
72
59
  if (fs.existsSync(path.join(process.cwd(), '.claude'))) tools.push('claude');
73
- if (fs.existsSync(path.join(process.cwd(), '.trae'))) tools.push('trae');
74
60
  if (fs.existsSync(path.join(process.cwd(), '.kilocode'))) tools.push('kilo');
75
- if (fs.existsSync(path.join(process.cwd(), '.github'))) tools.push('copilot');
76
- if (fs.existsSync(path.join(process.cwd(), '.roo'))) tools.push('roo');
77
61
  if (fs.existsSync(path.join(process.cwd(), '.opencode'))) tools.push('opencode');
78
- if (fs.existsSync(path.join(process.cwd(), 'prompts'))) tools.push('web');
79
-
80
- if (fs.existsSync(path.join(process.cwd(), '.antigravity'))) tools.push('antigravity');
62
+ if (fs.existsSync(path.join(process.cwd(), '.antigravity')) || fs.existsSync(path.join(process.cwd(), '.agent'))) tools.push('antigravity');
81
63
  if (tools.length === 0) {
82
64
  note(t('UPGRADE.NO_CONFIG'), t('UPGRADE.NO_CONFIG_TITLE'));
83
65
  } else {
84
66
  note(t('UPGRADE.DETECTED_TOOLS', tools.join(', ')), t('UPGRADE.DETECTED_TITLE'));
67
+
68
+ // 1. Smart Scaffolding (Update folders, preserve files)
69
+ const s = spinner();
70
+ s.start(t('SCAFFOLD.LOADING'));
71
+ try {
72
+ const stats = generateWorkflowGuide(process.cwd());
73
+ if (stats.created > 0) {
74
+ s.stop(`${t('SCAFFOLD.SUCCESS')} (${stats.created} new, ${stats.verified} verified)`);
75
+ } else {
76
+ s.stop(t('SCAFFOLD.ALREADY_EXISTS'));
77
+ }
78
+ } catch (e) {
79
+ s.stop(pc.red(t('SCAFFOLD.ERROR')));
80
+ }
81
+
82
+ // 2. Update Agents
85
83
  await processAgentsInstallation(tools, { locale: getLocale() });
86
84
  outro(pc.green(t('UPGRADE.SUCCESS')));
87
85
  process.exit(0);
@@ -119,18 +117,13 @@ async function main() {
119
117
  const tools = await multiselect({
120
118
  message: t('SETUP.TOOL_SELECT'),
121
119
  options: [
122
- { value: 'gemini', label: t('TOOLS.GEMINI'), hint: '.gemini/commands/dev' },
123
- { value: 'roo', label: t('TOOLS.ROO'), hint: '.roo/commands/*.md' },
124
- { value: 'cline', label: t('TOOLS.CLINE'), hint: '.cline/ & custom_modes.json' },
125
- { value: 'cursor', label: t('TOOLS.CURSOR'), hint: '.cursor/commands/*.mdc' },
126
- { value: 'windsurf', label: t('TOOLS.WINDSURF'), hint: '.windsurf/workflows/*.md' },
127
- { value: 'claude', label: 'Claude Code', hint: '.claude/commands/agents/*.md' },
128
- { value: 'trae', label: t('TOOLS.TRAE'), hint: '.trae/instructions.md' },
129
- { value: 'kilo', label: t('TOOLS.KILO'), hint: '.kilocode/workflows/*.md' },
130
- { value: 'copilot', label: t('TOOLS.COPILOT'), hint: '.github/prompts/*.md' },
131
- { value: 'web', label: t('TOOLS.WEB'), hint: 'prompts/*.txt' },
132
- { value: 'opencode', label: t('TOOLS.OPENCODE'), hint: '.opencode/skills/*' },
133
- { value: 'antigravity', label: t('TOOLS.ANTIGRAVITY'), hint: '.antigravity/skills/*' }
120
+ { value: 'gemini', label: t('TOOLS.GEMINI'), hint: '.gemini/commands/* & skills/*' },
121
+ { value: 'roo', label: t('TOOLS.ROO'), hint: '.roo/skills/*' },
122
+ { value: 'cursor', label: t('TOOLS.CURSOR'), hint: '.cursor/commands/* & skills/*' },
123
+ { value: 'claude', label: 'Claude Code', hint: '.claude/commands/* & skills/* & agents/*' },
124
+ { value: 'kilo', label: t('TOOLS.KILO'), hint: '.kilocode/workflows/* & skills/*' },
125
+ { value: 'opencode', label: t('TOOLS.OPENCODE'), hint: '.opencode/skills/* & agents/*' },
126
+ { value: 'antigravity', label: t('TOOLS.ANTIGRAVITY'), hint: '.agent/skills/* & workflows/*' }
134
127
  ],
135
128
  required: true,
136
129
  hint: t('SETUP.TOOL_HINT')
@@ -165,167 +158,10 @@ async function processAgentsInstallation(tools, options) {
165
158
 
166
159
  s.message(t('INSTALL.INSTALLING', tools.join(', ')));
167
160
 
168
- const toolHandlers = {
169
- gemini: async (validAgents, options) => {
170
- const targetDir = path.join(process.cwd(), '.gemini', 'commands', 'dev');
171
- await fsp.mkdir(targetDir, { recursive: true });
172
-
173
- await Promise.all(
174
- validAgents.map((agent) => {
175
- const toml = toGeminiTOML(agent, options);
176
- const fileName = `${agent.originalName}.toml`;
177
- return fsp.writeFile(path.join(targetDir, fileName), toml);
178
- })
179
- );
180
- },
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
- },
192
- cline: async (validAgents, options) => {
193
- const targetDir = path.join(process.cwd(), '.cline');
194
- await fsp.mkdir(targetDir, { recursive: true });
195
-
196
- await Promise.all(
197
- validAgents.map((agent) => {
198
- const md = toKiloMarkdown(agent, options);
199
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
200
- })
201
- );
202
-
203
- const modes = validAgents.map((agent) => toRooConfig(agent, agent.slug, options));
204
- const jsonContent = JSON.stringify({ customModes: modes }, null, 2);
205
- await fsp.writeFile(path.join(process.cwd(), 'cline_custom_modes.json'), jsonContent);
206
- },
207
- windsurf: async (validAgents, options) => {
208
- const targetDir = path.join(process.cwd(), '.windsurf', 'workflows');
209
- await fsp.mkdir(targetDir, { recursive: true });
210
-
211
- await Promise.all(
212
- validAgents.map((agent) => {
213
- const md = toWindsurfRules(agent, options);
214
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
215
- })
216
- );
217
- },
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 });
243
-
244
- await Promise.all(
245
- validAgents.map((agent) => {
246
- const md = toKiloMarkdown(agent, options);
247
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.md`), md);
248
- })
249
- );
250
- },
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
- },
267
- trae: async (validAgents, options) => {
268
- const traeDir = path.join(process.cwd(), '.trae');
269
- await fsp.mkdir(traeDir, { recursive: true });
270
-
271
- const mainAgent = validAgents.find((a) => a.slug.includes('coder')) || validAgents[0];
272
- const rules = toTraeRules(mainAgent, options);
273
- await fsp.writeFile(path.join(traeDir, 'instructions.md'), rules);
274
- },
275
- web: async (validAgents, options) => {
276
- const targetDir = path.join(process.cwd(), 'prompts');
277
- await fsp.mkdir(targetDir, { recursive: true });
278
-
279
- await Promise.all(
280
- validAgents.map((agent) => {
281
- const txt = toPlainSystemPrompt(agent, options);
282
- return fsp.writeFile(path.join(targetDir, `${agent.slug}.txt`), txt);
283
- })
284
- );
285
- },
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
- }
323
- };
324
-
325
161
  for (const tool of tools) {
326
- const handler = toolHandlers[tool];
327
- if (handler) {
328
- await handler(validAgents, options);
162
+ const handler = handlers[tool];
163
+ if (handler && typeof handler.install === 'function') {
164
+ await handler.install(validAgents, options);
329
165
  }
330
166
  }
331
167
 
@@ -0,0 +1,34 @@
1
+ const fsp = require('fs/promises');
2
+ const path = require('path');
3
+ const { toAntigravitySkill, toAntigravityWorkflow } = require('../transformers');
4
+
5
+ /**
6
+ * Handles installation for Antigravity
7
+ * @param {Array} agents - List of agents to install
8
+ * @param {Object} options - Installation options
9
+ */
10
+ async function install(agents, options) {
11
+ const skillsDir = path.join(process.cwd(), '.agent', 'skills');
12
+ const workflowsDir = path.join(process.cwd(), '.agent', 'workflows');
13
+
14
+ await fsp.mkdir(skillsDir, { recursive: true });
15
+ await fsp.mkdir(workflowsDir, { recursive: true });
16
+
17
+ await Promise.all(
18
+ agents.map(async (agent) => {
19
+ const skillName = agent.slug.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
20
+
21
+ // Generate Skill: .agent/skills/[agent-slug]/SKILL.md
22
+ const agentSkillDir = path.join(skillsDir, skillName);
23
+ await fsp.mkdir(agentSkillDir, { recursive: true });
24
+ const skillContent = toAntigravitySkill(agent, options);
25
+ await fsp.writeFile(path.join(agentSkillDir, 'SKILL.md'), skillContent);
26
+
27
+ // Generate Workflow: .agent/workflows/[agent-slug].md
28
+ const workflowContent = toAntigravityWorkflow(agent, options);
29
+ await fsp.writeFile(path.join(workflowsDir, `${skillName}.md`), workflowContent);
30
+ })
31
+ );
32
+ }
33
+
34
+ module.exports = { install };
@@ -0,0 +1,40 @@
1
+ const fsp = require('fs/promises');
2
+ const path = require('path');
3
+ const { toClaudeCommand, toClaudeSkill, toClaudeSubagent } = require('../transformers');
4
+
5
+ /**
6
+ * Handles installation for Claude Code
7
+ * @param {Array} agents - List of agents to install
8
+ * @param {Object} options - Installation options
9
+ */
10
+ async function install(agents, options) {
11
+ const commandsDir = path.join(process.cwd(), '.claude', 'commands', 'agents');
12
+ const skillsDir = path.join(process.cwd(), '.claude', 'skills');
13
+ const agentsDir = path.join(process.cwd(), '.claude', 'agents');
14
+
15
+ await fsp.mkdir(commandsDir, { recursive: true });
16
+ await fsp.mkdir(skillsDir, { recursive: true });
17
+ await fsp.mkdir(agentsDir, { recursive: true });
18
+
19
+ await Promise.all(
20
+ agents.map(async (agent) => {
21
+ const skillName = agent.slug.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
22
+
23
+ // Generate Command
24
+ const command = toClaudeCommand(agent, options);
25
+ await fsp.writeFile(path.join(commandsDir, `${agent.slug}.md`), command);
26
+
27
+ // Generate Skill
28
+ const agentSkillDir = path.join(skillsDir, skillName);
29
+ await fsp.mkdir(agentSkillDir, { recursive: true });
30
+ const skill = toClaudeSkill(agent, options);
31
+ await fsp.writeFile(path.join(agentSkillDir, 'SKILL.md'), skill);
32
+
33
+ // Generate Subagent
34
+ const subagent = toClaudeSubagent(agent, options);
35
+ await fsp.writeFile(path.join(agentsDir, `${skillName}.md`), subagent);
36
+ })
37
+ );
38
+ }
39
+
40
+ module.exports = { install };