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.
@@ -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 };
@@ -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
- if (agent.rules && agent.rules.length > 0) {
43
+ const allRules = [languageRule, ...(agent.rules || [])];
44
+
45
+ if (allRules.length > 0) {
19
46
  parts.push(`# Rules & Guidelines`);
20
- agent.rules.forEach(rule => parts.push(`- ${rule}`));
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 (agent.rules && agent.rules.length > 0) {
61
+ if (allRules.length > 0) {
35
62
  toml += 'rules = [\n';
36
- agent.rules.forEach(rule => {
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
- if (agent.rules && agent.rules.length > 0) {
83
+ const allRules = [languageRule, ...(agent.rules || [])];
84
+
85
+ if (allRules.length > 0) {
56
86
  promptParts.push(`## Rules & Guidelines`);
57
- agent.rules.forEach(rule => promptParts.push(`- ${rule}`));
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
- if (agent.rules && agent.rules.length > 0) {
112
+ const allRules = [languageRule, ...(agent.rules || [])];
113
+
114
+ if (allRules.length > 0) {
82
115
  parts.push(`## Constraints`);
83
- agent.rules.forEach(rule => parts.push(`- ${rule}`));
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
- if (agent.rules && agent.rules.length > 0) {
137
+ const allRules = [languageRule, ...(agent.rules || [])];
138
+
139
+ if (allRules.length > 0) {
104
140
  parts.push(`## Rules & Guidelines`);
105
- agent.rules.forEach(rule => parts.push(`- ${rule}`));
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
- return `---
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
- ${agent.rules && agent.rules.length > 0 ? '## Rules\n' + agent.rules.map(r => `- ${r}`).join('\n') : ''}
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
- ${agent.rules && agent.rules.length > 0 ? '## Guidelines\n' + agent.rules.map(r => `- ${r}`).join('\n') : ''}
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
- ${agent.rules && agent.rules.length > 0 ? '[GUIDELINES]\n' + agent.rules.map(r => `- ${r}`).join('\n') : ''}
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
- ${agent.rules && agent.rules.length > 0 ? '## Constraints\n' + agent.rules.map(r => `- ${r}`).join('\n') : ''}
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,9 @@
1
+ # 📜 Project Guidelines
2
+
3
+ ## 🏗️ Architecture Patterns
4
+
5
+ ## 💻 Code Conventions
6
+
7
+ ## 🛠️ Tech Stack & Versions
8
+
9
+ ## 🛡️ Security & Performance
@@ -0,0 +1,14 @@
1
+ ---
2
+ title: Development Roadmap
3
+ source_spec: docs/project.md
4
+ last_updated:
5
+ status:
6
+ ---
7
+
8
+ # Strategic Roadmap
9
+
10
+ ## 1. Strategy Summary
11
+
12
+ ## 2. Milestones Detail
13
+
14
+ ## 3. Risk Matrix
@@ -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)
@@ -0,0 +1,11 @@
1
+ ---
2
+ title: Tasks Sprint -
3
+ milestone_ref:
4
+ tech_stack:
5
+ ---
6
+
7
+ # Execution Backlog:
8
+
9
+ ## Technical Summary
10
+
11
+ ## Tasks Checklist