trackfw 1.0.3 → 1.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 +17 -8
- package/bin/trackfw +4 -0
- package/package.json +10 -13
- package/src/commands/adr.js +31 -0
- package/src/commands/index.js +28 -0
- package/src/commands/init.js +174 -0
- package/src/commands/log.js +30 -0
- package/src/commands/plugins.js +97 -0
- package/src/commands/req.js +70 -0
- package/src/commands/roadmap.js +37 -0
- package/src/commands/status.js +12 -0
- package/src/commands/validate.js +29 -0
- package/src/generators/adr.js +172 -0
- package/src/generators/init.js +702 -0
- package/src/generators/req.js +239 -0
- package/src/generators/roadmap.js +224 -0
- package/src/i18n/index.js +53 -0
- package/src/i18n/locales/en-US.json +122 -0
- package/src/i18n/locales/es-ES.json +122 -0
- package/src/i18n/locales/pt-BR.json +122 -0
- package/src/validator/index.js +340 -0
- package/bin/.gitkeep +0 -0
- package/bin/README.md +0 -301
- package/bin/trackfw-darwin-amd64 +0 -0
- package/bin/trackfw-darwin-arm64 +0 -0
- package/bin/trackfw-linux-amd64 +0 -0
- package/bin/trackfw-linux-arm64 +0 -0
- package/bin/trackfw-windows-amd64.exe +0 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const os = require('os')
|
|
6
|
+
|
|
7
|
+
const GOV_DIRS = [
|
|
8
|
+
'docs/adr',
|
|
9
|
+
'docs/req',
|
|
10
|
+
'docs/roadmaps/backlog',
|
|
11
|
+
'docs/roadmaps/wip',
|
|
12
|
+
'docs/roadmaps/blocked',
|
|
13
|
+
'docs/roadmaps/done',
|
|
14
|
+
'docs/roadmaps/abandoned',
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* scaffold(cfg) — cria diretórios de governança e gera arquivos de configuração.
|
|
19
|
+
* cfg = { projectName, projectType, frontend, backend, pkgManager, hooks, ci }
|
|
20
|
+
*/
|
|
21
|
+
async function scaffold(cfg) {
|
|
22
|
+
for (const dir of GOV_DIRS) {
|
|
23
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
24
|
+
console.log(` ✓ ${dir}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
writeTrackfwConfig(cfg)
|
|
28
|
+
generateValidateScript(cfg)
|
|
29
|
+
generateCIWorkflow(cfg)
|
|
30
|
+
generateGitHooks(cfg)
|
|
31
|
+
generateClaudeMD(cfg)
|
|
32
|
+
if (cfg.backend === 'java') generatePomXml(cfg)
|
|
33
|
+
generateClaudeCommands()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// trackfw.yaml
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
function writeTrackfwConfig(cfg) {
|
|
41
|
+
const today = new Date().toISOString().slice(0, 10)
|
|
42
|
+
const content = `# trackfw configuration
|
|
43
|
+
# generated: ${today}
|
|
44
|
+
|
|
45
|
+
frontend: ${cfg.frontend || ''}
|
|
46
|
+
backend: ${cfg.backend || ''}
|
|
47
|
+
backend_framework: ${cfg.backendFramework || ''}
|
|
48
|
+
pkg_manager: ${cfg.pkgManager || ''}
|
|
49
|
+
hooks: ${cfg.hooks || ''}
|
|
50
|
+
ci: ${cfg.ci || ''}
|
|
51
|
+
`
|
|
52
|
+
fs.writeFileSync('trackfw.yaml', content, 'utf8')
|
|
53
|
+
console.log(' ✓ trackfw.yaml')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// scripts/trackfw-validate.sh
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
function generateValidateScript(cfg) {
|
|
61
|
+
fs.mkdirSync('scripts', { recursive: true })
|
|
62
|
+
|
|
63
|
+
const script = buildValidateScript(cfg)
|
|
64
|
+
const scriptPath = path.join('scripts', 'trackfw-validate.sh')
|
|
65
|
+
fs.writeFileSync(scriptPath, script, { encoding: 'utf8', mode: 0o755 })
|
|
66
|
+
console.log(` ✓ ${scriptPath}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function buildValidateScript(cfg) {
|
|
70
|
+
let base = `#!/usr/bin/env sh
|
|
71
|
+
# trackfw governance gate — generated by trackfw init
|
|
72
|
+
set -e
|
|
73
|
+
|
|
74
|
+
echo "→ trackfw: validating governance..."
|
|
75
|
+
trackfw validate
|
|
76
|
+
|
|
77
|
+
`
|
|
78
|
+
|
|
79
|
+
switch (cfg.backend) {
|
|
80
|
+
case 'go':
|
|
81
|
+
base += 'echo "→ build check (go)..."\ngo build ./...\n'
|
|
82
|
+
break
|
|
83
|
+
case 'java':
|
|
84
|
+
base += 'echo "→ build check (maven)..."\nmvn compile -q\n'
|
|
85
|
+
break
|
|
86
|
+
case 'node': {
|
|
87
|
+
const pm = cfg.pkgManager || 'npm'
|
|
88
|
+
base += `echo "→ build check (node)..."\n${pm} run build\n`
|
|
89
|
+
break
|
|
90
|
+
}
|
|
91
|
+
case 'python':
|
|
92
|
+
base += "echo \"→ build check (python)...\"\npython -m py_compile $(find . -name '*.py' -not -path './.venv/*' -not -path './venv/*')\n"
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (['react', 'vue', 'angular'].includes(cfg.frontend)) {
|
|
97
|
+
const pm = cfg.pkgManager && cfg.pkgManager !== 'none' ? cfg.pkgManager : 'npm'
|
|
98
|
+
base += `echo "→ frontend build check..."\n${pm} run build\n`
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
base += '\necho "✓ all checks passed."\n'
|
|
102
|
+
return base
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// CI workflows
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
function generateCIWorkflow(cfg) {
|
|
110
|
+
switch (cfg.ci) {
|
|
111
|
+
case 'github-actions':
|
|
112
|
+
generateGitHubActionsWorkflow()
|
|
113
|
+
break
|
|
114
|
+
case 'gitlab-ci':
|
|
115
|
+
generateGitLabCIWorkflow()
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function generateGitHubActionsWorkflow() {
|
|
121
|
+
fs.mkdirSync('.github/workflows', { recursive: true })
|
|
122
|
+
|
|
123
|
+
const content = `name: trackfw-gate
|
|
124
|
+
on:
|
|
125
|
+
pull_request:
|
|
126
|
+
branches: [main]
|
|
127
|
+
|
|
128
|
+
jobs:
|
|
129
|
+
governance:
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v4
|
|
133
|
+
|
|
134
|
+
- name: Install trackfw
|
|
135
|
+
run: |
|
|
136
|
+
curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh
|
|
137
|
+
|
|
138
|
+
- name: Governance gate
|
|
139
|
+
run: trackfw validate
|
|
140
|
+
`
|
|
141
|
+
|
|
142
|
+
const filePath = '.github/workflows/trackfw-gate.yml'
|
|
143
|
+
fs.writeFileSync(filePath, content, 'utf8')
|
|
144
|
+
console.log(` ✓ ${filePath}`)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function generateGitLabCIWorkflow() {
|
|
148
|
+
const content = `# trackfw governance gate
|
|
149
|
+
trackfw-gate:
|
|
150
|
+
stage: test
|
|
151
|
+
image: alpine:latest
|
|
152
|
+
before_script:
|
|
153
|
+
- apk add --no-cache curl
|
|
154
|
+
- curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh
|
|
155
|
+
script:
|
|
156
|
+
- trackfw validate
|
|
157
|
+
only:
|
|
158
|
+
- merge_requests
|
|
159
|
+
`
|
|
160
|
+
|
|
161
|
+
fs.writeFileSync('.gitlab-ci-trackfw.yml', content, 'utf8')
|
|
162
|
+
console.log(' ✓ .gitlab-ci-trackfw.yml')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
// Git hooks
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
|
|
169
|
+
function generateGitHooks(cfg) {
|
|
170
|
+
switch (cfg.hooks) {
|
|
171
|
+
case 'husky':
|
|
172
|
+
generateHuskyHook()
|
|
173
|
+
break
|
|
174
|
+
case 'lefthook':
|
|
175
|
+
generateLefthookHook()
|
|
176
|
+
break
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function generateHuskyHook() {
|
|
181
|
+
fs.mkdirSync('.husky', { recursive: true })
|
|
182
|
+
const content = '#!/usr/bin/env sh\n. "$(dirname -- "$0")/_/husky.sh"\n\ntrackfw validate\n'
|
|
183
|
+
const filePath = '.husky/pre-commit'
|
|
184
|
+
fs.writeFileSync(filePath, content, { encoding: 'utf8', mode: 0o755 })
|
|
185
|
+
console.log(` ✓ ${filePath}`)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function generateLefthookHook() {
|
|
189
|
+
const content = `pre-commit:
|
|
190
|
+
commands:
|
|
191
|
+
trackfw-validate:
|
|
192
|
+
run: trackfw validate
|
|
193
|
+
`
|
|
194
|
+
fs.writeFileSync('lefthook.yml', content, 'utf8')
|
|
195
|
+
console.log(' ✓ lefthook.yml')
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// pom.xml (Java / Spring Boot)
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
|
|
202
|
+
function generatePomXml(cfg) {
|
|
203
|
+
const slug = cfg.projectName
|
|
204
|
+
? cfg.projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')
|
|
205
|
+
: 'my-app'
|
|
206
|
+
const name = cfg.projectName || 'My App'
|
|
207
|
+
const content = `<?xml version="1.0" encoding="UTF-8"?>
|
|
208
|
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
209
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
210
|
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
211
|
+
<modelVersion>4.0.0</modelVersion>
|
|
212
|
+
<parent>
|
|
213
|
+
<groupId>org.springframework.boot</groupId>
|
|
214
|
+
<artifactId>spring-boot-starter-parent</artifactId>
|
|
215
|
+
<version>3.3.0</version>
|
|
216
|
+
<relativePath/>
|
|
217
|
+
</parent>
|
|
218
|
+
<groupId>com.example</groupId>
|
|
219
|
+
<artifactId>${slug}</artifactId>
|
|
220
|
+
<version>0.0.1-SNAPSHOT</version>
|
|
221
|
+
<name>${name}</name>
|
|
222
|
+
<description>${name} — generated by trackfw</description>
|
|
223
|
+
<properties>
|
|
224
|
+
<java.version>21</java.version>
|
|
225
|
+
</properties>
|
|
226
|
+
<dependencies>
|
|
227
|
+
<dependency>
|
|
228
|
+
<groupId>org.springframework.boot</groupId>
|
|
229
|
+
<artifactId>spring-boot-starter-web</artifactId>
|
|
230
|
+
</dependency>
|
|
231
|
+
<dependency>
|
|
232
|
+
<groupId>org.springframework.boot</groupId>
|
|
233
|
+
<artifactId>spring-boot-starter-actuator</artifactId>
|
|
234
|
+
</dependency>
|
|
235
|
+
<dependency>
|
|
236
|
+
<groupId>org.springframework.boot</groupId>
|
|
237
|
+
<artifactId>spring-boot-starter-test</artifactId>
|
|
238
|
+
<scope>test</scope>
|
|
239
|
+
</dependency>
|
|
240
|
+
</dependencies>
|
|
241
|
+
<build>
|
|
242
|
+
<plugins>
|
|
243
|
+
<plugin>
|
|
244
|
+
<groupId>org.springframework.boot</groupId>
|
|
245
|
+
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
246
|
+
</plugin>
|
|
247
|
+
</plugins>
|
|
248
|
+
</build>
|
|
249
|
+
</project>
|
|
250
|
+
`
|
|
251
|
+
fs.writeFileSync('pom.xml', content, 'utf8')
|
|
252
|
+
console.log(' ✓ pom.xml')
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
// CLAUDE.md
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
|
|
259
|
+
function generateClaudeMD(cfg) {
|
|
260
|
+
const today = new Date().toISOString().slice(0, 10)
|
|
261
|
+
const projectName = cfg.projectName || 'my-project'
|
|
262
|
+
|
|
263
|
+
let content = `# ${projectName} — Claude Code Instructions\n\n`
|
|
264
|
+
content += `> Generated by trackfw on ${today}. Update this file as the project evolves.\n\n`
|
|
265
|
+
|
|
266
|
+
content += '## Project overview\n\n'
|
|
267
|
+
content += '<!-- Describe what this project does in 2-3 sentences. -->\n\n'
|
|
268
|
+
|
|
269
|
+
content += '## Governance chain\n\n'
|
|
270
|
+
content += '```\nADR → REQ → ROADMAP → backlog / wip / blocked / done / abandoned\n```\n\n'
|
|
271
|
+
|
|
272
|
+
content += '## Agent rules (mandatory)\n\n'
|
|
273
|
+
content += 'These rules apply to every agent or AI assistant working in this project:\n\n'
|
|
274
|
+
content += '1. **Never start coding without a REQ and a ROADMAP.** If none exists, create them first.\n'
|
|
275
|
+
content += '2. **Use `/trackfw:implement <req-slug>` to start any implementation.** This skill orchestrates the full flow automatically: finds or generates the roadmap, moves it to `wip/`, executes each ML, updates the roadmap, and moves to `done/`.\n'
|
|
276
|
+
content += '3. **Only one roadmap in `wip/` at a time.** Before starting a new one, complete or move to `blocked/` the current one.\n'
|
|
277
|
+
content += '4. **Update the roadmap after every ML.** Mark completed MLs as `✅ Concluído` in the roadmap file before moving to the next.\n'
|
|
278
|
+
content += '5. **Run `trackfw validate` before every commit.** Zero violations required.\n'
|
|
279
|
+
content += '6. **ADRs before decisions.** Any architectural or technical decision must have an ADR (`/trackfw:adr`).\n\n'
|
|
280
|
+
|
|
281
|
+
content += '## Slash commands (Claude Code)\n\n'
|
|
282
|
+
content += '| Command | When to use |\n'
|
|
283
|
+
content += '|---|---|\n'
|
|
284
|
+
content += '| `/trackfw:implement <req>` | **Start here** — orchestrates full implementation flow |\n'
|
|
285
|
+
content += '| `/trackfw:adr <title>` | Before any architectural decision |\n'
|
|
286
|
+
content += '| `/trackfw:req <title>` | Before any implementation work |\n'
|
|
287
|
+
content += '| `/trackfw:roadmap <req>` | Generate AI roadmap from a REQ |\n'
|
|
288
|
+
content += '| `/trackfw:move <name> <state>` | Move roadmap between states manually |\n'
|
|
289
|
+
content += '| `/trackfw:validate` | Run governance validation |\n'
|
|
290
|
+
content += '| `/trackfw:status` | Check what is in flight |\n\n'
|
|
291
|
+
|
|
292
|
+
content += '## CLI commands (terminal / CI)\n\n'
|
|
293
|
+
content += '| Command | When to use |\n'
|
|
294
|
+
content += '|---|---|\n'
|
|
295
|
+
content += '| `trackfw adr new "title"` | Create ADR |\n'
|
|
296
|
+
content += '| `trackfw req new "title"` | Create REQ |\n'
|
|
297
|
+
content += '| `trackfw roadmap new` | Create empty roadmap linked to a REQ |\n'
|
|
298
|
+
content += '| `trackfw roadmap move <name> <state>` | Move roadmap state |\n'
|
|
299
|
+
content += '| `trackfw validate` | Governance validation gate |\n'
|
|
300
|
+
content += '| `trackfw status` | Show governance status |\n\n'
|
|
301
|
+
|
|
302
|
+
// Frontend section
|
|
303
|
+
if (cfg.frontend && cfg.frontend !== 'none' && cfg.frontend !== '') {
|
|
304
|
+
const pm = (cfg.pkgManager && cfg.pkgManager !== 'none') ? cfg.pkgManager : 'npm'
|
|
305
|
+
content += '## Frontend\n\n'
|
|
306
|
+
content += `Stack: ${cfg.frontend}\n`
|
|
307
|
+
content += `Package manager: ${pm}\n\n`
|
|
308
|
+
content += 'Build commands:\n'
|
|
309
|
+
content += ` ${pm} run build # build\n`
|
|
310
|
+
content += ` ${pm} run dev # dev server\n`
|
|
311
|
+
content += ` ${pm} run test # tests\n\n`
|
|
312
|
+
content += 'Rules:\n'
|
|
313
|
+
content += `- Build must pass (\`${pm} run build\`) before marking any ML as done\n`
|
|
314
|
+
content += '- Run `trackfw validate` before committing frontend changes\n\n'
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Backend section
|
|
318
|
+
if (cfg.backend && cfg.backend !== 'none' && cfg.backend !== '') {
|
|
319
|
+
const [buildCmd, testCmd, lintCmd] = backendCommands(cfg)
|
|
320
|
+
content += '## Backend\n\n'
|
|
321
|
+
content += `Stack: ${cfg.backend}\n\n`
|
|
322
|
+
content += 'Build commands:\n'
|
|
323
|
+
content += ` ${buildCmd} # build / compile check\n`
|
|
324
|
+
content += ` ${testCmd} # tests\n`
|
|
325
|
+
content += ` ${lintCmd} # lint / vet\n\n`
|
|
326
|
+
content += 'Rules:\n'
|
|
327
|
+
content += '- Build must pass before marking any ML as done\n'
|
|
328
|
+
content += '- Run `trackfw validate` before committing backend changes\n\n'
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Pre-commit checklist
|
|
332
|
+
content += '## Pre-commit checklist\n\n'
|
|
333
|
+
content += 'Before every commit:\n'
|
|
334
|
+
content += '- [ ] `trackfw validate` passes with zero violations\n'
|
|
335
|
+
if (cfg.backend && cfg.backend !== 'none' && cfg.backend !== '') {
|
|
336
|
+
const [buildCmd] = backendCommands(cfg)
|
|
337
|
+
content += `- [ ] \`${buildCmd}\` passes\n`
|
|
338
|
+
}
|
|
339
|
+
if (cfg.frontend && cfg.frontend !== 'none' && cfg.frontend !== '') {
|
|
340
|
+
const pm = (cfg.pkgManager && cfg.pkgManager !== 'none') ? cfg.pkgManager : 'npm'
|
|
341
|
+
content += `- [ ] \`${pm} run build\` passes\n`
|
|
342
|
+
}
|
|
343
|
+
content += '\n'
|
|
344
|
+
|
|
345
|
+
// Git hooks section
|
|
346
|
+
content += '## Git hooks\n\n'
|
|
347
|
+
switch (cfg.hooks) {
|
|
348
|
+
case 'husky':
|
|
349
|
+
content += 'Git hook configured in `.husky/pre-commit` — runs `trackfw validate` automatically.\n\n'
|
|
350
|
+
break
|
|
351
|
+
case 'lefthook':
|
|
352
|
+
content += 'Git hook configured in `lefthook.yml` — runs `trackfw validate` automatically.\n\n'
|
|
353
|
+
break
|
|
354
|
+
default:
|
|
355
|
+
content += 'No git hook configured. Run `trackfw validate` manually before every commit.\n\n'
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// CI gate section
|
|
359
|
+
content += '## CI gate\n\n'
|
|
360
|
+
switch (cfg.ci) {
|
|
361
|
+
case 'github-actions':
|
|
362
|
+
content += '`.github/workflows/trackfw-gate.yml` runs `trackfw validate` on every pull request to main.\n'
|
|
363
|
+
break
|
|
364
|
+
case 'gitlab-ci':
|
|
365
|
+
content += '`.gitlab-ci-trackfw.yml` runs `trackfw validate` on every merge request.\n'
|
|
366
|
+
break
|
|
367
|
+
default:
|
|
368
|
+
content += 'No CI gate configured.\n'
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
fs.writeFileSync('CLAUDE.md', content, 'utf8')
|
|
372
|
+
console.log(' ✓ CLAUDE.md')
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Retorna [buildCmd, testCmd, lintCmd] para o backend configurado.
|
|
377
|
+
*/
|
|
378
|
+
function backendCommands(cfg) {
|
|
379
|
+
const pm = (cfg.pkgManager && cfg.pkgManager !== 'none') ? cfg.pkgManager : 'npm'
|
|
380
|
+
switch (cfg.backend) {
|
|
381
|
+
case 'go':
|
|
382
|
+
return ['go build ./...', 'go test ./...', 'go vet ./...']
|
|
383
|
+
case 'java':
|
|
384
|
+
return ['mvn package -q', 'mvn test', 'mvn compile -q']
|
|
385
|
+
case 'node':
|
|
386
|
+
return [`${pm} run build`, `${pm} test`, `${pm} run lint`]
|
|
387
|
+
case 'python':
|
|
388
|
+
return [
|
|
389
|
+
"python -m py_compile $(find . -name '*.py' -not -path './.venv/*' -not -path './venv/*')",
|
|
390
|
+
'python -m pytest',
|
|
391
|
+
'ruff check .',
|
|
392
|
+
]
|
|
393
|
+
default:
|
|
394
|
+
return ['', '', '']
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// ---------------------------------------------------------------------------
|
|
399
|
+
// .claude/commands/trackfw/ — 7 slash commands
|
|
400
|
+
// ---------------------------------------------------------------------------
|
|
401
|
+
|
|
402
|
+
function generateClaudeCommands() {
|
|
403
|
+
const dir = '.claude/commands/trackfw'
|
|
404
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
405
|
+
|
|
406
|
+
const commands = {
|
|
407
|
+
'adr.md': `Execute o seguinte comando bash: \`trackfw adr new "$ARGUMENTS"\`
|
|
408
|
+
|
|
409
|
+
Se o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:
|
|
410
|
+
|
|
411
|
+
\`\`\`
|
|
412
|
+
trackfw não está instalado. Instale com uma das opções:
|
|
413
|
+
|
|
414
|
+
curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh
|
|
415
|
+
npm install -g trackfw
|
|
416
|
+
pip install trackfw
|
|
417
|
+
\`\`\``,
|
|
418
|
+
|
|
419
|
+
'req.md': `Execute o seguinte comando bash: \`trackfw req new "$ARGUMENTS"\`
|
|
420
|
+
|
|
421
|
+
Se o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:
|
|
422
|
+
|
|
423
|
+
\`\`\`
|
|
424
|
+
trackfw não está instalado. Instale com uma das opções:
|
|
425
|
+
|
|
426
|
+
curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh
|
|
427
|
+
npm install -g trackfw
|
|
428
|
+
pip install trackfw
|
|
429
|
+
\`\`\``,
|
|
430
|
+
|
|
431
|
+
'validate.md': `Execute o seguinte comando bash: \`trackfw validate\`
|
|
432
|
+
|
|
433
|
+
Se o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:
|
|
434
|
+
|
|
435
|
+
\`\`\`
|
|
436
|
+
trackfw não está instalado. Instale com uma das opções:
|
|
437
|
+
|
|
438
|
+
curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh
|
|
439
|
+
npm install -g trackfw
|
|
440
|
+
pip install trackfw
|
|
441
|
+
\`\`\``,
|
|
442
|
+
|
|
443
|
+
'status.md': `Execute o seguinte comando bash: \`trackfw status\`
|
|
444
|
+
|
|
445
|
+
Se o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:
|
|
446
|
+
|
|
447
|
+
\`\`\`
|
|
448
|
+
trackfw não está instalado. Instale com uma das opções:
|
|
449
|
+
|
|
450
|
+
curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh
|
|
451
|
+
npm install -g trackfw
|
|
452
|
+
pip install trackfw
|
|
453
|
+
\`\`\``,
|
|
454
|
+
|
|
455
|
+
'move.md': `Execute o seguinte comando bash: \`trackfw roadmap move $ARGUMENTS\`
|
|
456
|
+
|
|
457
|
+
O formato esperado é: \`<nome-do-roadmap> <estado>\`
|
|
458
|
+
|
|
459
|
+
Estados válidos: \`backlog\`, \`wip\`, \`blocked\`, \`done\`, \`abandoned\`
|
|
460
|
+
|
|
461
|
+
Exemplo: \`/trackfw:move meu-roadmap wip\`
|
|
462
|
+
|
|
463
|
+
Se o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:
|
|
464
|
+
trackfw não está instalado. Instale com:
|
|
465
|
+
curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh
|
|
466
|
+
npm install -g trackfw
|
|
467
|
+
pip install trackfw`,
|
|
468
|
+
|
|
469
|
+
'roadmap.md': `Gere um roadmap de implementação em microlotes para uma REQ do projeto.
|
|
470
|
+
|
|
471
|
+
## Passos
|
|
472
|
+
|
|
473
|
+
1. **Listar REQs disponíveis**
|
|
474
|
+
Use Glob para listar \`docs/req/*.md\`. Se nenhum arquivo encontrado, informe:
|
|
475
|
+
> Nenhuma REQ encontrada em \`docs/req/\`. Crie uma primeiro com \`/trackfw:req\`.
|
|
476
|
+
|
|
477
|
+
2. **Selecionar a REQ**
|
|
478
|
+
- Se \`$ARGUMENTS\` foi fornecido: use como filtro (substring case-insensitive) para encontrar o arquivo
|
|
479
|
+
- Se não foi fornecido ou o filtro não encontrar exatamente um: liste os arquivos disponíveis e pergunte ao usuário qual usar
|
|
480
|
+
- Leia o conteúdo completo do arquivo REQ selecionado
|
|
481
|
+
|
|
482
|
+
3. **Gerar o roadmap**
|
|
483
|
+
Com base no conteúdo da REQ, gere um roadmap seguindo **estritamente** este formato:
|
|
484
|
+
|
|
485
|
+
\`\`\`markdown
|
|
486
|
+
# Roadmap: <título derivado da REQ>
|
|
487
|
+
|
|
488
|
+
> Criado em: <YYYY-MM-DD> | Status: ⬜ Backlog
|
|
489
|
+
|
|
490
|
+
## Diagnóstico / Contexto
|
|
491
|
+
<resumo do problema, motivação e escopo extraídos da REQ>
|
|
492
|
+
|
|
493
|
+
## Wave 1 — <nome descritivo> (<N> MLs em paralelo)
|
|
494
|
+
> Dependências: Independente
|
|
495
|
+
|
|
496
|
+
### ML-1A — <título>
|
|
497
|
+
**Status:** ⬜ Pendente
|
|
498
|
+
**Arquivos afetados:**
|
|
499
|
+
- \`caminho/exato/do/arquivo\`
|
|
500
|
+
**Ações:**
|
|
501
|
+
- Descrição detalhada da ação com valores, chaves e comandos exatos
|
|
502
|
+
**Critérios de aceite:**
|
|
503
|
+
- [ ] build sem erros
|
|
504
|
+
- [ ] testes verdes
|
|
505
|
+
**Comandos de validação:** \`<comando de build e teste do projeto>\`
|
|
506
|
+
\`\`\`
|
|
507
|
+
|
|
508
|
+
**Princípios obrigatórios:**
|
|
509
|
+
- MLs dentro da mesma Wave são **independentes** (arquivos distintos, sem conflito)
|
|
510
|
+
- Cada ML deve ser detalhado o suficiente para execução por um agente sem contexto extra
|
|
511
|
+
- Maximizar paralelismo: agrupe em paralelo tudo que não compartilhar arquivos
|
|
512
|
+
- Waves sequenciais apenas quando há dependência real de resultado
|
|
513
|
+
- Critérios de aceite mensuráveis em cada ML
|
|
514
|
+
|
|
515
|
+
4. **Salvar o arquivo**
|
|
516
|
+
- Calcule o slug: título em lowercase, espaços → hifens, remova caracteres especiais
|
|
517
|
+
- Crie o arquivo em \`docs/roadmaps/backlog/ROADMAP-<YYYY-MM-DD>-<slug>.md\`
|
|
518
|
+
- Use a data de hoje
|
|
519
|
+
|
|
520
|
+
5. **Confirmar**
|
|
521
|
+
Informe o caminho do arquivo criado e um resumo das Waves e total de MLs gerados.`,
|
|
522
|
+
|
|
523
|
+
'implement.md': `Você é o orquestrador de implementação do trackfw. Siga o fluxo abaixo **sem pular etapas**.
|
|
524
|
+
|
|
525
|
+
## Argumento
|
|
526
|
+
|
|
527
|
+
\`$ARGUMENTS\` é opcional. Se fornecido, é usado como filtro (substring case-insensitive) sobre os nomes de arquivo das REQs.
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Passo 1 — Selecionar a REQ
|
|
532
|
+
|
|
533
|
+
Use Glob para listar \`docs/req/*.md\`.
|
|
534
|
+
|
|
535
|
+
- Se **nenhum arquivo encontrado**: informe que não há REQs disponíveis e sugira criar com \`/trackfw:req\`.
|
|
536
|
+
- Se **\`$ARGUMENTS\` foi fornecido** e filtra para exatamente uma REQ: use-a diretamente.
|
|
537
|
+
- Em **todos os outros casos** (sem argumento, ou argumento ambíguo): apresente a lista de REQs disponíveis e pergunte ao usuário qual deseja implementar.
|
|
538
|
+
|
|
539
|
+
Leia o conteúdo completo da REQ selecionada.
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## Passo 2 — Encontrar ou gerar o Roadmap
|
|
544
|
+
|
|
545
|
+
Verifique se existe um roadmap vinculado à REQ buscando em \`docs/roadmaps/\` (backlog, wip, blocked, done, abandoned) por arquivo cujo nome contenha o slug da REQ.
|
|
546
|
+
|
|
547
|
+
**Se o roadmap ainda não existe:**
|
|
548
|
+
- Informe o usuário: "Nenhum roadmap encontrado para esta REQ. Gerando agora..."
|
|
549
|
+
- Execute o fluxo completo de geração do \`/trackfw:roadmap\` (leia o arquivo \`.claude/commands/trackfw/roadmap.md\` para seguir as instruções exatas), passando a REQ já selecionada — não pergunte novamente.
|
|
550
|
+
- Salve o roadmap gerado em \`docs/roadmaps/backlog/ROADMAP-<YYYY-MM-DD>-<slug>.md\`.
|
|
551
|
+
|
|
552
|
+
**Se o roadmap existe e já está em \`done/\` ou \`abandoned/\`:**
|
|
553
|
+
- Informe o usuário e pergunte se deseja criar um novo roadmap ou encerrar.
|
|
554
|
+
|
|
555
|
+
**Se o roadmap existe em \`backlog/\` ou \`blocked/\`:**
|
|
556
|
+
- Prossiga para o Passo 3.
|
|
557
|
+
|
|
558
|
+
**Se já está em \`wip/\`:**
|
|
559
|
+
- Prossiga diretamente para o Passo 4 (já está em execução).
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
## Passo 3 — Mover roadmap para WIP
|
|
564
|
+
|
|
565
|
+
Execute:
|
|
566
|
+
\`\`\`bash
|
|
567
|
+
trackfw roadmap move <nome-do-roadmap> wip
|
|
568
|
+
\`\`\`
|
|
569
|
+
|
|
570
|
+
Confirme que o arquivo foi movido para \`docs/roadmaps/wip/\`.
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## Passo 4 — Ler e apresentar o plano
|
|
575
|
+
|
|
576
|
+
Leia o roadmap (agora em \`wip/\`). Apresente ao usuário:
|
|
577
|
+
- Título do roadmap
|
|
578
|
+
- Total de Waves e MLs
|
|
579
|
+
- Lista resumida dos MLs por Wave
|
|
580
|
+
|
|
581
|
+
Confirme: "Iniciando implementação. Vou executar cada ML em ordem e atualizar o roadmap a cada conclusão."
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Passo 5 — Executar cada ML em ordem
|
|
586
|
+
|
|
587
|
+
Para cada Wave (em sequência), execute os MLs da Wave:
|
|
588
|
+
|
|
589
|
+
### Para cada ML:
|
|
590
|
+
|
|
591
|
+
**5a. Anunciar:** informe qual ML está sendo executado (ex: "Executando ML-1A — Criar client.go").
|
|
592
|
+
|
|
593
|
+
**5b. Implementar:** execute as ações descritas no ML usando suas ferramentas (Read, Write, Edit, Bash). Siga exatamente os arquivos afetados, ações e critérios de aceite listados no roadmap.
|
|
594
|
+
|
|
595
|
+
**5c. Validar:** execute os comandos de validação do ML. Se falhar, corrija antes de avançar.
|
|
596
|
+
|
|
597
|
+
**5d. Atualizar o roadmap:** edite o arquivo de roadmap em \`docs/roadmaps/wip/\` substituindo o status do ML:
|
|
598
|
+
- \`**Status:** ⬜ Pendente\` → \`**Status:** ✅ Concluído\`
|
|
599
|
+
|
|
600
|
+
**5e. Commitar:**
|
|
601
|
+
\`\`\`bash
|
|
602
|
+
git add -A
|
|
603
|
+
git commit -m "feat(<escopo>): <descrição do ML>"
|
|
604
|
+
\`\`\`
|
|
605
|
+
|
|
606
|
+
Só avance para a próxima Wave após todos os MLs da Wave atual estarem ✅.
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
## Passo 6 — Finalizar
|
|
611
|
+
|
|
612
|
+
Quando todos os MLs estiverem ✅:
|
|
613
|
+
|
|
614
|
+
**6a.** Execute \`trackfw validate\` — deve passar com zero violations.
|
|
615
|
+
|
|
616
|
+
**6b.** Mova o roadmap para done:
|
|
617
|
+
\`\`\`bash
|
|
618
|
+
trackfw roadmap move <nome-do-roadmap> done
|
|
619
|
+
\`\`\`
|
|
620
|
+
|
|
621
|
+
**6c.** Faça o commit final:
|
|
622
|
+
\`\`\`bash
|
|
623
|
+
git add docs/roadmaps/
|
|
624
|
+
git commit -m "docs(trackfw): roadmap <nome> → done"
|
|
625
|
+
\`\`\`
|
|
626
|
+
|
|
627
|
+
**6d.** Informe o usuário:
|
|
628
|
+
\`\`\`
|
|
629
|
+
✅ Implementação concluída.
|
|
630
|
+
Roadmap: docs/roadmaps/done/<nome>.md
|
|
631
|
+
Próximo passo: abrir PR com gh pr create
|
|
632
|
+
\`\`\``,
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
let created = 0
|
|
636
|
+
let skipped = 0
|
|
637
|
+
for (const [filename, content] of Object.entries(commands)) {
|
|
638
|
+
const filePath = path.join(dir, filename)
|
|
639
|
+
if (fs.existsSync(filePath)) {
|
|
640
|
+
skipped++
|
|
641
|
+
continue
|
|
642
|
+
}
|
|
643
|
+
fs.writeFileSync(filePath, content, 'utf8')
|
|
644
|
+
created++
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (skipped > 0) {
|
|
648
|
+
console.log(` ✓ ${dir} (${created} slash commands criados, ${skipped} já existiam — não sobrescritos)`)
|
|
649
|
+
} else {
|
|
650
|
+
console.log(` ✓ ${dir} (${created} slash commands)`)
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// ---------------------------------------------------------------------------
|
|
655
|
+
// AI tool installers
|
|
656
|
+
// ---------------------------------------------------------------------------
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* installAgents — instala agentes Claude Code em ~/.claude/agents/
|
|
660
|
+
* O pacote npm não embute os templates binários do Go, por isso informa
|
|
661
|
+
* ao usuário que esta operação requer o binário Go instalado.
|
|
662
|
+
*/
|
|
663
|
+
async function installAgents() {
|
|
664
|
+
console.log(' ✓ claude (agentes — execute `trackfw install agents` com o binário Go para instalar os templates)')
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
async function installGemini() {
|
|
668
|
+
console.log(' ✓ gemini (sem templates disponíveis no pacote npm — instale o binário Go para acesso completo)')
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
async function installCursor() {
|
|
672
|
+
console.log(' ✓ cursor (sem templates disponíveis no pacote npm — instale o binário Go para acesso completo)')
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
async function installCopilot() {
|
|
676
|
+
console.log(' ✓ copilot (sem templates disponíveis no pacote npm — instale o binário Go para acesso completo)')
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
async function installWindsurf() {
|
|
680
|
+
console.log(' ✓ windsurf (sem templates disponíveis no pacote npm — instale o binário Go para acesso completo)')
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
async function installAmazonQ() {
|
|
684
|
+
console.log(' ✓ amazonq (sem templates disponíveis no pacote npm — instale o binário Go para acesso completo)')
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
module.exports = {
|
|
688
|
+
GOV_DIRS,
|
|
689
|
+
scaffold,
|
|
690
|
+
writeTrackfwConfig,
|
|
691
|
+
generateValidateScript,
|
|
692
|
+
generateCIWorkflow,
|
|
693
|
+
generateGitHooks,
|
|
694
|
+
generateClaudeMD,
|
|
695
|
+
generateClaudeCommands,
|
|
696
|
+
installAgents,
|
|
697
|
+
installGemini,
|
|
698
|
+
installCursor,
|
|
699
|
+
installCopilot,
|
|
700
|
+
installWindsurf,
|
|
701
|
+
installAmazonQ,
|
|
702
|
+
}
|