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.
- package/README.md +22 -22
- package/definitions/AGENTS.md +114 -0
- package/definitions/RULES.md +248 -0
- package/definitions/sdd-backend.yaml +427 -0
- package/definitions/sdd-coder.yaml +237 -161
- package/definitions/sdd-feature.yaml +272 -140
- package/definitions/sdd-frontend.yaml +423 -0
- package/definitions/sdd-log.yaml +70 -70
- package/definitions/sdd-project.yaml +298 -179
- package/definitions/sdd-prompt.yaml +334 -0
- package/definitions/sdd-requirements.yaml +323 -136
- package/definitions/sdd-review.yaml +197 -105
- package/definitions/sdd-security.yaml +335 -0
- package/definitions/sdd-test.yaml +369 -0
- package/definitions/skills/brownfield-setup/SKILL.md +119 -0
- package/definitions/skills/detect-manifest/SKILL.md +97 -0
- package/definitions/skills/feature-templates/SKILL.md +136 -0
- package/definitions/skills/handover-protocol/SKILL.md +62 -0
- package/definitions/skills/stack-interview/SKILL.md +124 -0
- package/package.json +1 -1
- package/src/index.js +28 -192
- package/src/lib/handlers/antigravity.js +34 -0
- package/src/lib/handlers/claude.js +40 -0
- package/src/lib/handlers/cursor.js +34 -0
- package/src/lib/handlers/gemini.js +34 -0
- package/src/lib/handlers/index.js +17 -0
- package/src/lib/handlers/kilo.js +34 -0
- package/src/lib/handlers/opencode.js +36 -0
- package/src/lib/handlers/roo.js +27 -0
- package/src/lib/transformers.js +235 -3
- package/definitions/sdd.yaml +0 -29
|
@@ -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
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(), '
|
|
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
|
|
123
|
-
{ value: 'roo', label: t('TOOLS.ROO'), hint: '.roo/
|
|
124
|
-
{ value: '
|
|
125
|
-
{ value: '
|
|
126
|
-
{ value: '
|
|
127
|
-
{ value: '
|
|
128
|
-
{ value: '
|
|
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 =
|
|
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 };
|