sdd-toolkit 1.1.0 → 1.6.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 +139 -133
- package/README.pt.md +135 -0
- package/definitions/{dev.coder.yaml → coder.yaml} +71 -59
- package/definitions/feature.yaml +74 -0
- package/definitions/log.yaml +61 -0
- package/definitions/project.yaml +108 -0
- package/definitions/requirements.yaml +71 -0
- package/definitions/review.yaml +88 -0
- package/definitions/sdd.yaml +30 -0
- package/package.json +2 -1
- package/src/commands/view.js +18 -0
- package/src/index.js +240 -112
- package/src/lib/agents.js +21 -21
- package/src/lib/dashboard.js +188 -0
- package/src/lib/docs.js +69 -104
- package/src/lib/i18n.js +65 -0
- package/src/lib/messages.js +234 -0
- package/src/lib/profiles.js +4 -4
- package/src/lib/transformers.js +166 -33
- 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
- package/definitions/dev.auditor.yaml +0 -54
- package/definitions/dev.feature.yaml +0 -108
- package/definitions/dev.log.yaml +0 -51
- package/definitions/dev.milestone.yaml +0 -62
- package/definitions/dev.ops.yaml +0 -39
- package/definitions/dev.project.yaml +0 -91
- package/definitions/dev.requirements.yaml +0 -76
- package/definitions/dev.review.yaml +0 -72
- package/definitions/dev.tasks.yaml +0 -70
package/src/lib/transformers.js
CHANGED
|
@@ -1,9 +1,34 @@
|
|
|
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
|
-
const description = (agent.description || agent.role).replace(/"/g, '
|
|
31
|
+
const description = (agent.description || agent.role).replace(/"/g, '\"');
|
|
7
32
|
|
|
8
33
|
// Constrói o prompt completo
|
|
9
34
|
const parts = [
|
|
@@ -15,26 +40,28 @@ 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
|
-
|
|
37
|
-
const escaped = rule.replace(/\\/g, '\\\\').replace(/"/g, '
|
|
63
|
+
allRules.forEach(rule => {
|
|
64
|
+
const escaped = rule.replace(/\\/g, '\\\\').replace(/"/g, '\"');
|
|
38
65
|
toml += ` "${escaped}",\n`;
|
|
39
66
|
});
|
|
40
67
|
toml += ']\n';
|
|
@@ -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,18 @@ 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
|
-
* Converte para Windsurf (.
|
|
184
|
+
* Converte para Windsurf Workflow (.windsurf/workflows/*.md)
|
|
185
|
+
* Cascade reconhece esses arquivos como comandos de workflow
|
|
147
186
|
*/
|
|
148
|
-
function toWindsurfRules(agent) {
|
|
187
|
+
function toWindsurfRules(agent, options = {}) {
|
|
188
|
+
const languageRule = getLanguageRule(options.locale);
|
|
189
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
190
|
+
|
|
149
191
|
return `# ${agent.name} ${agent.emoji} Rules
|
|
150
192
|
|
|
151
193
|
Role: ${agent.role}
|
|
@@ -153,28 +195,117 @@ Role: ${agent.role}
|
|
|
153
195
|
## Core Logic
|
|
154
196
|
${agent.systemPrompt.trim()}
|
|
155
197
|
|
|
156
|
-
${
|
|
198
|
+
${allRules.length > 0 ? '## Guidelines\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
199
|
+
`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Converte para Claude Code Command (.claude/commands/openspec/*.md)
|
|
204
|
+
*/
|
|
205
|
+
function toClaudeCommand(agent, options = {}) {
|
|
206
|
+
const languageRule = getLanguageRule(options.locale);
|
|
207
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
208
|
+
|
|
209
|
+
return `---
|
|
210
|
+
name: OpenSpec: ${agent.name}
|
|
211
|
+
description: ${agent.description || agent.role}
|
|
212
|
+
category: OpenSpec
|
|
213
|
+
---
|
|
214
|
+
# ${agent.name} ${agent.emoji}
|
|
215
|
+
|
|
216
|
+
Role: ${agent.role}
|
|
217
|
+
|
|
218
|
+
## Instructions
|
|
219
|
+
${agent.systemPrompt.trim()}
|
|
220
|
+
|
|
221
|
+
${allRules.length > 0 ? '## Rules\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
157
222
|
`;
|
|
158
223
|
}
|
|
159
224
|
|
|
160
225
|
/**
|
|
161
226
|
* Converte para System Prompt Puro (OpenAI/Claude/Web)
|
|
162
227
|
*/
|
|
163
|
-
function toPlainSystemPrompt(agent) {
|
|
228
|
+
function toPlainSystemPrompt(agent, options = {}) {
|
|
229
|
+
const languageRule = getLanguageRule(options.locale);
|
|
230
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
231
|
+
|
|
164
232
|
return `You are ${agent.name} ${agent.emoji}
|
|
165
233
|
Role: ${agent.role}
|
|
166
234
|
|
|
167
235
|
[SYSTEM INSTRUCTIONS]
|
|
168
236
|
${agent.systemPrompt.trim()}
|
|
169
237
|
|
|
170
|
-
${
|
|
238
|
+
${allRules.length > 0 ? '[GUIDELINES]\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
171
239
|
`;
|
|
172
240
|
}
|
|
173
241
|
|
|
174
242
|
/**
|
|
175
243
|
* Converte para Trae Instructions
|
|
176
244
|
*/
|
|
177
|
-
function toTraeRules(agent) {
|
|
245
|
+
function toTraeRules(agent, options = {}) {
|
|
246
|
+
const languageRule = getLanguageRule(options.locale);
|
|
247
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
248
|
+
|
|
249
|
+
return `<!-- Trae Workspace Rules -->
|
|
250
|
+
# ${agent.name} ${agent.emoji}
|
|
251
|
+
|
|
252
|
+
**Role**: ${agent.role}
|
|
253
|
+
|
|
254
|
+
## Context & Instructions
|
|
255
|
+
${agent.systemPrompt.trim()}
|
|
256
|
+
|
|
257
|
+
${allRules.length > 0 ? '## Constraints\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
258
|
+
`;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Converte para OpenCode Agent (.opencode/agent/*.md)
|
|
263
|
+
*/
|
|
264
|
+
function toOpenCodeAgent(agent, options = {}) {
|
|
265
|
+
const languageRule = getLanguageRule(options.locale);
|
|
266
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
267
|
+
|
|
268
|
+
// Configurar permissões baseado no tipo de agente
|
|
269
|
+
const isReadOnly = agent.slug.includes('review') || agent.slug.includes('audit') || agent.name.includes('Architect') || agent.role.includes('QA') || agent.role.includes('Review');
|
|
270
|
+
const tools = {
|
|
271
|
+
write: !isReadOnly,
|
|
272
|
+
edit: !isReadOnly,
|
|
273
|
+
bash: !isReadOnly
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const frontmatter = {
|
|
277
|
+
description: agent.description || agent.role,
|
|
278
|
+
mode: 'subagent',
|
|
279
|
+
temperature: 0.3,
|
|
280
|
+
tools
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const frontmatterStr = Object.entries(frontmatter)
|
|
284
|
+
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
|
|
285
|
+
.join('\n');
|
|
286
|
+
|
|
287
|
+
return `---
|
|
288
|
+
${frontmatterStr}
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
# ${agent.name} ${agent.emoji}
|
|
292
|
+
|
|
293
|
+
**Role**: ${agent.role}
|
|
294
|
+
|
|
295
|
+
${agent.systemPrompt.trim()}
|
|
296
|
+
|
|
297
|
+
## Rules
|
|
298
|
+
${allRules.map(rule => `- ${rule}`).join('\n')}
|
|
299
|
+
`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Converte para Trae Instructions
|
|
304
|
+
*/
|
|
305
|
+
function toTraeRules(agent, options = {}) {
|
|
306
|
+
const languageRule = getLanguageRule(options.locale);
|
|
307
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
308
|
+
|
|
178
309
|
return `<!-- Trae Workspace Rules -->
|
|
179
310
|
# ${agent.name} ${agent.emoji}
|
|
180
311
|
|
|
@@ -183,17 +314,19 @@ function toTraeRules(agent) {
|
|
|
183
314
|
## Context & Instructions
|
|
184
315
|
${agent.systemPrompt.trim()}
|
|
185
316
|
|
|
186
|
-
${
|
|
317
|
+
${allRules.length > 0 ? '## Constraints\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
187
318
|
`;
|
|
188
319
|
}
|
|
189
320
|
|
|
190
|
-
module.exports = {
|
|
191
|
-
toGeminiTOML,
|
|
192
|
-
toRooConfig,
|
|
193
|
-
toKiloMarkdown,
|
|
321
|
+
module.exports = {
|
|
322
|
+
toGeminiTOML,
|
|
323
|
+
toRooConfig,
|
|
324
|
+
toKiloMarkdown,
|
|
194
325
|
toCopilotInstructions,
|
|
195
326
|
toCursorMDC,
|
|
196
327
|
toWindsurfRules,
|
|
328
|
+
toClaudeCommand,
|
|
197
329
|
toPlainSystemPrompt,
|
|
198
|
-
toTraeRules
|
|
330
|
+
toTraeRules,
|
|
331
|
+
toOpenCodeAgent
|
|
199
332
|
};
|
|
@@ -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(), '.sdd-toolkit');
|
|
6
|
+
const archiveDir = path.join(docsDir, 'archive');
|
|
7
|
+
|
|
8
|
+
// Files to archive (Ephemeral context)
|
|
9
|
+
const filesToArchive = ['project.md', 'task.md', 'audit_report.md', 'requirements.md', 'milestones.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 .sdd-toolkit/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: .sdd-toolkit/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 /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(), '.sdd-toolkit');
|
|
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
|
+
['project.md', 'task.md', 'requirements.md', 'milestones.md', 'guidelines.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: .sdd-toolkit/${file}`);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
console.log('✅ Wipe complete. You can start fresh with /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(), '.sdd-toolkit');
|
|
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('project.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 /project)`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. Plan Status
|
|
39
|
+
const plan = checkFile('task.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, 'task.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 /tasks)`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log('Use /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)
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
name: Auditor
|
|
2
|
-
role: Blueprint Validator & Consistency Checker
|
|
3
|
-
emoji: 🕵️
|
|
4
|
-
systemPrompt: |
|
|
5
|
-
# SYSTEM ROLE & IDENTITY
|
|
6
|
-
You are the **Lead Auditor**.
|
|
7
|
-
Your role is to **prevent failure** by detecting gaps in planning BEFORE code is written.
|
|
8
|
-
You do not execute code. You analyze logical consistency between documents.
|
|
9
|
-
|
|
10
|
-
# INPUT CONTEXT
|
|
11
|
-
1. **Mandatory Reading:**
|
|
12
|
-
- `docs/requirements.md` (The Contract).
|
|
13
|
-
- `docs/task.md` (The Plan).
|
|
14
|
-
- `docs/milestones.md` (The Strategy).
|
|
15
|
-
|
|
16
|
-
# WORKFLOW (AUDIT PROCESS)
|
|
17
|
-
Execute a non-destructive analysis to verify if the Plan covers the Contract.
|
|
18
|
-
|
|
19
|
-
## 1. Coverage Analysis
|
|
20
|
-
- Map every Requirement (FR-XX, BR-XX) to at least one Task (M1-TXX).
|
|
21
|
-
- **FLAG** any orphaned requirement (exists in docs but no task to implement it).
|
|
22
|
-
|
|
23
|
-
## 2. Ambiguity Detection
|
|
24
|
-
- Scan `task.md` for vague terms: "Make it work", "Fix bugs", "improve".
|
|
25
|
-
- **Task Definition:** Every task MUST have a clear "DoD" (Definition of Done) or "Acceptance Criteria".
|
|
26
|
-
|
|
27
|
-
## 3. Conflict Check
|
|
28
|
-
- Check if `task.md` contradicts `requirements.md` (e.g., Req says "Postgres", Task says "Install Mongo").
|
|
29
|
-
|
|
30
|
-
# OUTPUT STRUCTURE (docs/logs/audit_report.md)
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
**Audit Date:** [YYYY-MM-DD HH:MM]
|
|
34
|
-
**Status:** [PASS / WARN / FAIL]
|
|
35
|
-
|
|
36
|
-
## 1. Coverage Matrix
|
|
37
|
-
- [x] FR-01 -> M1-T02
|
|
38
|
-
- [ ] FR-02 -> **MISSING IN TASKS** (Critical)
|
|
39
|
-
|
|
40
|
-
## 2. Issues Found
|
|
41
|
-
- **Critical:** Requirement [FR-02] has no implementation task.
|
|
42
|
-
- **Warning:** Task [M1-T04] mentions "Optimize" without specific metric.
|
|
43
|
-
|
|
44
|
-
## 3. Recommendation
|
|
45
|
-
- [ ] Generate detailed tasks for FR-02.
|
|
46
|
-
- [ ] Proceed to code (only if Status is PASS).
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
# INSTRUCTION
|
|
50
|
-
Read requirements and tasks. Generate the `audit_report.md`.
|
|
51
|
-
rules:
|
|
52
|
-
- "**STRICTNESS:** If a Business Rule (BR) is ignored, Fail the audit."
|
|
53
|
-
- "**NO ASSUMPTIONS:** If a task suggests a library not in requirements, Flag it."
|
|
54
|
-
- "Language Adaptability: Respond in English by default. If the user speaks in another language, mirror their language."
|