sdd-toolkit 1.0.0 → 1.5.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 +155 -133
- package/definitions/dev.auditor.yaml +61 -49
- package/definitions/dev.coder.yaml +22 -3
- package/definitions/dev.feature.yaml +105 -108
- package/definitions/dev.log.yaml +90 -51
- package/definitions/dev.milestone.yaml +75 -62
- package/definitions/dev.ops.yaml +51 -39
- package/definitions/dev.project.yaml +106 -91
- package/definitions/dev.requirements.yaml +91 -76
- package/definitions/dev.review.yaml +61 -72
- package/definitions/dev.tasks.yaml +84 -70
- package/package.json +41 -40
- package/src/index.js +147 -46
- package/src/lib/agents.js +125 -68
- package/src/lib/docs.js +52 -88
- package/src/lib/i18n.js +65 -0
- package/src/lib/messages.js +186 -0
- package/src/lib/profiles.js +186 -0
- package/src/lib/schema.js +13 -13
- package/src/lib/transformers.js +73 -26
- package/src/scripts/archive.js +56 -0
- package/src/scripts/reset.js +19 -0
- package/src/scripts/status.js +58 -0
- package/templates/guidelines.md +9 -0
- package/templates/milestones.md +14 -0
- package/templates/project.md +28 -0
- package/templates/requirements.md +15 -0
- package/templates/task.md +11 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Technical Stack Profiles
|
|
3
|
+
* Defines additional rules to be injected into agents
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const STACK_PROFILES = {
|
|
7
|
+
// --- GENERIC ---
|
|
8
|
+
'generic': {
|
|
9
|
+
label: '🌐 Generic / None',
|
|
10
|
+
rules: []
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
// --- FRONTEND ---
|
|
14
|
+
'frontend-react': {
|
|
15
|
+
label: '🎨 Frontend: React + Tailwind',
|
|
16
|
+
rules: [
|
|
17
|
+
"Prefer Functional Components with Hooks.",
|
|
18
|
+
"Use Tailwind CSS for styling. Avoid inline styles.",
|
|
19
|
+
"Ensure accessibility (a11y) standards are met.",
|
|
20
|
+
"Use strict type checking if TypeScript is enabled.",
|
|
21
|
+
"Prefer React Query or SWR for data fetching."
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
'frontend-next': {
|
|
25
|
+
label: '🎨 Frontend: Next.js (App Router)',
|
|
26
|
+
rules: [
|
|
27
|
+
"Use App Router directory structure.",
|
|
28
|
+
"Prefer Server Components by default; use 'use client' only when necessary.",
|
|
29
|
+
"Optimize images using next/image.",
|
|
30
|
+
"Use Server Actions for mutations."
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
'frontend-vue': {
|
|
34
|
+
label: '🎨 Frontend: Vue.js 3 + Pinia',
|
|
35
|
+
rules: [
|
|
36
|
+
"Use Composition API with <script setup>.",
|
|
37
|
+
"Use Pinia for state management.",
|
|
38
|
+
"Prefer Tailwind CSS or Scoped CSS.",
|
|
39
|
+
"Follow the Vue Style Guide Priority A rules."
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
'frontend-angular': {
|
|
43
|
+
label: '🎨 Frontend: Angular',
|
|
44
|
+
rules: [
|
|
45
|
+
"Use Standalone Components.",
|
|
46
|
+
"Prefer Signals over RxJS for synchronous state.",
|
|
47
|
+
"Strictly follow the Angular Style Guide.",
|
|
48
|
+
"Use Dependency Injection patterns."
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
'frontend-svelte': {
|
|
52
|
+
label: '🎨 Frontend: SvelteKit',
|
|
53
|
+
rules: [
|
|
54
|
+
"Use Svelte 5 Runes syntax if available.",
|
|
55
|
+
"Leverage SvelteKit's load functions for server-side data.",
|
|
56
|
+
"Keep stores simple and derived."
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// --- BACKEND ---
|
|
61
|
+
'backend-node': {
|
|
62
|
+
label: '⚙️ Backend: Node.js (Express)',
|
|
63
|
+
rules: [
|
|
64
|
+
"Prefer Async/Await over raw Promises.",
|
|
65
|
+
"Follow Error Handling best practices (don't ignore errors).",
|
|
66
|
+
"Use Environment Variables for configuration.",
|
|
67
|
+
"Adhere to RESTful API standards."
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
'backend-nest': {
|
|
71
|
+
label: '⚙️ Backend: NestJS',
|
|
72
|
+
rules: [
|
|
73
|
+
"Use Dependency Injection strictly.",
|
|
74
|
+
"Follow the module structure.",
|
|
75
|
+
"Use DTOs with ValidationPipe for all inputs.",
|
|
76
|
+
"Prefer TypeORM or Prisma for database interaction."
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
'backend-python-fastapi': {
|
|
80
|
+
label: '⚙️ Backend: Python (FastAPI)',
|
|
81
|
+
rules: [
|
|
82
|
+
"Use Pydantic models for data validation.",
|
|
83
|
+
"Use Type Hints for function arguments and return values.",
|
|
84
|
+
"Implement async/await for I/O bound operations.",
|
|
85
|
+
"Follow PEP 8 style guidelines."
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
'backend-python-django': {
|
|
89
|
+
label: '⚙️ Backend: Python (Django)',
|
|
90
|
+
rules: [
|
|
91
|
+
"Use Class-Based Views (CBVs) where appropriate.",
|
|
92
|
+
"Follow the 'Fat Models, Thin Views' philosophy.",
|
|
93
|
+
"Use Django ORM optimizations (select_related, prefetch_related).",
|
|
94
|
+
"Keep settings separated for dev/prod."
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
'backend-java-spring': {
|
|
98
|
+
label: '⚙️ Backend: Java (Spring Boot)',
|
|
99
|
+
rules: [
|
|
100
|
+
"Use constructor injection over @Autowired.",
|
|
101
|
+
"Follow Google Java Style Guide.",
|
|
102
|
+
"Use Lombok to reduce boilerplate code.",
|
|
103
|
+
"Handle exceptions with @ControllerAdvice."
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
'backend-csharp': {
|
|
107
|
+
label: '⚙️ Backend: C# (.NET Core)',
|
|
108
|
+
rules: [
|
|
109
|
+
"Follow Microsoft's C# Coding Conventions.",
|
|
110
|
+
"Use Async/Await all the way down.",
|
|
111
|
+
"Prefer LINQ for collection manipulation.",
|
|
112
|
+
"Use Dependency Injection via IServiceCollection."
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
'backend-go': {
|
|
116
|
+
label: '⚙️ Backend: Go (Golang)',
|
|
117
|
+
rules: [
|
|
118
|
+
"Handle errors explicitly (if err != nil).",
|
|
119
|
+
"Follow strict formatting (gofmt).",
|
|
120
|
+
"Prefer standard library over external dependencies when possible.",
|
|
121
|
+
"Use context for cancellation and timeouts."
|
|
122
|
+
]
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// --- MOBILE ---
|
|
126
|
+
'mobile-react-native': {
|
|
127
|
+
label: '📱 Mobile: React Native',
|
|
128
|
+
rules: [
|
|
129
|
+
"Use Functional Components and Hooks.",
|
|
130
|
+
"Avoid bridge passing heavy data.",
|
|
131
|
+
"Optimize lists with FlatList or FlashList.",
|
|
132
|
+
"Style using StyleSheet objects or styled-components."
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
'mobile-flutter': {
|
|
136
|
+
label: '📱 Mobile: Flutter',
|
|
137
|
+
rules: [
|
|
138
|
+
"Use const constructors whenever possible.",
|
|
139
|
+
"Prefer Composition over Inheritance.",
|
|
140
|
+
"Manage state with Riverpod or BLoC.",
|
|
141
|
+
"Follow Effective Dart guidelines."
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
'mobile-ios': {
|
|
145
|
+
label: '📱 Mobile: iOS (SwiftUI)',
|
|
146
|
+
rules: [
|
|
147
|
+
"Use MVVM pattern.",
|
|
148
|
+
"Prefer Structs over Classes for data models.",
|
|
149
|
+
"Use strict concurrency checking.",
|
|
150
|
+
"Follow Apple's Human Interface Guidelines."
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
'mobile-android': {
|
|
154
|
+
label: '📱 Mobile: Android (Kotlin Compose)',
|
|
155
|
+
rules: [
|
|
156
|
+
"Use Jetpack Compose for UI.",
|
|
157
|
+
"Follow Material Design 3 guidelines.",
|
|
158
|
+
"Use Coroutines and Flow for async work.",
|
|
159
|
+
"Implement Hilt for Dependency Injection."
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
// --- DATA & AI ---
|
|
164
|
+
'data-python': {
|
|
165
|
+
label: '📊 Data Science: Python',
|
|
166
|
+
rules: [
|
|
167
|
+
"Use Pandas vectorization over loops.",
|
|
168
|
+
"Document notebooks with Markdown cells explaining logic.",
|
|
169
|
+
"Use Type Hints even in scripts.",
|
|
170
|
+
"Prefer Polars for large datasets if possible."
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// --- INFRASTRUCTURE ---
|
|
175
|
+
'infra-terraform': {
|
|
176
|
+
label: '☁️ Infra: Terraform',
|
|
177
|
+
rules: [
|
|
178
|
+
"Use modules for reusable resources.",
|
|
179
|
+
"Keep state remote and locked.",
|
|
180
|
+
"Format code with `terraform fmt`.",
|
|
181
|
+
"Avoid hardcoding values; use variables."
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
module.exports = { STACK_PROFILES };
|
package/src/lib/schema.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const { z } = require('zod');
|
|
2
|
-
|
|
3
|
-
const AgentSchema = z.object({
|
|
4
|
-
name: z.string().min(1, "Nome é obrigatório"),
|
|
5
|
-
role: z.string().min(1, "Papel (Role) é obrigatório"),
|
|
6
|
-
emoji: z.string().optional().default('🤖'),
|
|
7
|
-
systemPrompt: z.string().min(10, "System Prompt deve ter pelo menos 10 caracteres"),
|
|
8
|
-
rules: z.array(z.string()).optional().default([]),
|
|
9
|
-
tools: z.array(z.string()).optional().default([]),
|
|
10
|
-
description: z.string().optional()
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
module.exports = { AgentSchema };
|
|
1
|
+
const { z } = require('zod');
|
|
2
|
+
|
|
3
|
+
const AgentSchema = z.object({
|
|
4
|
+
name: z.string().min(1, "Nome é obrigatório"),
|
|
5
|
+
role: z.string().min(1, "Papel (Role) é obrigatório"),
|
|
6
|
+
emoji: z.string().optional().default('🤖'),
|
|
7
|
+
systemPrompt: z.string().min(10, "System Prompt deve ter pelo menos 10 caracteres"),
|
|
8
|
+
rules: z.array(z.string()).optional().default([]),
|
|
9
|
+
tools: z.array(z.string()).optional().default([]),
|
|
10
|
+
description: z.string().optional()
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
module.exports = { AgentSchema };
|
package/src/lib/transformers.js
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
|
+
const { TRANSLATIONS } = require('./messages');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the language rule based on the locale
|
|
5
|
+
* @param {string} locale - 'en', 'pt-br', 'es', etc.
|
|
6
|
+
*/
|
|
7
|
+
function getLanguageRule(locale = 'en') {
|
|
8
|
+
const normalized = locale.toLowerCase().replace('-', '_');
|
|
9
|
+
|
|
10
|
+
// Mapping locale slug to property key in messages
|
|
11
|
+
const keyMap = {
|
|
12
|
+
'en': 'EN',
|
|
13
|
+
'pt_br': 'PT_BR',
|
|
14
|
+
'es': 'ES'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const ruleKey = keyMap[normalized] || 'EN';
|
|
18
|
+
|
|
19
|
+
// Get dictionary for the target locale or fallback to EN
|
|
20
|
+
const dict = TRANSLATIONS[normalized] || TRANSLATIONS['en'];
|
|
21
|
+
|
|
22
|
+
return dict.LANGUAGE_RULES[ruleKey];
|
|
23
|
+
}
|
|
24
|
+
|
|
1
25
|
/**
|
|
2
26
|
* Converte definição do agente para TOML do Gemini CLI
|
|
3
27
|
*/
|
|
4
|
-
function toGeminiTOML(agent) {
|
|
28
|
+
function toGeminiTOML(agent, options = {}) {
|
|
29
|
+
const languageRule = getLanguageRule(options.locale);
|
|
5
30
|
// Escapa aspas duplas na descrição
|
|
6
31
|
const description = (agent.description || agent.role).replace(/"/g, '\\"');
|
|
7
32
|
|
|
@@ -15,25 +40,27 @@ function toGeminiTOML(agent) {
|
|
|
15
40
|
'\n'
|
|
16
41
|
];
|
|
17
42
|
|
|
18
|
-
|
|
43
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
44
|
+
|
|
45
|
+
if (allRules.length > 0) {
|
|
19
46
|
parts.push(`# Rules & Guidelines`);
|
|
20
|
-
|
|
47
|
+
allRules.forEach(rule => parts.push(`- ${rule}`));
|
|
21
48
|
parts.push('\n');
|
|
22
49
|
}
|
|
23
50
|
|
|
24
51
|
const fullPrompt = parts.join('\n');
|
|
25
52
|
|
|
26
53
|
// Escapa aspas triplas para o bloco multilinha TOML
|
|
27
|
-
const escapedPrompt = fullPrompt.replace(/"""/g, '\\"\\\"
|
|
54
|
+
const escapedPrompt = fullPrompt.replace(/"""/g, '\\"\\\"\\\"');
|
|
28
55
|
|
|
29
56
|
// Monta o TOML final
|
|
30
57
|
let toml = `description = "${description}"\n`;
|
|
31
58
|
toml += `prompt = """\n${escapedPrompt}\n"""\n`;
|
|
32
59
|
|
|
33
60
|
// Mantém rules como array separado se a ferramenta suportar (Gemini CLI suporta)
|
|
34
|
-
if (
|
|
61
|
+
if (allRules.length > 0) {
|
|
35
62
|
toml += 'rules = [\n';
|
|
36
|
-
|
|
63
|
+
allRules.forEach(rule => {
|
|
37
64
|
const escaped = rule.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
38
65
|
toml += ` "${escaped}",\n`;
|
|
39
66
|
});
|
|
@@ -46,15 +73,18 @@ function toGeminiTOML(agent) {
|
|
|
46
73
|
/**
|
|
47
74
|
* Converte para configuração de Custom Mode do Roo Code / Cline (JSON)
|
|
48
75
|
*/
|
|
49
|
-
function toRooConfig(agent, slug) {
|
|
76
|
+
function toRooConfig(agent, slug, options = {}) {
|
|
77
|
+
const languageRule = getLanguageRule(options.locale);
|
|
50
78
|
const promptParts = [
|
|
51
79
|
`# ${agent.name} (${agent.role})`,
|
|
52
80
|
`\n${agent.systemPrompt.trim()}\n`
|
|
53
81
|
];
|
|
54
82
|
|
|
55
|
-
|
|
83
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
84
|
+
|
|
85
|
+
if (allRules.length > 0) {
|
|
56
86
|
promptParts.push(`## Rules & Guidelines`);
|
|
57
|
-
|
|
87
|
+
allRules.forEach(rule => promptParts.push(`- ${rule}`));
|
|
58
88
|
}
|
|
59
89
|
|
|
60
90
|
return {
|
|
@@ -68,7 +98,8 @@ function toRooConfig(agent, slug) {
|
|
|
68
98
|
/**
|
|
69
99
|
* Converte para Markdown do Kilo Code
|
|
70
100
|
*/
|
|
71
|
-
function toKiloMarkdown(agent) {
|
|
101
|
+
function toKiloMarkdown(agent, options = {}) {
|
|
102
|
+
const languageRule = getLanguageRule(options.locale);
|
|
72
103
|
const parts = [
|
|
73
104
|
`<!--- Kilo Code Agent Config --->`,
|
|
74
105
|
`# ${agent.name} ${agent.emoji}`,
|
|
@@ -78,9 +109,11 @@ function toKiloMarkdown(agent) {
|
|
|
78
109
|
'\n'
|
|
79
110
|
];
|
|
80
111
|
|
|
81
|
-
|
|
112
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
113
|
+
|
|
114
|
+
if (allRules.length > 0) {
|
|
82
115
|
parts.push(`## Constraints`);
|
|
83
|
-
|
|
116
|
+
allRules.forEach(rule => parts.push(`- ${rule}`));
|
|
84
117
|
}
|
|
85
118
|
|
|
86
119
|
return parts.join('\n');
|
|
@@ -89,7 +122,8 @@ function toKiloMarkdown(agent) {
|
|
|
89
122
|
/**
|
|
90
123
|
* Converte para Instruções do GitHub Copilot (.github/copilot-instructions.md)
|
|
91
124
|
*/
|
|
92
|
-
function toCopilotInstructions(agent) {
|
|
125
|
+
function toCopilotInstructions(agent, options = {}) {
|
|
126
|
+
const languageRule = getLanguageRule(options.locale);
|
|
93
127
|
const parts = [
|
|
94
128
|
`<!-- GitHub Copilot Instructions for ${agent.name} -->`,
|
|
95
129
|
`# Identity and Role`,
|
|
@@ -100,15 +134,16 @@ function toCopilotInstructions(agent) {
|
|
|
100
134
|
'\n'
|
|
101
135
|
];
|
|
102
136
|
|
|
103
|
-
|
|
137
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
138
|
+
|
|
139
|
+
if (allRules.length > 0) {
|
|
104
140
|
parts.push(`## Rules & Guidelines`);
|
|
105
|
-
|
|
141
|
+
allRules.forEach(rule => parts.push(`- ${rule}`));
|
|
106
142
|
}
|
|
107
143
|
|
|
108
144
|
// Adiciona uma seção de estilo de resposta para garantir conformidade
|
|
109
145
|
parts.push(`\n## Response Style`);
|
|
110
146
|
parts.push(`- Be concise and objective.`);
|
|
111
|
-
parts.push(`- Use Portuguese (Brazil) unless told otherwise.`);
|
|
112
147
|
parts.push(`- Follow the project conventions defined in the workspace.`);
|
|
113
148
|
|
|
114
149
|
return parts.join('\n');
|
|
@@ -118,7 +153,8 @@ function toCopilotInstructions(agent) {
|
|
|
118
153
|
* Converte para Cursor Rules (.mdc)
|
|
119
154
|
* Inclui Frontmatter para Contexto
|
|
120
155
|
*/
|
|
121
|
-
function toCursorMDC(agent) {
|
|
156
|
+
function toCursorMDC(agent, options = {}) {
|
|
157
|
+
const languageRule = getLanguageRule(options.locale);
|
|
122
158
|
// Tenta inferir globs baseados no papel do agente
|
|
123
159
|
let globs = "*";
|
|
124
160
|
const roleLower = agent.slug.toLowerCase();
|
|
@@ -127,7 +163,9 @@ function toCursorMDC(agent) {
|
|
|
127
163
|
if (roleLower.includes('css') || roleLower.includes('style')) globs = "*.css, *.scss, *.tailwind";
|
|
128
164
|
if (roleLower.includes('sql') || roleLower.includes('db')) globs = "*.sql, *.prisma, *.schema";
|
|
129
165
|
|
|
130
|
-
|
|
166
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
167
|
+
|
|
168
|
+
return `---
|
|
131
169
|
description: ${agent.description || agent.role}
|
|
132
170
|
globs: ${globs}
|
|
133
171
|
---
|
|
@@ -138,14 +176,17 @@ Role: ${agent.role}
|
|
|
138
176
|
## Instructions
|
|
139
177
|
${agent.systemPrompt.trim()}
|
|
140
178
|
|
|
141
|
-
${
|
|
179
|
+
${allRules.length > 0 ? '## Rules\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
142
180
|
`;
|
|
143
181
|
}
|
|
144
182
|
|
|
145
183
|
/**
|
|
146
184
|
* Converte para Windsurf (.windsurfrules)
|
|
147
185
|
*/
|
|
148
|
-
function toWindsurfRules(agent) {
|
|
186
|
+
function toWindsurfRules(agent, options = {}) {
|
|
187
|
+
const languageRule = getLanguageRule(options.locale);
|
|
188
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
189
|
+
|
|
149
190
|
return `# ${agent.name} ${agent.emoji} Rules
|
|
150
191
|
|
|
151
192
|
Role: ${agent.role}
|
|
@@ -153,28 +194,34 @@ Role: ${agent.role}
|
|
|
153
194
|
## Core Logic
|
|
154
195
|
${agent.systemPrompt.trim()}
|
|
155
196
|
|
|
156
|
-
${
|
|
197
|
+
${allRules.length > 0 ? '## Guidelines\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
157
198
|
`;
|
|
158
199
|
}
|
|
159
200
|
|
|
160
201
|
/**
|
|
161
202
|
* Converte para System Prompt Puro (OpenAI/Claude/Web)
|
|
162
203
|
*/
|
|
163
|
-
function toPlainSystemPrompt(agent) {
|
|
204
|
+
function toPlainSystemPrompt(agent, options = {}) {
|
|
205
|
+
const languageRule = getLanguageRule(options.locale);
|
|
206
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
207
|
+
|
|
164
208
|
return `You are ${agent.name} ${agent.emoji}
|
|
165
209
|
Role: ${agent.role}
|
|
166
210
|
|
|
167
211
|
[SYSTEM INSTRUCTIONS]
|
|
168
212
|
${agent.systemPrompt.trim()}
|
|
169
213
|
|
|
170
|
-
${
|
|
214
|
+
${allRules.length > 0 ? '[GUIDELINES]\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
171
215
|
`;
|
|
172
216
|
}
|
|
173
217
|
|
|
174
218
|
/**
|
|
175
219
|
* Converte para Trae Instructions
|
|
176
220
|
*/
|
|
177
|
-
function toTraeRules(agent) {
|
|
221
|
+
function toTraeRules(agent, options = {}) {
|
|
222
|
+
const languageRule = getLanguageRule(options.locale);
|
|
223
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
224
|
+
|
|
178
225
|
return `<!-- Trae Workspace Rules -->
|
|
179
226
|
# ${agent.name} ${agent.emoji}
|
|
180
227
|
|
|
@@ -183,7 +230,7 @@ function toTraeRules(agent) {
|
|
|
183
230
|
## Context & Instructions
|
|
184
231
|
${agent.systemPrompt.trim()}
|
|
185
232
|
|
|
186
|
-
${
|
|
233
|
+
${allRules.length > 0 ? '## Constraints\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
187
234
|
`;
|
|
188
235
|
}
|
|
189
236
|
|
|
@@ -196,4 +243,4 @@ module.exports = {
|
|
|
196
243
|
toWindsurfRules,
|
|
197
244
|
toPlainSystemPrompt,
|
|
198
245
|
toTraeRules
|
|
199
|
-
};
|
|
246
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const readline = require('readline');
|
|
4
|
+
|
|
5
|
+
const docsDir = path.join(process.cwd(), 'docs');
|
|
6
|
+
const archiveDir = path.join(docsDir, 'archive');
|
|
7
|
+
|
|
8
|
+
// Files to archive (Ephemeral context)
|
|
9
|
+
const filesToArchive = ['spec.md', 'plan.md', 'audit_report.md'];
|
|
10
|
+
|
|
11
|
+
// Files to keep (Long-term context)
|
|
12
|
+
// - guidelines.md (Laws)
|
|
13
|
+
// - context.md (Project Reality)
|
|
14
|
+
// - work_log.md (History)
|
|
15
|
+
|
|
16
|
+
const rl = readline.createInterface({
|
|
17
|
+
input: process.stdin,
|
|
18
|
+
output: process.stdout
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
console.log('📦 SDD SESSION ARCHIVER');
|
|
22
|
+
console.log('This will move current Spec, Plan, and Audit reports to docs/archive/.');
|
|
23
|
+
console.log('Your Work Log and Context will remain untouched.\n');
|
|
24
|
+
|
|
25
|
+
// Check if there is anything to archive
|
|
26
|
+
const existingFiles = filesToArchive.filter(f => fs.existsSync(path.join(docsDir, f)));
|
|
27
|
+
|
|
28
|
+
if (existingFiles.length === 0) {
|
|
29
|
+
console.log('❌ No active session files found (spec.md, plan.md, etc). Nothing to archive.');
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
rl.question('Enter a name for this feature/session (e.g., "auth-system"): ', (name) => {
|
|
34
|
+
const safeName = (name || 'untitled').replace(/[^a-z0-9-_]/gi, '-').toLowerCase();
|
|
35
|
+
const timestamp = new Date().toISOString().split('T')[0];
|
|
36
|
+
const folderName = `${timestamp}_${safeName}`;
|
|
37
|
+
const targetDir = path.join(archiveDir, folderName);
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(targetDir)) {
|
|
40
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(`\nMoving files to: docs/archive/${folderName}/
|
|
44
|
+
`);
|
|
45
|
+
|
|
46
|
+
existingFiles.forEach(file => {
|
|
47
|
+
const srcPath = path.join(docsDir, file);
|
|
48
|
+
const destPath = path.join(targetDir, file);
|
|
49
|
+
fs.renameSync(srcPath, destPath);
|
|
50
|
+
console.log(`✔ Archived: ${file}`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log('\n✅ Session archived successfully!');
|
|
54
|
+
console.log('You are ready to start a new feature with /dev.spec');
|
|
55
|
+
rl.close();
|
|
56
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const docsDir = path.join(process.cwd(), 'docs');
|
|
5
|
+
|
|
6
|
+
console.log('⚠️ WARNING: This will wipe all documentation (Spec, Plan, Context).');
|
|
7
|
+
console.log('Your source code (src/) will NOT be touched.');
|
|
8
|
+
console.log('Are you sure? (Run with --force to execute)');
|
|
9
|
+
|
|
10
|
+
if (process.argv.includes('--force')) {
|
|
11
|
+
['spec.md', 'plan.md', 'context.md', 'audit_report.md'].forEach(file => {
|
|
12
|
+
const p = path.join(docsDir, file);
|
|
13
|
+
if (fs.existsSync(p)) {
|
|
14
|
+
fs.unlinkSync(p);
|
|
15
|
+
console.log(`Deleted: docs/${file}`);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
console.log('✅ Wipe complete. You can start fresh with /dev.explore');
|
|
19
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// Tenta carregar picocolors se estiver disponível no projeto do usuário, senão usa fallback
|
|
5
|
+
let pc = {
|
|
6
|
+
green: s => s,
|
|
7
|
+
blue: s => s,
|
|
8
|
+
yellow: s => s,
|
|
9
|
+
red: s => s,
|
|
10
|
+
bold: s => s,
|
|
11
|
+
bgBlue: s => s
|
|
12
|
+
};
|
|
13
|
+
try { pc = require('picocolors'); } catch (e) {}
|
|
14
|
+
|
|
15
|
+
const docsDir = path.join(process.cwd(), 'docs');
|
|
16
|
+
|
|
17
|
+
function checkFile(name) {
|
|
18
|
+
const p = path.join(docsDir, name);
|
|
19
|
+
if (fs.existsSync(p)) {
|
|
20
|
+
const stats = fs.statSync(p);
|
|
21
|
+
return { exists: true, size: stats.size, mtime: stats.mtime };
|
|
22
|
+
}
|
|
23
|
+
return { exists: false };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.clear();
|
|
27
|
+
console.log(pc.bgBlue(pc.bold(' 📊 SDD PROJECT STATUS ')));
|
|
28
|
+
console.log('');
|
|
29
|
+
|
|
30
|
+
// 1. Spec Status
|
|
31
|
+
const spec = checkFile('spec.md');
|
|
32
|
+
if (spec.exists && spec.size > 100) {
|
|
33
|
+
console.log(`${pc.green('✔ Spec Defined')} (Last update: ${spec.mtime.toLocaleString()})`);
|
|
34
|
+
} else {
|
|
35
|
+
console.log(`${pc.red('✖ Spec Missing')} (Run /dev.spec)`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. Plan Status
|
|
39
|
+
const plan = checkFile('plan.md');
|
|
40
|
+
if (plan.exists && plan.size > 100) {
|
|
41
|
+
console.log(`${pc.green('✔ Plan Active')} (Last update: ${plan.mtime.toLocaleString()})`);
|
|
42
|
+
|
|
43
|
+
// Tenta ler progresso simples
|
|
44
|
+
try {
|
|
45
|
+
const content = fs.readFileSync(path.join(docsDir, 'plan.md'), 'utf-8');
|
|
46
|
+
const total = (content.match(/- \[ \]/g) || []).length + (content.match(/- \[x\]/g) || []).length;
|
|
47
|
+
const done = (content.match(/- \[x\]/g) || []).length;
|
|
48
|
+
if (total > 0) {
|
|
49
|
+
const percent = Math.round((done / total) * 100);
|
|
50
|
+
console.log(` Progress: [${'#'.repeat(Math.floor(percent/10))}${'-'.repeat(10 - Math.floor(percent/10))}] ${percent}% (${done}/${total} tasks)`);
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {}
|
|
53
|
+
} else {
|
|
54
|
+
console.log(`${pc.yellow('⚠ Plan Missing')} (Run /dev.plan)`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log('Use /dev.build to continue work.');
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title:
|
|
3
|
+
version:
|
|
4
|
+
status:
|
|
5
|
+
last_updated:
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
## 1. Overview
|
|
11
|
+
|
|
12
|
+
## 2. Business Objectives
|
|
13
|
+
|
|
14
|
+
## 3. Actors and Personas
|
|
15
|
+
|
|
16
|
+
## 4. Modules and Features Structure
|
|
17
|
+
|
|
18
|
+
## 5. User Journey (Flow)
|
|
19
|
+
|
|
20
|
+
## 6. Business Rules
|
|
21
|
+
|
|
22
|
+
## 7. External Integrations
|
|
23
|
+
|
|
24
|
+
## 8. Non-Functional Requirements & Constraints
|
|
25
|
+
|
|
26
|
+
## 9. Data Definitions
|
|
27
|
+
|
|
28
|
+
## 10. Project Principles (Constitution)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Requirements and Architecture Specification
|
|
3
|
+
scope:
|
|
4
|
+
last_updated:
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Requirements and Stack Catalog
|
|
8
|
+
|
|
9
|
+
## 1. Tech Stack and Standards (Tech Constraints)
|
|
10
|
+
|
|
11
|
+
## 2. Functional Requirements (FR)
|
|
12
|
+
|
|
13
|
+
## 3. Non-Functional Requirements (NFR)
|
|
14
|
+
|
|
15
|
+
## 4. Data Model (Schema Draft)
|