sdd-toolkit 1.1.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 +59 -37
- package/definitions/dev.auditor.yaml +61 -49
- package/definitions/dev.coder.yaml +78 -59
- 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 +2 -1
- package/src/index.js +284 -207
- package/src/lib/agents.js +21 -21
- package/src/lib/docs.js +68 -104
- package/src/lib/i18n.js +65 -0
- package/src/lib/messages.js +186 -0
- package/src/lib/profiles.js +4 -4
- package/src/lib/transformers.js +246 -199
- 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/src/lib/transformers.js
CHANGED
|
@@ -1,199 +1,246 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
agent.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
agent.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
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
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Converte definição do agente para TOML do Gemini CLI
|
|
27
|
+
*/
|
|
28
|
+
function toGeminiTOML(agent, options = {}) {
|
|
29
|
+
const languageRule = getLanguageRule(options.locale);
|
|
30
|
+
// Escapa aspas duplas na descrição
|
|
31
|
+
const description = (agent.description || agent.role).replace(/"/g, '\\"');
|
|
32
|
+
|
|
33
|
+
// Constrói o prompt completo
|
|
34
|
+
const parts = [
|
|
35
|
+
`# Identity`,
|
|
36
|
+
`You are **${agent.name}** ${agent.emoji}`,
|
|
37
|
+
`Role: ${agent.role}\n`,
|
|
38
|
+
`# Core Instructions`,
|
|
39
|
+
agent.systemPrompt.trim(),
|
|
40
|
+
'\n'
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
44
|
+
|
|
45
|
+
if (allRules.length > 0) {
|
|
46
|
+
parts.push(`# Rules & Guidelines`);
|
|
47
|
+
allRules.forEach(rule => parts.push(`- ${rule}`));
|
|
48
|
+
parts.push('\n');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const fullPrompt = parts.join('\n');
|
|
52
|
+
|
|
53
|
+
// Escapa aspas triplas para o bloco multilinha TOML
|
|
54
|
+
const escapedPrompt = fullPrompt.replace(/"""/g, '\\"\\\"\\\"');
|
|
55
|
+
|
|
56
|
+
// Monta o TOML final
|
|
57
|
+
let toml = `description = "${description}"\n`;
|
|
58
|
+
toml += `prompt = """\n${escapedPrompt}\n"""\n`;
|
|
59
|
+
|
|
60
|
+
// Mantém rules como array separado se a ferramenta suportar (Gemini CLI suporta)
|
|
61
|
+
if (allRules.length > 0) {
|
|
62
|
+
toml += 'rules = [\n';
|
|
63
|
+
allRules.forEach(rule => {
|
|
64
|
+
const escaped = rule.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
65
|
+
toml += ` "${escaped}",\n`;
|
|
66
|
+
});
|
|
67
|
+
toml += ']\n';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return toml;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Converte para configuração de Custom Mode do Roo Code / Cline (JSON)
|
|
75
|
+
*/
|
|
76
|
+
function toRooConfig(agent, slug, options = {}) {
|
|
77
|
+
const languageRule = getLanguageRule(options.locale);
|
|
78
|
+
const promptParts = [
|
|
79
|
+
`# ${agent.name} (${agent.role})`,
|
|
80
|
+
`\n${agent.systemPrompt.trim()}\n`
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
84
|
+
|
|
85
|
+
if (allRules.length > 0) {
|
|
86
|
+
promptParts.push(`## Rules & Guidelines`);
|
|
87
|
+
allRules.forEach(rule => promptParts.push(`- ${rule}`));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
slug: slug,
|
|
92
|
+
name: `${agent.emoji} ${agent.name}`,
|
|
93
|
+
roleDefinition: promptParts.join('\n'),
|
|
94
|
+
groups: ["read", "edit", "browser", "command", "mcp"]
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Converte para Markdown do Kilo Code
|
|
100
|
+
*/
|
|
101
|
+
function toKiloMarkdown(agent, options = {}) {
|
|
102
|
+
const languageRule = getLanguageRule(options.locale);
|
|
103
|
+
const parts = [
|
|
104
|
+
`<!--- Kilo Code Agent Config --->`,
|
|
105
|
+
`# ${agent.name} ${agent.emoji}`,
|
|
106
|
+
`**Role**: ${agent.role}\n`,
|
|
107
|
+
`## Instructions`,
|
|
108
|
+
agent.systemPrompt.trim(),
|
|
109
|
+
'\n'
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
113
|
+
|
|
114
|
+
if (allRules.length > 0) {
|
|
115
|
+
parts.push(`## Constraints`);
|
|
116
|
+
allRules.forEach(rule => parts.push(`- ${rule}`));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return parts.join('\n');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Converte para Instruções do GitHub Copilot (.github/copilot-instructions.md)
|
|
124
|
+
*/
|
|
125
|
+
function toCopilotInstructions(agent, options = {}) {
|
|
126
|
+
const languageRule = getLanguageRule(options.locale);
|
|
127
|
+
const parts = [
|
|
128
|
+
`<!-- GitHub Copilot Instructions for ${agent.name} -->`,
|
|
129
|
+
`# Identity and Role`,
|
|
130
|
+
`You are **${agent.name}** ${agent.emoji}.`,
|
|
131
|
+
`**Role**: ${agent.role}`,
|
|
132
|
+
`\n## Core Instructions`,
|
|
133
|
+
agent.systemPrompt.trim(),
|
|
134
|
+
'\n'
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
138
|
+
|
|
139
|
+
if (allRules.length > 0) {
|
|
140
|
+
parts.push(`## Rules & Guidelines`);
|
|
141
|
+
allRules.forEach(rule => parts.push(`- ${rule}`));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Adiciona uma seção de estilo de resposta para garantir conformidade
|
|
145
|
+
parts.push(`\n## Response Style`);
|
|
146
|
+
parts.push(`- Be concise and objective.`);
|
|
147
|
+
parts.push(`- Follow the project conventions defined in the workspace.`);
|
|
148
|
+
|
|
149
|
+
return parts.join('\n');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Converte para Cursor Rules (.mdc)
|
|
154
|
+
* Inclui Frontmatter para Contexto
|
|
155
|
+
*/
|
|
156
|
+
function toCursorMDC(agent, options = {}) {
|
|
157
|
+
const languageRule = getLanguageRule(options.locale);
|
|
158
|
+
// Tenta inferir globs baseados no papel do agente
|
|
159
|
+
let globs = "*";
|
|
160
|
+
const roleLower = agent.slug.toLowerCase();
|
|
161
|
+
|
|
162
|
+
if (roleLower.includes('test') || roleLower.includes('qa')) globs = "*.test.*, *.spec.*, **/tests/**";
|
|
163
|
+
if (roleLower.includes('css') || roleLower.includes('style')) globs = "*.css, *.scss, *.tailwind";
|
|
164
|
+
if (roleLower.includes('sql') || roleLower.includes('db')) globs = "*.sql, *.prisma, *.schema";
|
|
165
|
+
|
|
166
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
167
|
+
|
|
168
|
+
return `---
|
|
169
|
+
description: ${agent.description || agent.role}
|
|
170
|
+
globs: ${globs}
|
|
171
|
+
---
|
|
172
|
+
# ${agent.name} ${agent.emoji}
|
|
173
|
+
|
|
174
|
+
Role: ${agent.role}
|
|
175
|
+
|
|
176
|
+
## Instructions
|
|
177
|
+
${agent.systemPrompt.trim()}
|
|
178
|
+
|
|
179
|
+
${allRules.length > 0 ? '## Rules\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Converte para Windsurf (.windsurfrules)
|
|
185
|
+
*/
|
|
186
|
+
function toWindsurfRules(agent, options = {}) {
|
|
187
|
+
const languageRule = getLanguageRule(options.locale);
|
|
188
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
189
|
+
|
|
190
|
+
return `# ${agent.name} ${agent.emoji} Rules
|
|
191
|
+
|
|
192
|
+
Role: ${agent.role}
|
|
193
|
+
|
|
194
|
+
## Core Logic
|
|
195
|
+
${agent.systemPrompt.trim()}
|
|
196
|
+
|
|
197
|
+
${allRules.length > 0 ? '## Guidelines\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
198
|
+
`;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Converte para System Prompt Puro (OpenAI/Claude/Web)
|
|
203
|
+
*/
|
|
204
|
+
function toPlainSystemPrompt(agent, options = {}) {
|
|
205
|
+
const languageRule = getLanguageRule(options.locale);
|
|
206
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
207
|
+
|
|
208
|
+
return `You are ${agent.name} ${agent.emoji}
|
|
209
|
+
Role: ${agent.role}
|
|
210
|
+
|
|
211
|
+
[SYSTEM INSTRUCTIONS]
|
|
212
|
+
${agent.systemPrompt.trim()}
|
|
213
|
+
|
|
214
|
+
${allRules.length > 0 ? '[GUIDELINES]\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
215
|
+
`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Converte para Trae Instructions
|
|
220
|
+
*/
|
|
221
|
+
function toTraeRules(agent, options = {}) {
|
|
222
|
+
const languageRule = getLanguageRule(options.locale);
|
|
223
|
+
const allRules = [languageRule, ...(agent.rules || [])];
|
|
224
|
+
|
|
225
|
+
return `<!-- Trae Workspace Rules -->
|
|
226
|
+
# ${agent.name} ${agent.emoji}
|
|
227
|
+
|
|
228
|
+
**Role**: ${agent.role}
|
|
229
|
+
|
|
230
|
+
## Context & Instructions
|
|
231
|
+
${agent.systemPrompt.trim()}
|
|
232
|
+
|
|
233
|
+
${allRules.length > 0 ? '## Constraints\n' + allRules.map(r => `- ${r}`).join('\n') : ''}
|
|
234
|
+
`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
module.exports = {
|
|
238
|
+
toGeminiTOML,
|
|
239
|
+
toRooConfig,
|
|
240
|
+
toKiloMarkdown,
|
|
241
|
+
toCopilotInstructions,
|
|
242
|
+
toCursorMDC,
|
|
243
|
+
toWindsurfRules,
|
|
244
|
+
toPlainSystemPrompt,
|
|
245
|
+
toTraeRules
|
|
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)
|