trackfw 1.0.4 → 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/package.json +1 -1
- package/src/commands/adr.js +8 -7
- package/src/commands/init.js +50 -19
- package/src/commands/log.js +5 -4
- package/src/commands/plugins.js +11 -10
- package/src/commands/req.js +10 -9
- package/src/commands/roadmap.js +6 -5
- package/src/commands/status.js +2 -1
- package/src/commands/validate.js +5 -4
- package/src/generators/init.js +59 -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/README.md
CHANGED
|
@@ -79,12 +79,14 @@ brew install kgsaran/tap/trackfw
|
|
|
79
79
|
go install github.com/kgsaran/trackfw/cmd/trackfw@latest
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
### npm
|
|
82
|
+
### npm (pure Node.js — no binary)
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
85
|
npm install -g trackfw
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
The npm package is pure Node.js — no compiled binary, no postinstall download. Works everywhere Node.js ≥ 18 is installed, including corporate Windows environments where unsigned `.exe` files are blocked by antivirus.
|
|
89
|
+
|
|
88
90
|
### pip
|
|
89
91
|
|
|
90
92
|
```bash
|
|
@@ -127,18 +129,25 @@ trackfw status
|
|
|
127
129
|
| `trackfw req new "title"` | Create a REQ with guided ADR discovery |
|
|
128
130
|
| `trackfw req list` | List all REQs with status |
|
|
129
131
|
| `trackfw roadmap new "title"` | Create a roadmap in `backlog/` |
|
|
132
|
+
| `trackfw roadmap show <name>` | Print a roadmap with its current state |
|
|
130
133
|
| `trackfw roadmap move <name> <state>` | Move roadmap between states |
|
|
131
134
|
| `trackfw roadmap list` | List all roadmaps grouped by state |
|
|
132
135
|
| `trackfw validate` | Check governance consistency (use as CI gate) |
|
|
133
136
|
| `trackfw status` | Show wip, blocked, REQs waiting on ADRs |
|
|
134
|
-
| `trackfw
|
|
135
|
-
| `trackfw
|
|
136
|
-
| `trackfw
|
|
137
|
-
| `trackfw
|
|
138
|
-
| `trackfw
|
|
139
|
-
| `trackfw
|
|
137
|
+
| `trackfw log [--tail N]` | Show roadmap state transition history |
|
|
138
|
+
| `trackfw plugins list` | List installed plugins |
|
|
139
|
+
| `trackfw plugins add <user/repo>` | Install a plugin from GitHub Releases |
|
|
140
|
+
| `trackfw plugins remove <name>` | Remove an installed plugin |
|
|
141
|
+
| `trackfw agents` | Install Claude Code subagents *(Go binary only)* |
|
|
142
|
+
| `trackfw gemini` | Install Gemini CLI skills and commands *(Go binary only)* |
|
|
143
|
+
| `trackfw cursor` | Install Cursor rules *(Go binary only)* |
|
|
144
|
+
| `trackfw copilot` | Install GitHub Copilot instructions *(Go binary only)* |
|
|
145
|
+
| `trackfw windsurf` | Install Windsurf rules and workflows *(Go binary only)* |
|
|
146
|
+
| `trackfw amazonq` | Install Amazon Q Developer rules *(Go binary only)* |
|
|
140
147
|
| `trackfw version` | Print version |
|
|
141
148
|
|
|
149
|
+
> **Go binary only** commands (`agents`, `gemini`, `cursor`, `copilot`, `windsurf`, `amazonq`) are available when installed via brew, `install.sh`, or `go install`. When using the npm package, AI integrations are installed through `trackfw init`.
|
|
150
|
+
|
|
142
151
|
---
|
|
143
152
|
|
|
144
153
|
## Governance chain
|
|
@@ -227,7 +236,7 @@ $ trackfw status
|
|
|
227
236
|
|
|
228
237
|
## AI assistant integration
|
|
229
238
|
|
|
230
|
-
`trackfw init` asks which AI tools your team uses and installs native governance context for each.
|
|
239
|
+
`trackfw init` asks which AI tools your team uses and installs native governance context for each. When using the Go binary (brew, `install.sh`, `go install`), each integration can also be run as a standalone command.
|
|
231
240
|
|
|
232
241
|
| Command | Installs | Format |
|
|
233
242
|
|---|---|---|
|
package/package.json
CHANGED
package/src/commands/adr.js
CHANGED
|
@@ -3,26 +3,27 @@
|
|
|
3
3
|
const { Command } = require('commander')
|
|
4
4
|
const { input } = require('@inquirer/prompts')
|
|
5
5
|
const generators = require('../generators/adr')
|
|
6
|
+
const { t } = require('../i18n')
|
|
6
7
|
|
|
7
8
|
const cmd = new Command('adr')
|
|
8
|
-
cmd.description('
|
|
9
|
+
cmd.description(t('adr.description'))
|
|
9
10
|
|
|
10
11
|
cmd.command('new <title>')
|
|
11
|
-
.description('
|
|
12
|
+
.description(t('adr.new.description'))
|
|
12
13
|
.action(async (title) => {
|
|
13
14
|
const content = { title }
|
|
14
15
|
// wizard interativo se TTY
|
|
15
16
|
if (process.stdin.isTTY) {
|
|
16
|
-
content.context = await input({ message: '
|
|
17
|
-
content.decision = await input({ message: '
|
|
18
|
-
content.consequences = await input({ message: '
|
|
19
|
-
content.alternatives = await input({ message: '
|
|
17
|
+
content.context = await input({ message: t('adr.new.prompt.context'), default: '' })
|
|
18
|
+
content.decision = await input({ message: t('adr.new.prompt.decision'), default: '' })
|
|
19
|
+
content.consequences = await input({ message: t('adr.new.prompt.consequences'), default: '' })
|
|
20
|
+
content.alternatives = await input({ message: t('adr.new.prompt.alternatives'), default: '' })
|
|
20
21
|
}
|
|
21
22
|
await generators.newADR(content)
|
|
22
23
|
})
|
|
23
24
|
|
|
24
25
|
cmd.command('list')
|
|
25
|
-
.description('
|
|
26
|
+
.description(t('adr.list.description'))
|
|
26
27
|
.action(async () => {
|
|
27
28
|
await generators.listADRs('docs/adr')
|
|
28
29
|
})
|
package/src/commands/init.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { Command } = require('commander')
|
|
3
|
+
const { t } = require('../i18n')
|
|
3
4
|
|
|
4
5
|
const cmd = new Command('init')
|
|
5
|
-
cmd.description('
|
|
6
|
+
cmd.description(t('init.description'))
|
|
6
7
|
cmd.action(async () => {
|
|
7
8
|
const path = require('path')
|
|
8
9
|
const generators = require('../generators/init')
|
|
@@ -19,27 +20,27 @@ cmd.action(async () => {
|
|
|
19
20
|
ci: 'none',
|
|
20
21
|
}
|
|
21
22
|
await generators.scaffold(cfg)
|
|
22
|
-
console.log(
|
|
23
|
+
console.log(`\n${t('init.success')}`)
|
|
23
24
|
return
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const { input, select, checkbox } = require('@inquirer/prompts')
|
|
27
28
|
|
|
28
|
-
let projectName, projectType, frontend, pkgManager, backend, hooks, ci, aiTools
|
|
29
|
+
let projectName, projectType, frontend, pkgManager, backend, backendFramework, hooks, ci, aiTools
|
|
29
30
|
|
|
30
31
|
try {
|
|
31
32
|
projectName = await input({
|
|
32
|
-
message: '
|
|
33
|
+
message: t('init.prompt.projectName'),
|
|
33
34
|
default: path.basename(process.cwd()),
|
|
34
35
|
})
|
|
35
36
|
|
|
36
37
|
projectType = await select({
|
|
37
|
-
message: '
|
|
38
|
+
message: t('init.prompt.projectType'),
|
|
38
39
|
choices: [
|
|
39
|
-
{ name: '
|
|
40
|
-
{ name: '
|
|
41
|
-
{ name: '
|
|
42
|
-
{ name: '
|
|
40
|
+
{ name: t('init.prompt.projectType_fullstack'), value: 'fullstack' },
|
|
41
|
+
{ name: t('init.prompt.projectType_frontend'), value: 'frontend' },
|
|
42
|
+
{ name: t('init.prompt.projectType_backend'), value: 'backend' },
|
|
43
|
+
{ name: t('init.prompt.projectType_governance'), value: 'governance' },
|
|
43
44
|
],
|
|
44
45
|
})
|
|
45
46
|
|
|
@@ -47,7 +48,7 @@ cmd.action(async () => {
|
|
|
47
48
|
pkgManager = ''
|
|
48
49
|
if (projectType === 'fullstack' || projectType === 'frontend') {
|
|
49
50
|
frontend = await select({
|
|
50
|
-
message: '
|
|
51
|
+
message: t('init.prompt.frontendStack'),
|
|
51
52
|
choices: [
|
|
52
53
|
{ name: 'React / Next.js', value: 'react' },
|
|
53
54
|
{ name: 'Vue', value: 'vue' },
|
|
@@ -55,7 +56,7 @@ cmd.action(async () => {
|
|
|
55
56
|
],
|
|
56
57
|
})
|
|
57
58
|
pkgManager = await select({
|
|
58
|
-
message: '
|
|
59
|
+
message: t('init.prompt.pkgManager'),
|
|
59
60
|
choices: [
|
|
60
61
|
{ name: 'npm', value: 'npm' },
|
|
61
62
|
{ name: 'pnpm', value: 'pnpm' },
|
|
@@ -66,20 +67,50 @@ cmd.action(async () => {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
backend = ''
|
|
70
|
+
let backendFramework = ''
|
|
69
71
|
if (projectType === 'fullstack' || projectType === 'backend') {
|
|
70
72
|
backend = await select({
|
|
71
|
-
message: '
|
|
73
|
+
message: t('init.prompt.backendLang'),
|
|
72
74
|
choices: [
|
|
73
75
|
{ name: 'Go', value: 'go' },
|
|
74
|
-
{ name: 'Java
|
|
76
|
+
{ name: 'Java', value: 'java' },
|
|
75
77
|
{ name: 'Node.js', value: 'node' },
|
|
76
78
|
{ name: 'Python', value: 'python' },
|
|
77
79
|
],
|
|
78
80
|
})
|
|
81
|
+
|
|
82
|
+
const frameworkChoices = {
|
|
83
|
+
go: [
|
|
84
|
+
{ name: 'Gin', value: 'gin' },
|
|
85
|
+
{ name: 'Echo', value: 'echo' },
|
|
86
|
+
{ name: 'Fiber', value: 'fiber' },
|
|
87
|
+
{ name: 'Standard library (net/http)', value: 'stdlib' },
|
|
88
|
+
],
|
|
89
|
+
java: [
|
|
90
|
+
{ name: 'Spring Boot', value: 'spring-boot' },
|
|
91
|
+
{ name: 'Quarkus', value: 'quarkus' },
|
|
92
|
+
{ name: 'Micronaut', value: 'micronaut' },
|
|
93
|
+
],
|
|
94
|
+
node: [
|
|
95
|
+
{ name: 'Express', value: 'express' },
|
|
96
|
+
{ name: 'Fastify', value: 'fastify' },
|
|
97
|
+
{ name: 'NestJS', value: 'nestjs' },
|
|
98
|
+
{ name: 'Koa', value: 'koa' },
|
|
99
|
+
],
|
|
100
|
+
python: [
|
|
101
|
+
{ name: 'FastAPI', value: 'fastapi' },
|
|
102
|
+
{ name: 'Django', value: 'django' },
|
|
103
|
+
{ name: 'Flask', value: 'flask' },
|
|
104
|
+
],
|
|
105
|
+
}
|
|
106
|
+
backendFramework = await select({
|
|
107
|
+
message: t('init.prompt.backendFramework'),
|
|
108
|
+
choices: frameworkChoices[backend] || [],
|
|
109
|
+
})
|
|
79
110
|
}
|
|
80
111
|
|
|
81
112
|
hooks = await select({
|
|
82
|
-
message: '
|
|
113
|
+
message: t('init.prompt.gitHooks'),
|
|
83
114
|
choices: [
|
|
84
115
|
{ name: 'husky', value: 'husky' },
|
|
85
116
|
{ name: 'lefthook', value: 'lefthook' },
|
|
@@ -88,7 +119,7 @@ cmd.action(async () => {
|
|
|
88
119
|
})
|
|
89
120
|
|
|
90
121
|
ci = await select({
|
|
91
|
-
message: '
|
|
122
|
+
message: t('init.prompt.ci'),
|
|
92
123
|
choices: [
|
|
93
124
|
{ name: 'GitHub Actions', value: 'github-actions' },
|
|
94
125
|
{ name: 'GitLab CI', value: 'gitlab-ci' },
|
|
@@ -97,7 +128,7 @@ cmd.action(async () => {
|
|
|
97
128
|
})
|
|
98
129
|
|
|
99
130
|
aiTools = await checkbox({
|
|
100
|
-
message: '
|
|
131
|
+
message: t('init.prompt.aiTools'),
|
|
101
132
|
choices: [
|
|
102
133
|
{ name: 'Claude Code', value: 'claude' },
|
|
103
134
|
{ name: 'Gemini CLI', value: 'gemini' },
|
|
@@ -119,11 +150,11 @@ cmd.action(async () => {
|
|
|
119
150
|
ci: 'none',
|
|
120
151
|
}
|
|
121
152
|
await generators.scaffold(cfg)
|
|
122
|
-
console.log(
|
|
153
|
+
console.log(`\n${t('init.success')}`)
|
|
123
154
|
return
|
|
124
155
|
}
|
|
125
156
|
|
|
126
|
-
const cfg = { projectName, projectType, frontend, backend, pkgManager, hooks, ci }
|
|
157
|
+
const cfg = { projectName, projectType, frontend, backend, backendFramework, pkgManager, hooks, ci }
|
|
127
158
|
await generators.scaffold(cfg)
|
|
128
159
|
|
|
129
160
|
for (const tool of (aiTools || [])) {
|
|
@@ -137,7 +168,7 @@ cmd.action(async () => {
|
|
|
137
168
|
}
|
|
138
169
|
}
|
|
139
170
|
|
|
140
|
-
console.log(
|
|
171
|
+
console.log(`\n${t('init.success')}`)
|
|
141
172
|
})
|
|
142
173
|
|
|
143
174
|
module.exports = cmd
|
package/src/commands/log.js
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
const { Command } = require('commander')
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
const path = require('path')
|
|
5
|
+
const { t } = require('../i18n')
|
|
5
6
|
|
|
6
7
|
const cmd = new Command('log')
|
|
7
|
-
cmd.description('
|
|
8
|
-
cmd.option('--tail <n>', '
|
|
8
|
+
cmd.description(t('log.description'))
|
|
9
|
+
cmd.option('--tail <n>', t('log.tail'), '20')
|
|
9
10
|
cmd.action(async (opts) => {
|
|
10
11
|
const tail = parseInt(opts.tail, 10)
|
|
11
12
|
const logPath = path.join('docs', 'roadmaps', '.trackfw-log')
|
|
12
13
|
|
|
13
14
|
if (!fs.existsSync(logPath)) {
|
|
14
|
-
console.log('
|
|
15
|
+
console.log(t('log.empty'))
|
|
15
16
|
return
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -22,7 +23,7 @@ cmd.action(async (opts) => {
|
|
|
22
23
|
const start = Math.max(0, lines.length - tail)
|
|
23
24
|
const visible = lines.slice(start)
|
|
24
25
|
|
|
25
|
-
console.log('
|
|
26
|
+
console.log(t('log.header'))
|
|
26
27
|
visible.forEach(l => console.log(l))
|
|
27
28
|
})
|
|
28
29
|
|
package/src/commands/plugins.js
CHANGED
|
@@ -3,6 +3,7 @@ const { Command } = require('commander')
|
|
|
3
3
|
const os = require('os')
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const fs = require('fs')
|
|
6
|
+
const { t } = require('../i18n')
|
|
6
7
|
|
|
7
8
|
function pluginsDir() {
|
|
8
9
|
return path.join(os.homedir(), '.trackfw', 'plugins')
|
|
@@ -40,7 +41,7 @@ async function installPlugin(repo) {
|
|
|
40
41
|
: `https://github.com/${base}/releases/download/${tag}/${assetName}`
|
|
41
42
|
|
|
42
43
|
const res = await fetch(url)
|
|
43
|
-
if (!res.ok) throw new Error(
|
|
44
|
+
if (!res.ok) throw new Error(t('errors.downloadFailed', { status: res.status, url }))
|
|
44
45
|
|
|
45
46
|
const dir = pluginsDir()
|
|
46
47
|
fs.mkdirSync(dir, { recursive: true })
|
|
@@ -49,32 +50,32 @@ async function installPlugin(repo) {
|
|
|
49
50
|
|
|
50
51
|
function removePlugin(name) {
|
|
51
52
|
const filePath = path.join(pluginsDir(), name)
|
|
52
|
-
if (!fs.existsSync(filePath)) throw new Error(
|
|
53
|
+
if (!fs.existsSync(filePath)) throw new Error(t('errors.pluginNotFound', { name }))
|
|
53
54
|
fs.unlinkSync(filePath)
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
const cmd = new Command('plugins')
|
|
57
|
-
cmd.description('
|
|
58
|
+
cmd.description(t('plugins.description'))
|
|
58
59
|
|
|
59
60
|
cmd.command('list')
|
|
60
|
-
.description('
|
|
61
|
+
.description(t('plugins.list.description'))
|
|
61
62
|
.action(() => {
|
|
62
63
|
const plugins = listPlugins()
|
|
63
64
|
if (plugins.length === 0) {
|
|
64
|
-
console.log('
|
|
65
|
+
console.log(t('plugins.list.empty'))
|
|
65
66
|
return
|
|
66
67
|
}
|
|
67
68
|
plugins.forEach(p => console.log(p))
|
|
68
69
|
})
|
|
69
70
|
|
|
70
71
|
cmd.command('add <repo>')
|
|
71
|
-
.description(
|
|
72
|
+
.description(t('plugins.add.description'))
|
|
72
73
|
.action(async (repo) => {
|
|
73
74
|
try {
|
|
74
|
-
console.log(
|
|
75
|
+
console.log(t('plugins.add.installing', { repo }))
|
|
75
76
|
await installPlugin(repo)
|
|
76
77
|
const name = repo.split('@')[0].split('/').pop()
|
|
77
|
-
console.log(
|
|
78
|
+
console.log(t('plugins.add.success', { name }))
|
|
78
79
|
} catch (err) {
|
|
79
80
|
console.error(`Error: ${err.message}`)
|
|
80
81
|
process.exit(1)
|
|
@@ -82,11 +83,11 @@ cmd.command('add <repo>')
|
|
|
82
83
|
})
|
|
83
84
|
|
|
84
85
|
cmd.command('remove <name>')
|
|
85
|
-
.description('
|
|
86
|
+
.description(t('plugins.remove.description'))
|
|
86
87
|
.action((name) => {
|
|
87
88
|
try {
|
|
88
89
|
removePlugin(name)
|
|
89
|
-
console.log(
|
|
90
|
+
console.log(t('plugins.remove.success', { name }))
|
|
90
91
|
} catch (err) {
|
|
91
92
|
console.error(`Error: ${err.message}`)
|
|
92
93
|
process.exit(1)
|
package/src/commands/req.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { Command } = require('commander')
|
|
3
3
|
const { listREQs } = require('../generators/req')
|
|
4
|
+
const { t } = require('../i18n')
|
|
4
5
|
|
|
5
6
|
const cmd = new Command('req')
|
|
6
|
-
cmd.description('
|
|
7
|
+
cmd.description(t('req.description'))
|
|
7
8
|
|
|
8
9
|
cmd.command('new <title>')
|
|
9
|
-
.description('
|
|
10
|
+
.description(t('req.new.description'))
|
|
10
11
|
.action(async (title) => {
|
|
11
12
|
const { input, select } = require('@inquirer/prompts')
|
|
12
13
|
const generators = require('../generators/req')
|
|
@@ -16,14 +17,14 @@ cmd.command('new <title>')
|
|
|
16
17
|
|
|
17
18
|
if (process.stdin.isTTY) {
|
|
18
19
|
// Form 1 — título + motivação
|
|
19
|
-
content.title = await input({ message: '
|
|
20
|
-
content.motivation = await input({ message: '
|
|
20
|
+
content.title = await input({ message: t('req.new.prompt.title'), default: title })
|
|
21
|
+
content.motivation = await input({ message: t('req.new.prompt.motivation'), default: '' })
|
|
21
22
|
|
|
22
23
|
// Detectar domínios com base em título + motivação
|
|
23
24
|
const probes = generators.detectDomains(content.title + ' ' + content.motivation)
|
|
24
25
|
|
|
25
26
|
// Form 2 — critérios de aceite
|
|
26
|
-
content.criteria = await input({ message: '
|
|
27
|
+
content.criteria = await input({ message: t('req.new.prompt.criteria'), default: '- [ ]\n- [ ]' })
|
|
27
28
|
|
|
28
29
|
// Perguntas dinâmicas por probe
|
|
29
30
|
const generatedADRs = []
|
|
@@ -42,7 +43,7 @@ cmd.command('new <title>')
|
|
|
42
43
|
const basename = await adrGenerators.newADRDraft(answer)
|
|
43
44
|
if (basename) generatedADRs.push(basename)
|
|
44
45
|
} catch (e) {
|
|
45
|
-
console.warn(
|
|
46
|
+
console.warn(t('req.new.adrWarning', { slug: answer, message: e.message }))
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
}
|
|
@@ -54,14 +55,14 @@ cmd.command('new <title>')
|
|
|
54
55
|
await generators.newREQ(content)
|
|
55
56
|
|
|
56
57
|
if (content.dependsOnADRs.length > 0) {
|
|
57
|
-
console.log('
|
|
58
|
+
console.log(`\n${t('req.new.adrDraftsCreated')}`)
|
|
58
59
|
content.dependsOnADRs.forEach(adr => console.log(` -> ${adr}`))
|
|
59
|
-
console.log('
|
|
60
|
+
console.log(`\n${t('req.new.resolveADRs')}`)
|
|
60
61
|
}
|
|
61
62
|
})
|
|
62
63
|
|
|
63
64
|
cmd.command('list')
|
|
64
|
-
.description('
|
|
65
|
+
.description(t('req.list.description'))
|
|
65
66
|
.action(async () => {
|
|
66
67
|
listREQs('docs/req')
|
|
67
68
|
})
|
package/src/commands/roadmap.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { Command } = require('commander')
|
|
3
3
|
const { listRoadmaps, showRoadmap, moveRoadmap, newRoadmap } = require('../generators/roadmap')
|
|
4
|
+
const { t } = require('../i18n')
|
|
4
5
|
|
|
5
6
|
const cmd = new Command('roadmap')
|
|
6
|
-
cmd.description('
|
|
7
|
+
cmd.description(t('roadmap.description'))
|
|
7
8
|
|
|
8
9
|
cmd.command('new')
|
|
9
|
-
.description('
|
|
10
|
+
.description(t('roadmap.new.description'))
|
|
10
11
|
.option('-t, --title <title>', 'Roadmap title')
|
|
11
12
|
.option('-r, --req <path>', 'Path to the linked REQ')
|
|
12
13
|
.action(async (opts) => {
|
|
@@ -16,19 +17,19 @@ cmd.command('new')
|
|
|
16
17
|
})
|
|
17
18
|
|
|
18
19
|
cmd.command('list')
|
|
19
|
-
.description('
|
|
20
|
+
.description(t('roadmap.list.description'))
|
|
20
21
|
.action(async () => {
|
|
21
22
|
listRoadmaps()
|
|
22
23
|
})
|
|
23
24
|
|
|
24
25
|
cmd.command('show <name>')
|
|
25
|
-
.description('
|
|
26
|
+
.description(t('roadmap.show.description'))
|
|
26
27
|
.action(async (name) => {
|
|
27
28
|
showRoadmap(name)
|
|
28
29
|
})
|
|
29
30
|
|
|
30
31
|
cmd.command('move <name> <state>')
|
|
31
|
-
.description('
|
|
32
|
+
.description(t('roadmap.move.description'))
|
|
32
33
|
.action(async (name, state) => {
|
|
33
34
|
moveRoadmap(name, state)
|
|
34
35
|
})
|
package/src/commands/status.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { Command } = require('commander')
|
|
3
3
|
const { getStatus } = require('../validator')
|
|
4
|
+
const { t } = require('../i18n')
|
|
4
5
|
|
|
5
6
|
const cmd = new Command('status')
|
|
6
|
-
cmd.description('
|
|
7
|
+
cmd.description(t('status.description'))
|
|
7
8
|
cmd.action(async () => {
|
|
8
9
|
console.log(await getStatus())
|
|
9
10
|
})
|
package/src/commands/validate.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { Command } = require('commander')
|
|
3
3
|
const { validate } = require('../validator')
|
|
4
|
+
const { t } = require('../i18n')
|
|
4
5
|
|
|
5
6
|
const cmd = new Command('validate')
|
|
6
|
-
cmd.description('
|
|
7
|
+
cmd.description(t('validate.description'))
|
|
7
8
|
cmd.action(async () => {
|
|
8
9
|
const { violations, warnings } = await validate()
|
|
9
10
|
|
|
10
11
|
if (violations.length === 0 && warnings.length === 0) {
|
|
11
|
-
console.log('
|
|
12
|
+
console.log(t('validate.ok'))
|
|
12
13
|
return
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
if (violations.length > 0) {
|
|
16
|
-
console.log(`\n
|
|
17
|
+
console.log(`\n${t('validate.violations', { count: violations.length })}`)
|
|
17
18
|
violations.forEach(v => console.log(` • ${v}`))
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
if (warnings.length > 0) {
|
|
21
|
-
console.log(`\n
|
|
22
|
+
console.log(`\n${t('validate.warnings', { count: warnings.length })}`)
|
|
22
23
|
warnings.forEach(w => console.log(` • ${w}`))
|
|
23
24
|
}
|
|
24
25
|
|
package/src/generators/init.js
CHANGED
|
@@ -29,6 +29,7 @@ async function scaffold(cfg) {
|
|
|
29
29
|
generateCIWorkflow(cfg)
|
|
30
30
|
generateGitHooks(cfg)
|
|
31
31
|
generateClaudeMD(cfg)
|
|
32
|
+
if (cfg.backend === 'java') generatePomXml(cfg)
|
|
32
33
|
generateClaudeCommands()
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -43,6 +44,7 @@ function writeTrackfwConfig(cfg) {
|
|
|
43
44
|
|
|
44
45
|
frontend: ${cfg.frontend || ''}
|
|
45
46
|
backend: ${cfg.backend || ''}
|
|
47
|
+
backend_framework: ${cfg.backendFramework || ''}
|
|
46
48
|
pkg_manager: ${cfg.pkgManager || ''}
|
|
47
49
|
hooks: ${cfg.hooks || ''}
|
|
48
50
|
ci: ${cfg.ci || ''}
|
|
@@ -193,6 +195,63 @@ function generateLefthookHook() {
|
|
|
193
195
|
console.log(' ✓ lefthook.yml')
|
|
194
196
|
}
|
|
195
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
|
+
|
|
196
255
|
// ---------------------------------------------------------------------------
|
|
197
256
|
// CLAUDE.md
|
|
198
257
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
|
|
5
|
+
function detectLocale() {
|
|
6
|
+
const raw = process.env.LANG || process.env.LC_ALL || process.env.LANGUAGE || ''
|
|
7
|
+
// Mapeia pt_BR.UTF-8 → pt-BR, es_ES.UTF-8 → es-ES, en_US.UTF-8 → en-US
|
|
8
|
+
const map = { pt: 'pt-BR', es: 'es-ES' }
|
|
9
|
+
const code = raw.split('.')[0].replace('_', '-') // pt-BR
|
|
10
|
+
const lang = code.split('-')[0] // pt
|
|
11
|
+
if (map[lang]) return map[lang]
|
|
12
|
+
// Fallback para Windows: usar Intl
|
|
13
|
+
try {
|
|
14
|
+
const loc = Intl.DateTimeFormat().resolvedOptions().locale
|
|
15
|
+
const l = loc.split('-')[0]
|
|
16
|
+
if (map[l]) return map[l]
|
|
17
|
+
} catch (_) {}
|
|
18
|
+
return 'en-US'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let _locale = null
|
|
22
|
+
let _messages = null
|
|
23
|
+
|
|
24
|
+
function load() {
|
|
25
|
+
if (_messages) return
|
|
26
|
+
_locale = detectLocale()
|
|
27
|
+
const filePath = path.join(__dirname, 'locales', `${_locale}.json`)
|
|
28
|
+
const fallback = path.join(__dirname, 'locales', 'en-US.json')
|
|
29
|
+
try {
|
|
30
|
+
_messages = JSON.parse(fs.readFileSync(fs.existsSync(filePath) ? filePath : fallback, 'utf8'))
|
|
31
|
+
} catch (_) {
|
|
32
|
+
_messages = {}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function t(key, vars = {}) {
|
|
37
|
+
load()
|
|
38
|
+
const keys = key.split('.')
|
|
39
|
+
let val = _messages
|
|
40
|
+
for (const k of keys) {
|
|
41
|
+
val = val?.[k]
|
|
42
|
+
if (val === undefined) break
|
|
43
|
+
}
|
|
44
|
+
if (typeof val !== 'string') return key
|
|
45
|
+
return val.replace(/\{\{(\w+)\}\}/g, (_, k) => vars[k] ?? `{{${k}}}`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function locale() {
|
|
49
|
+
load()
|
|
50
|
+
return _locale
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = { t, locale }
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"init": {
|
|
3
|
+
"description": "Initialize trackfw governance in the current project",
|
|
4
|
+
"prompt": {
|
|
5
|
+
"projectName": "Project name?",
|
|
6
|
+
"projectType": "Project type?",
|
|
7
|
+
"frontendStack": "Frontend stack?",
|
|
8
|
+
"pkgManager": "Package manager?",
|
|
9
|
+
"backendLang": "Backend language?",
|
|
10
|
+
"backendFramework": "Backend framework?",
|
|
11
|
+
"gitHooks": "Git hooks?",
|
|
12
|
+
"ci": "CI system?",
|
|
13
|
+
"aiTools": "Which AI assistants do you use?",
|
|
14
|
+
"projectType_fullstack": "Full-stack (frontend + backend)",
|
|
15
|
+
"projectType_frontend": "Frontend only",
|
|
16
|
+
"projectType_backend": "Backend only",
|
|
17
|
+
"projectType_governance": "Governance only (no build stack)"
|
|
18
|
+
},
|
|
19
|
+
"success": "✓ trackfw initialized — run 'trackfw status' to see your governance state."
|
|
20
|
+
},
|
|
21
|
+
"adr": {
|
|
22
|
+
"description": "Manage Architecture Decision Records",
|
|
23
|
+
"new": {
|
|
24
|
+
"description": "Create a new Architecture Decision Record",
|
|
25
|
+
"prompt": {
|
|
26
|
+
"title": "ADR title?",
|
|
27
|
+
"status": "Initial status?",
|
|
28
|
+
"context": "Context (what motivates this decision)?",
|
|
29
|
+
"decision": "Decision (what was decided)?",
|
|
30
|
+
"consequences": "Consequences (positive and negative)?",
|
|
31
|
+
"alternatives": "Alternatives considered?"
|
|
32
|
+
},
|
|
33
|
+
"created": "✓ ADR created: {{path}}"
|
|
34
|
+
},
|
|
35
|
+
"list": {
|
|
36
|
+
"description": "List all ADRs with status",
|
|
37
|
+
"empty": "No ADRs found in docs/adr/"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"req": {
|
|
41
|
+
"description": "Manage Requirements",
|
|
42
|
+
"new": {
|
|
43
|
+
"description": "Create a new requirement",
|
|
44
|
+
"prompt": {
|
|
45
|
+
"title": "Project requirement",
|
|
46
|
+
"motivation": "Motivation (why is this needed)?",
|
|
47
|
+
"criteria": "Acceptance Criteria (one per line)",
|
|
48
|
+
"domainQuestion_authentication": "How will users authenticate?",
|
|
49
|
+
"domainQuestion_ui": "Is there an existing UI framework or design system?",
|
|
50
|
+
"domainQuestion_persistence": "Which database engine will be used?",
|
|
51
|
+
"domainQuestion_api": "Which API protocol will be used?",
|
|
52
|
+
"domainQuestion_deploy": "What is the deployment target?",
|
|
53
|
+
"domainQuestion_events": "Which event broker will be used?"
|
|
54
|
+
},
|
|
55
|
+
"detectedDomains": "Detected domains: {{domains}}",
|
|
56
|
+
"created": "✓ REQ created: {{path}}",
|
|
57
|
+
"adrDraftsCreated": "ADR drafts created:",
|
|
58
|
+
"resolveADRs": "Resolve these ADRs (set Status: Accepted) before creating a roadmap.",
|
|
59
|
+
"adrWarning": "warning: could not create ADR draft for {{slug}}: {{message}}"
|
|
60
|
+
},
|
|
61
|
+
"list": {
|
|
62
|
+
"description": "List all REQs with status",
|
|
63
|
+
"empty": "No REQs found in docs/req/"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"roadmap": {
|
|
67
|
+
"description": "Manage Roadmaps",
|
|
68
|
+
"list": {
|
|
69
|
+
"description": "List all roadmaps grouped by state",
|
|
70
|
+
"empty": "No roadmaps found."
|
|
71
|
+
},
|
|
72
|
+
"show": {
|
|
73
|
+
"description": "Show a roadmap by name (partial match)",
|
|
74
|
+
"notFound": "Roadmap not found: {{name}}"
|
|
75
|
+
},
|
|
76
|
+
"move": {
|
|
77
|
+
"description": "Move a roadmap between states (backlog|wip|blocked|done|abandoned)",
|
|
78
|
+
"success": "✓ Moved {{name}} → {{state}}",
|
|
79
|
+
"notFound": "Roadmap not found: {{name}}"
|
|
80
|
+
},
|
|
81
|
+
"new": {
|
|
82
|
+
"description": "Create a new roadmap from a REQ",
|
|
83
|
+
"created": "✓ Roadmap created: {{path}}"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"validate": {
|
|
87
|
+
"description": "Validate governance rules (use as CI gate)",
|
|
88
|
+
"ok": "✓ No violations found.",
|
|
89
|
+
"violations": "✗ Violations ({{count}}):",
|
|
90
|
+
"warnings": "⚠ Warnings ({{count}}):"
|
|
91
|
+
},
|
|
92
|
+
"status": {
|
|
93
|
+
"description": "Show project governance status"
|
|
94
|
+
},
|
|
95
|
+
"log": {
|
|
96
|
+
"description": "Show roadmap state transition history",
|
|
97
|
+
"empty": "No transitions recorded yet.",
|
|
98
|
+
"tail": "Number of recent transitions to show",
|
|
99
|
+
"header": "── trackfw log ─────────────────────────"
|
|
100
|
+
},
|
|
101
|
+
"plugins": {
|
|
102
|
+
"description": "Manage trackfw plugins",
|
|
103
|
+
"list": {
|
|
104
|
+
"description": "List installed plugins",
|
|
105
|
+
"empty": "No plugins installed. Use `trackfw plugins add <user/repo>` to install one."
|
|
106
|
+
},
|
|
107
|
+
"add": {
|
|
108
|
+
"description": "Install a plugin from GitHub Releases (user/repo or user/repo@tag)",
|
|
109
|
+
"installing": "Installing plugin from {{repo}}...",
|
|
110
|
+
"success": "Plugin \"{{name}}\" installed successfully."
|
|
111
|
+
},
|
|
112
|
+
"remove": {
|
|
113
|
+
"description": "Remove an installed plugin",
|
|
114
|
+
"success": "Plugin \"{{name}}\" removed."
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"errors": {
|
|
118
|
+
"notFound": "Not found: {{path}}",
|
|
119
|
+
"downloadFailed": "download failed: HTTP {{status}} for {{url}}",
|
|
120
|
+
"pluginNotFound": "plugin \"{{name}}\" not found"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"init": {
|
|
3
|
+
"description": "Inicializa la gobernanza trackfw en el proyecto actual",
|
|
4
|
+
"prompt": {
|
|
5
|
+
"projectName": "¿Nombre del proyecto?",
|
|
6
|
+
"projectType": "¿Tipo de proyecto?",
|
|
7
|
+
"frontendStack": "¿Stack de frontend?",
|
|
8
|
+
"pkgManager": "¿Gestor de paquetes?",
|
|
9
|
+
"backendLang": "¿Lenguaje de backend?",
|
|
10
|
+
"backendFramework": "¿Framework de backend?",
|
|
11
|
+
"gitHooks": "¿Git hooks?",
|
|
12
|
+
"ci": "¿Sistema de CI?",
|
|
13
|
+
"aiTools": "¿Qué asistentes de IA usas?",
|
|
14
|
+
"projectType_fullstack": "Full-stack (frontend + backend)",
|
|
15
|
+
"projectType_frontend": "Solo frontend",
|
|
16
|
+
"projectType_backend": "Solo backend",
|
|
17
|
+
"projectType_governance": "Solo gobernanza (sin stack de build)"
|
|
18
|
+
},
|
|
19
|
+
"success": "✓ trackfw inicializado — ejecuta 'trackfw status' para ver el estado de gobernanza."
|
|
20
|
+
},
|
|
21
|
+
"adr": {
|
|
22
|
+
"description": "Gestionar Architecture Decision Records",
|
|
23
|
+
"new": {
|
|
24
|
+
"description": "Crear un nuevo Architecture Decision Record",
|
|
25
|
+
"prompt": {
|
|
26
|
+
"title": "¿Título del ADR?",
|
|
27
|
+
"status": "¿Estado inicial?",
|
|
28
|
+
"context": "¿Contexto (qué motiva esta decisión)?",
|
|
29
|
+
"decision": "¿Decisión (qué fue decidido)?",
|
|
30
|
+
"consequences": "¿Consecuencias (positivas y negativas)?",
|
|
31
|
+
"alternatives": "¿Alternativas consideradas?"
|
|
32
|
+
},
|
|
33
|
+
"created": "✓ ADR creado: {{path}}"
|
|
34
|
+
},
|
|
35
|
+
"list": {
|
|
36
|
+
"description": "Listar todos los ADRs con estado",
|
|
37
|
+
"empty": "No se encontraron ADRs en docs/adr/"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"req": {
|
|
41
|
+
"description": "Gestionar Requisitos",
|
|
42
|
+
"new": {
|
|
43
|
+
"description": "Crear un nuevo requisito",
|
|
44
|
+
"prompt": {
|
|
45
|
+
"title": "Requisito del proyecto",
|
|
46
|
+
"motivation": "¿Motivación (por qué lo necesitamos)?",
|
|
47
|
+
"criteria": "Criterios de aceptación (uno por línea)",
|
|
48
|
+
"domainQuestion_authentication": "¿Cómo se autenticarán los usuarios?",
|
|
49
|
+
"domainQuestion_ui": "¿Existe un framework de UI o design system ya elegido?",
|
|
50
|
+
"domainQuestion_persistence": "¿Qué motor de base de datos se usará?",
|
|
51
|
+
"domainQuestion_api": "¿Qué protocolo de API se usará?",
|
|
52
|
+
"domainQuestion_deploy": "¿Cuál es el destino de despliegue?",
|
|
53
|
+
"domainQuestion_events": "¿Qué message broker se usará?"
|
|
54
|
+
},
|
|
55
|
+
"detectedDomains": "Dominios detectados: {{domains}}",
|
|
56
|
+
"created": "✓ REQ creado: {{path}}",
|
|
57
|
+
"adrDraftsCreated": "ADR borradores creados:",
|
|
58
|
+
"resolveADRs": "Resuelve estos ADRs (establece Status: Accepted) antes de crear un roadmap.",
|
|
59
|
+
"adrWarning": "advertencia: no se pudo crear ADR borrador para {{slug}}: {{message}}"
|
|
60
|
+
},
|
|
61
|
+
"list": {
|
|
62
|
+
"description": "Listar todos los REQs con estado",
|
|
63
|
+
"empty": "No se encontraron REQs en docs/req/"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"roadmap": {
|
|
67
|
+
"description": "Gestionar Roadmaps",
|
|
68
|
+
"list": {
|
|
69
|
+
"description": "Listar todos los roadmaps agrupados por estado",
|
|
70
|
+
"empty": "No se encontraron roadmaps."
|
|
71
|
+
},
|
|
72
|
+
"show": {
|
|
73
|
+
"description": "Mostrar roadmap por nombre (coincidencia parcial)",
|
|
74
|
+
"notFound": "Roadmap no encontrado: {{name}}"
|
|
75
|
+
},
|
|
76
|
+
"move": {
|
|
77
|
+
"description": "Mover un roadmap entre estados (backlog|wip|blocked|done|abandoned)",
|
|
78
|
+
"success": "✓ Movido {{name}} → {{state}}",
|
|
79
|
+
"notFound": "Roadmap no encontrado: {{name}}"
|
|
80
|
+
},
|
|
81
|
+
"new": {
|
|
82
|
+
"description": "Crear un nuevo roadmap desde un REQ",
|
|
83
|
+
"created": "✓ Roadmap creado: {{path}}"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"validate": {
|
|
87
|
+
"description": "Validar reglas de gobernanza (úsalo como gate de CI)",
|
|
88
|
+
"ok": "✓ No se encontraron violaciones.",
|
|
89
|
+
"violations": "✗ Violaciones ({{count}}):",
|
|
90
|
+
"warnings": "⚠ Avisos ({{count}}):"
|
|
91
|
+
},
|
|
92
|
+
"status": {
|
|
93
|
+
"description": "Mostrar el estado actual de gobernanza del proyecto"
|
|
94
|
+
},
|
|
95
|
+
"log": {
|
|
96
|
+
"description": "Mostrar historial de transiciones de estado de los roadmaps",
|
|
97
|
+
"empty": "Aún no hay transiciones registradas.",
|
|
98
|
+
"tail": "Número de transiciones recientes a mostrar",
|
|
99
|
+
"header": "── trackfw log ─────────────────────────"
|
|
100
|
+
},
|
|
101
|
+
"plugins": {
|
|
102
|
+
"description": "Gestionar plugins de trackfw",
|
|
103
|
+
"list": {
|
|
104
|
+
"description": "Listar plugins instalados",
|
|
105
|
+
"empty": "No hay plugins instalados. Usa `trackfw plugins add <user/repo>` para instalar uno."
|
|
106
|
+
},
|
|
107
|
+
"add": {
|
|
108
|
+
"description": "Instalar un plugin desde GitHub Releases (user/repo o user/repo@tag)",
|
|
109
|
+
"installing": "Instalando plugin desde {{repo}}...",
|
|
110
|
+
"success": "Plugin \"{{name}}\" instalado correctamente."
|
|
111
|
+
},
|
|
112
|
+
"remove": {
|
|
113
|
+
"description": "Eliminar un plugin instalado",
|
|
114
|
+
"success": "Plugin \"{{name}}\" eliminado."
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"errors": {
|
|
118
|
+
"notFound": "No encontrado: {{path}}",
|
|
119
|
+
"downloadFailed": "fallo en la descarga: HTTP {{status}} para {{url}}",
|
|
120
|
+
"pluginNotFound": "plugin \"{{name}}\" no encontrado"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"init": {
|
|
3
|
+
"description": "Inicializa a governança trackfw no projeto atual",
|
|
4
|
+
"prompt": {
|
|
5
|
+
"projectName": "Nome do projeto?",
|
|
6
|
+
"projectType": "Tipo de projeto?",
|
|
7
|
+
"frontendStack": "Stack de frontend?",
|
|
8
|
+
"pkgManager": "Gerenciador de pacotes?",
|
|
9
|
+
"backendLang": "Linguagem de backend?",
|
|
10
|
+
"backendFramework": "Framework de backend?",
|
|
11
|
+
"gitHooks": "Git hooks?",
|
|
12
|
+
"ci": "Sistema de CI?",
|
|
13
|
+
"aiTools": "Quais assistentes de IA você usa?",
|
|
14
|
+
"projectType_fullstack": "Full-stack (frontend + backend)",
|
|
15
|
+
"projectType_frontend": "Somente frontend",
|
|
16
|
+
"projectType_backend": "Somente backend",
|
|
17
|
+
"projectType_governance": "Somente governança (sem stack de build)"
|
|
18
|
+
},
|
|
19
|
+
"success": "✓ trackfw inicializado — execute 'trackfw status' para ver o estado de governança."
|
|
20
|
+
},
|
|
21
|
+
"adr": {
|
|
22
|
+
"description": "Gerenciar Architecture Decision Records",
|
|
23
|
+
"new": {
|
|
24
|
+
"description": "Criar um novo Architecture Decision Record",
|
|
25
|
+
"prompt": {
|
|
26
|
+
"title": "Título do ADR?",
|
|
27
|
+
"status": "Status inicial?",
|
|
28
|
+
"context": "Contexto (o que motiva esta decisão)?",
|
|
29
|
+
"decision": "Decisão (o que foi decidido)?",
|
|
30
|
+
"consequences": "Consequências (positivas e negativas)?",
|
|
31
|
+
"alternatives": "Alternativas consideradas?"
|
|
32
|
+
},
|
|
33
|
+
"created": "✓ ADR criado: {{path}}"
|
|
34
|
+
},
|
|
35
|
+
"list": {
|
|
36
|
+
"description": "Listar todos os ADRs com status",
|
|
37
|
+
"empty": "Nenhum ADR encontrado em docs/adr/"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"req": {
|
|
41
|
+
"description": "Gerenciar Requisitos",
|
|
42
|
+
"new": {
|
|
43
|
+
"description": "Criar um novo requisito",
|
|
44
|
+
"prompt": {
|
|
45
|
+
"title": "Requisito do projeto",
|
|
46
|
+
"motivation": "Motivação (por que isso é necessário)?",
|
|
47
|
+
"criteria": "Critérios de aceite (um por linha)",
|
|
48
|
+
"domainQuestion_authentication": "Como os usuários serão autenticados?",
|
|
49
|
+
"domainQuestion_ui": "Existe um framework de UI ou design system já escolhido?",
|
|
50
|
+
"domainQuestion_persistence": "Qual engine de banco de dados será usada?",
|
|
51
|
+
"domainQuestion_api": "Qual protocolo de API será usado?",
|
|
52
|
+
"domainQuestion_deploy": "Qual é o destino de deploy?",
|
|
53
|
+
"domainQuestion_events": "Qual message broker será usado?"
|
|
54
|
+
},
|
|
55
|
+
"detectedDomains": "Domínios detectados: {{domains}}",
|
|
56
|
+
"created": "✓ REQ criado: {{path}}",
|
|
57
|
+
"adrDraftsCreated": "ADR drafts criados:",
|
|
58
|
+
"resolveADRs": "Resolva estes ADRs (defina Status: Accepted) antes de criar um roadmap.",
|
|
59
|
+
"adrWarning": "aviso: não foi possível criar ADR draft para {{slug}}: {{message}}"
|
|
60
|
+
},
|
|
61
|
+
"list": {
|
|
62
|
+
"description": "Listar todos os REQs com status",
|
|
63
|
+
"empty": "Nenhum REQ encontrado em docs/req/"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"roadmap": {
|
|
67
|
+
"description": "Gerenciar Roadmaps",
|
|
68
|
+
"list": {
|
|
69
|
+
"description": "Listar todos os roadmaps agrupados por estado",
|
|
70
|
+
"empty": "Nenhum roadmap encontrado."
|
|
71
|
+
},
|
|
72
|
+
"show": {
|
|
73
|
+
"description": "Exibir roadmap pelo nome (correspondência parcial)",
|
|
74
|
+
"notFound": "Roadmap não encontrado: {{name}}"
|
|
75
|
+
},
|
|
76
|
+
"move": {
|
|
77
|
+
"description": "Mover um roadmap entre estados (backlog|wip|blocked|done|abandoned)",
|
|
78
|
+
"success": "✓ Movido {{name}} → {{state}}",
|
|
79
|
+
"notFound": "Roadmap não encontrado: {{name}}"
|
|
80
|
+
},
|
|
81
|
+
"new": {
|
|
82
|
+
"description": "Criar um novo roadmap a partir de uma REQ",
|
|
83
|
+
"created": "✓ Roadmap criado: {{path}}"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"validate": {
|
|
87
|
+
"description": "Validar regras de governança (use como gate de CI)",
|
|
88
|
+
"ok": "✓ Nenhuma violação encontrada.",
|
|
89
|
+
"violations": "✗ Violações ({{count}}):",
|
|
90
|
+
"warnings": "⚠ Avisos ({{count}}):"
|
|
91
|
+
},
|
|
92
|
+
"status": {
|
|
93
|
+
"description": "Exibir o estado atual de governança do projeto"
|
|
94
|
+
},
|
|
95
|
+
"log": {
|
|
96
|
+
"description": "Exibir histórico de transições de estado dos roadmaps",
|
|
97
|
+
"empty": "Nenhuma transição registrada ainda.",
|
|
98
|
+
"tail": "Número de transições recentes a exibir",
|
|
99
|
+
"header": "── trackfw log ─────────────────────────"
|
|
100
|
+
},
|
|
101
|
+
"plugins": {
|
|
102
|
+
"description": "Gerenciar plugins do trackfw",
|
|
103
|
+
"list": {
|
|
104
|
+
"description": "Listar plugins instalados",
|
|
105
|
+
"empty": "Nenhum plugin instalado. Use `trackfw plugins add <user/repo>` para instalar um."
|
|
106
|
+
},
|
|
107
|
+
"add": {
|
|
108
|
+
"description": "Instalar um plugin do GitHub Releases (user/repo ou user/repo@tag)",
|
|
109
|
+
"installing": "Instalando plugin de {{repo}}...",
|
|
110
|
+
"success": "Plugin \"{{name}}\" instalado com sucesso."
|
|
111
|
+
},
|
|
112
|
+
"remove": {
|
|
113
|
+
"description": "Remover um plugin instalado",
|
|
114
|
+
"success": "Plugin \"{{name}}\" removido."
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"errors": {
|
|
118
|
+
"notFound": "Não encontrado: {{path}}",
|
|
119
|
+
"downloadFailed": "falha no download: HTTP {{status}} para {{url}}",
|
|
120
|
+
"pluginNotFound": "plugin \"{{name}}\" não encontrado"
|
|
121
|
+
}
|
|
122
|
+
}
|