trackfw 2.8.0 → 2.9.1
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/package.json +1 -1
- package/src/commands/discover.js +30 -0
- package/src/commands/index.js +1 -0
- package/src/commands/update.js +115 -0
- package/src/generators/init.js +226 -6
package/package.json
CHANGED
package/src/commands/discover.js
CHANGED
|
@@ -388,6 +388,13 @@ cmd.action((opts) => {
|
|
|
388
388
|
} catch (e) {
|
|
389
389
|
console.log(`⚠ gates install partial: ${e.message}`);
|
|
390
390
|
}
|
|
391
|
+
try {
|
|
392
|
+
const generators = require('../generators/init');
|
|
393
|
+
generators.injectRulesDetected(cwd);
|
|
394
|
+
console.log('✓ trackfw rules injected into agent config files');
|
|
395
|
+
} catch (e) {
|
|
396
|
+
console.log(`⚠ agent rules inject partial: ${e.message}`);
|
|
397
|
+
}
|
|
391
398
|
}
|
|
392
399
|
}
|
|
393
400
|
|
|
@@ -403,7 +410,30 @@ cmd.action((opts) => {
|
|
|
403
410
|
}
|
|
404
411
|
});
|
|
405
412
|
|
|
413
|
+
function writeCIWorkflowForce(rootDir) {
|
|
414
|
+
const workflowsDir = path.join(rootDir, '.github', 'workflows');
|
|
415
|
+
if (!isDir(workflowsDir)) fs.mkdirSync(workflowsDir, { recursive: true });
|
|
416
|
+
const dest = path.join(workflowsDir, 'trackfw-validate.yml');
|
|
417
|
+
const content = `name: trackfw validate
|
|
418
|
+
on: [push, pull_request]
|
|
419
|
+
jobs:
|
|
420
|
+
governance:
|
|
421
|
+
runs-on: ubuntu-latest
|
|
422
|
+
steps:
|
|
423
|
+
- uses: actions/checkout@v4
|
|
424
|
+
- uses: actions/setup-go@v5
|
|
425
|
+
with:
|
|
426
|
+
go-version: "1.22"
|
|
427
|
+
- run: go install github.com/kgsaran/trackfw/cmd/trackfw@latest
|
|
428
|
+
- run: trackfw validate
|
|
429
|
+
`;
|
|
430
|
+
fs.writeFileSync(dest, content, 'utf8');
|
|
431
|
+
}
|
|
432
|
+
|
|
406
433
|
module.exports = cmd;
|
|
407
434
|
module.exports.scan = scan;
|
|
408
435
|
module.exports.generateYAML = generateYAML;
|
|
409
436
|
module.exports.generateBootstrapLog = generateBootstrapLog;
|
|
437
|
+
module.exports.writeValidateScript = writeValidateScript;
|
|
438
|
+
module.exports.writeCIWorkflow = writeCIWorkflow;
|
|
439
|
+
module.exports.writeCIWorkflowForce = writeCIWorkflowForce;
|
package/src/commands/index.js
CHANGED
|
@@ -19,6 +19,7 @@ function createProgram() {
|
|
|
19
19
|
program.addCommand(require('./log'))
|
|
20
20
|
program.addCommand(require('./plugins'))
|
|
21
21
|
program.addCommand(require('./discover'))
|
|
22
|
+
program.addCommand(require('./update'))
|
|
22
23
|
program.addCommand(require('./metrics'))
|
|
23
24
|
program.addCommand(require('./sync'))
|
|
24
25
|
program.addCommand(require('./context'))
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
function readUpdateConfig(rootDir) {
|
|
8
|
+
const yaml = path.join(rootDir, 'trackfw.yaml');
|
|
9
|
+
if (!fs.existsSync(yaml)) return {};
|
|
10
|
+
const lines = fs.readFileSync(yaml, 'utf8').split('\n');
|
|
11
|
+
const cfg = {};
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
const trimmed = line.trim();
|
|
14
|
+
if (trimmed.startsWith('#')) continue;
|
|
15
|
+
const idx = trimmed.indexOf(':');
|
|
16
|
+
if (idx < 0) continue;
|
|
17
|
+
const key = trimmed.slice(0, idx).trim();
|
|
18
|
+
let val = trimmed.slice(idx + 1).trim();
|
|
19
|
+
const ci = val.indexOf(' #');
|
|
20
|
+
if (ci >= 0) val = val.slice(0, ci).trim();
|
|
21
|
+
cfg[key] = val;
|
|
22
|
+
}
|
|
23
|
+
return cfg;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function updateHooksSurgical(cfg, rootDir) {
|
|
27
|
+
const hooks = cfg.hooks || '';
|
|
28
|
+
if (hooks === 'husky') {
|
|
29
|
+
const hookPath = path.join(rootDir, '.husky', 'pre-commit');
|
|
30
|
+
const content = fs.existsSync(hookPath) ? fs.readFileSync(hookPath, 'utf8') : '';
|
|
31
|
+
if (content.includes('trackfw validate')) {
|
|
32
|
+
console.log(' ✓ .husky/pre-commit — trackfw validate já presente');
|
|
33
|
+
} else {
|
|
34
|
+
fs.mkdirSync(path.join(rootDir, '.husky'), { recursive: true });
|
|
35
|
+
fs.appendFileSync(hookPath, '\ntrackfw validate\n', 'utf8');
|
|
36
|
+
try { fs.chmodSync(hookPath, 0o755); } catch (_) {}
|
|
37
|
+
console.log(' ✓ .husky/pre-commit — trackfw validate injetado');
|
|
38
|
+
}
|
|
39
|
+
} else if (hooks === 'lefthook') {
|
|
40
|
+
const lefthookPath = path.join(rootDir, 'lefthook.yml');
|
|
41
|
+
const content = fs.existsSync(lefthookPath) ? fs.readFileSync(lefthookPath, 'utf8') : '';
|
|
42
|
+
if (content.includes('trackfw-validate:') || content.includes('trackfw validate')) {
|
|
43
|
+
console.log(' ✓ lefthook.yml — trackfw já presente');
|
|
44
|
+
} else {
|
|
45
|
+
fs.appendFileSync(lefthookPath, '\npre-commit:\n commands:\n trackfw-validate:\n run: trackfw validate\n', 'utf8');
|
|
46
|
+
console.log(' ✓ lefthook.yml — trackfw-validate injetado');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const cmd = new Command('update');
|
|
52
|
+
cmd.description('Update trackfw-managed artifacts to the current version');
|
|
53
|
+
cmd.action(() => {
|
|
54
|
+
const cwd = process.cwd();
|
|
55
|
+
const yaml = path.join(cwd, 'trackfw.yaml');
|
|
56
|
+
if (!fs.existsSync(yaml)) {
|
|
57
|
+
console.error('✗ trackfw.yaml não encontrado — execute trackfw init primeiro');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const cfg = readUpdateConfig(cwd);
|
|
62
|
+
const generators = require('../generators/init');
|
|
63
|
+
const discover = require('./discover');
|
|
64
|
+
|
|
65
|
+
console.log('trackfw update — re-aplicando templates atuais...\n');
|
|
66
|
+
|
|
67
|
+
// 1. Agent rules (marker-delimited, idempotent)
|
|
68
|
+
try {
|
|
69
|
+
generators.injectRulesDetected(cwd);
|
|
70
|
+
console.log(' ✓ agent rules atualizadas');
|
|
71
|
+
} catch (e) {
|
|
72
|
+
console.log(` ⚠ agent rules: ${e.message}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 2. Validate script (trackfw-owned, overwrite)
|
|
76
|
+
try {
|
|
77
|
+
discover.writeValidateScript(cwd);
|
|
78
|
+
console.log(' ✓ scripts/trackfw-validate.sh atualizado');
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.log(` ⚠ validate script: ${e.message}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 3. CI workflow (trackfw-owned, overwrite)
|
|
84
|
+
if (cfg.ci === 'github-actions' || cfg.ci === 'github_actions') {
|
|
85
|
+
try {
|
|
86
|
+
discover.writeCIWorkflowForce(cwd);
|
|
87
|
+
console.log(' ✓ .github/workflows/trackfw-validate.yml atualizado');
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.log(` ⚠ CI workflow: ${e.message}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 4. Git hooks (surgical)
|
|
94
|
+
updateHooksSurgical(cfg, cwd);
|
|
95
|
+
|
|
96
|
+
// 5. Claude commands (force overwrite)
|
|
97
|
+
try {
|
|
98
|
+
generators.generateClaudeCommandsForce(cwd);
|
|
99
|
+
console.log(' ✓ .claude/commands/trackfw/ atualizado');
|
|
100
|
+
} catch (e) {
|
|
101
|
+
console.log(` ⚠ Claude commands: ${e.message}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 6. Global skill (force overwrite)
|
|
105
|
+
try {
|
|
106
|
+
generators.installSkillsForce(cwd);
|
|
107
|
+
console.log(' ✓ skill global atualizada');
|
|
108
|
+
} catch (e) {
|
|
109
|
+
console.log(` ⚠ skills: ${e.message}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log('\n✓ trackfw update concluído');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
module.exports = cmd;
|
package/src/generators/init.js
CHANGED
|
@@ -301,6 +301,136 @@ function generatePomXml(cfg) {
|
|
|
301
301
|
console.log(' ✓ pom.xml')
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// ---------------------------------------------------------------------------
|
|
305
|
+
// trackfw rules inject-or-update (idempotente via marcadores HTML)
|
|
306
|
+
// ---------------------------------------------------------------------------
|
|
307
|
+
|
|
308
|
+
const RULES_START = '<!-- trackfw:rules:start -->'
|
|
309
|
+
const RULES_END = '<!-- trackfw:rules:end -->'
|
|
310
|
+
|
|
311
|
+
const AGENT_FILES = {
|
|
312
|
+
claude: 'CLAUDE.md',
|
|
313
|
+
codex: 'AGENTS.md',
|
|
314
|
+
gemini: 'GEMINI.md',
|
|
315
|
+
copilot: '.github/copilot-instructions.md',
|
|
316
|
+
windsurf: '.windsurfrules',
|
|
317
|
+
amazonq: '.amazonq/developer/guidelines.md',
|
|
318
|
+
cursor: '.cursor/rules/trackfw.mdc',
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const AGENT_HEADERS = {
|
|
322
|
+
claude: '# Project Instructions\n',
|
|
323
|
+
codex: '# Project Instructions\n',
|
|
324
|
+
gemini: '# Project Instructions\n',
|
|
325
|
+
copilot: '# GitHub Copilot Instructions\n',
|
|
326
|
+
windsurf: '# Windsurf Rules\n',
|
|
327
|
+
amazonq: '# Amazon Q Developer Guidelines\n',
|
|
328
|
+
cursor: '---\ndescription: trackfw governance rules\nglob: "**/*"\nalwaysApply: true\n---\n',
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function trackfwRulesBlock() {
|
|
332
|
+
return RULES_START + `
|
|
333
|
+
## trackfw — Governance Rules
|
|
334
|
+
|
|
335
|
+
This project uses **trackfw** for AI-native delivery governance.
|
|
336
|
+
Chain: \`ADR → REQ → ROADMAP\` · States: \`backlog / wip / blocked / done / abandoned\`
|
|
337
|
+
|
|
338
|
+
### Agent Protocol
|
|
339
|
+
1. **Before starting:** run \`trackfw context\` · read \`docs/agents-working-context.md\`
|
|
340
|
+
2. **After finishing:** update \`docs/agents-working-context.md\` with what changed
|
|
341
|
+
3. **Before PR:** \`trackfw validate\` must pass
|
|
342
|
+
|
|
343
|
+
### Key Commands
|
|
344
|
+
- \`trackfw context\` — current governance state (always run first)
|
|
345
|
+
- \`trackfw status\` — all artifacts and states
|
|
346
|
+
- \`trackfw validate\` — governance consistency check
|
|
347
|
+
- \`trackfw roadmap move <name> <state>\` — transition roadmap state
|
|
348
|
+
- \`trackfw serve\` — live Kanban board at http://localhost:4080
|
|
349
|
+
|
|
350
|
+
### Attention Signal (when you need user input during a task)
|
|
351
|
+
Write \`docs/roadmaps/.trackfw-attention.json\`:
|
|
352
|
+
\`\`\`json
|
|
353
|
+
{"roadmap":"file.md","ml":"ML-1A","message":"what you need","level":"action_required","timestamp":"ISO8601Z"}
|
|
354
|
+
\`\`\`
|
|
355
|
+
Delete the file when resolved. Visible as a live banner in \`trackfw serve\`.
|
|
356
|
+
` + RULES_END
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* injectOrUpdateRules — injeta ou atualiza o bloco de regras trackfw no arquivo.
|
|
361
|
+
* - Arquivo não existe: cria com headerIfNew + bloco de regras
|
|
362
|
+
* - Arquivo existe, sem marcador: appenda o bloco no final
|
|
363
|
+
* - Arquivo existe, com marcador: substitui conteúdo entre marcadores
|
|
364
|
+
*/
|
|
365
|
+
function injectOrUpdateRules(filePath, headerIfNew) {
|
|
366
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
367
|
+
|
|
368
|
+
const block = trackfwRulesBlock()
|
|
369
|
+
|
|
370
|
+
if (!fs.existsSync(filePath)) {
|
|
371
|
+
let content = headerIfNew || ''
|
|
372
|
+
if (content && !content.endsWith('\n')) content += '\n'
|
|
373
|
+
content += '\n' + block + '\n'
|
|
374
|
+
fs.writeFileSync(filePath, content, 'utf8')
|
|
375
|
+
return
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
let content = fs.readFileSync(filePath, 'utf8')
|
|
379
|
+
|
|
380
|
+
const start = content.indexOf(RULES_START)
|
|
381
|
+
if (start === -1) {
|
|
382
|
+
// No marker: append
|
|
383
|
+
if (!content.endsWith('\n')) content += '\n'
|
|
384
|
+
content += '\n' + block + '\n'
|
|
385
|
+
fs.writeFileSync(filePath, content, 'utf8')
|
|
386
|
+
return
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Has marker: replace between start and end
|
|
390
|
+
const end = content.indexOf(RULES_END, start)
|
|
391
|
+
if (end === -1) {
|
|
392
|
+
// Malformed: append new block
|
|
393
|
+
content += '\n' + block + '\n'
|
|
394
|
+
fs.writeFileSync(filePath, content, 'utf8')
|
|
395
|
+
return
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const newContent = content.slice(0, start) + block + content.slice(end + RULES_END.length)
|
|
399
|
+
fs.writeFileSync(filePath, newContent, 'utf8')
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* injectRulesForTool — injeta regras trackfw no arquivo de config do tool dado.
|
|
404
|
+
* tool: 'claude' | 'codex' | 'gemini' | 'copilot' | 'windsurf' | 'amazonq' | 'cursor'
|
|
405
|
+
* cwd: diretório raiz do projeto (default: process.cwd())
|
|
406
|
+
*/
|
|
407
|
+
function injectRulesForTool(tool, cwd) {
|
|
408
|
+
const relPath = AGENT_FILES[tool]
|
|
409
|
+
if (!relPath) return
|
|
410
|
+
const header = AGENT_HEADERS[tool] || ''
|
|
411
|
+
injectOrUpdateRules(path.join(cwd || process.cwd(), relPath), header)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* injectRulesDetected — varre cwd por arquivos de config de agentes existentes
|
|
416
|
+
* e injeta as regras trackfw em cada um encontrado.
|
|
417
|
+
* Cursor: injeta também se .cursor/ existir, mesmo que trackfw.mdc não exista ainda.
|
|
418
|
+
*/
|
|
419
|
+
function injectRulesDetected(cwd) {
|
|
420
|
+
const root = cwd || process.cwd()
|
|
421
|
+
for (const [tool, relPath] of Object.entries(AGENT_FILES)) {
|
|
422
|
+
if (tool === 'cursor') {
|
|
423
|
+
if (fs.existsSync(path.join(root, '.cursor'))) {
|
|
424
|
+
try { injectRulesForTool('cursor', root) } catch (_) {}
|
|
425
|
+
}
|
|
426
|
+
continue
|
|
427
|
+
}
|
|
428
|
+
if (fs.existsSync(path.join(root, relPath))) {
|
|
429
|
+
try { injectRulesForTool(tool, root) } catch (_) {}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
304
434
|
// ---------------------------------------------------------------------------
|
|
305
435
|
// CLAUDE.md
|
|
306
436
|
// ---------------------------------------------------------------------------
|
|
@@ -417,7 +547,7 @@ function generateClaudeMD(cfg) {
|
|
|
417
547
|
content += 'No CI gate configured.\n'
|
|
418
548
|
}
|
|
419
549
|
|
|
420
|
-
|
|
550
|
+
injectOrUpdateRules('CLAUDE.md', content)
|
|
421
551
|
console.log(' ✓ CLAUDE.md')
|
|
422
552
|
}
|
|
423
553
|
|
|
@@ -710,27 +840,112 @@ Próximo passo: abrir PR com gh pr create
|
|
|
710
840
|
* ao usuário que esta operação requer o binário Go instalado.
|
|
711
841
|
*/
|
|
712
842
|
async function installAgents() {
|
|
843
|
+
// CLAUDE.md já tratado por generateClaudeMD via injectOrUpdateRules
|
|
713
844
|
console.log(' ✓ claude (agentes — execute `trackfw install agents` com o binário Go para instalar os templates)')
|
|
714
845
|
}
|
|
715
846
|
|
|
716
847
|
async function installGemini() {
|
|
717
|
-
|
|
848
|
+
try {
|
|
849
|
+
injectRulesForTool('gemini', process.cwd())
|
|
850
|
+
console.log(' ✓ trackfw rules → GEMINI.md')
|
|
851
|
+
} catch (e) {
|
|
852
|
+
console.log(` ⚠ gemini rules inject: ${e.message}`)
|
|
853
|
+
}
|
|
718
854
|
}
|
|
719
855
|
|
|
720
856
|
async function installCursor() {
|
|
721
|
-
|
|
857
|
+
try {
|
|
858
|
+
injectRulesForTool('cursor', process.cwd())
|
|
859
|
+
console.log(' ✓ trackfw rules → .cursor/rules/trackfw.mdc')
|
|
860
|
+
} catch (e) {
|
|
861
|
+
console.log(` ⚠ cursor rules inject: ${e.message}`)
|
|
862
|
+
}
|
|
722
863
|
}
|
|
723
864
|
|
|
724
865
|
async function installCopilot() {
|
|
725
|
-
|
|
866
|
+
try {
|
|
867
|
+
injectRulesForTool('copilot', process.cwd())
|
|
868
|
+
console.log(' ✓ trackfw rules → .github/copilot-instructions.md')
|
|
869
|
+
} catch (e) {
|
|
870
|
+
console.log(` ⚠ copilot rules inject: ${e.message}`)
|
|
871
|
+
}
|
|
726
872
|
}
|
|
727
873
|
|
|
728
874
|
async function installWindsurf() {
|
|
729
|
-
|
|
875
|
+
try {
|
|
876
|
+
injectRulesForTool('windsurf', process.cwd())
|
|
877
|
+
console.log(' ✓ trackfw rules → .windsurfrules')
|
|
878
|
+
} catch (e) {
|
|
879
|
+
console.log(` ⚠ windsurf rules inject: ${e.message}`)
|
|
880
|
+
}
|
|
730
881
|
}
|
|
731
882
|
|
|
732
883
|
async function installAmazonQ() {
|
|
733
|
-
|
|
884
|
+
try {
|
|
885
|
+
injectRulesForTool('amazonq', process.cwd())
|
|
886
|
+
console.log(' ✓ trackfw rules → .amazonq/developer/guidelines.md')
|
|
887
|
+
} catch (e) {
|
|
888
|
+
console.log(` ⚠ amazonq rules inject: ${e.message}`)
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* generateClaudeCommandsForce — re-gera todos os slash commands, sobrescrevendo arquivos existentes.
|
|
894
|
+
*/
|
|
895
|
+
function generateClaudeCommandsForce(rootDir) {
|
|
896
|
+
const dir = rootDir ? path.join(rootDir, '.claude', 'commands', 'trackfw') : '.claude/commands/trackfw'
|
|
897
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
898
|
+
|
|
899
|
+
const commands = {
|
|
900
|
+
'adr.md': `Execute o seguinte comando bash: \`trackfw adr new "$ARGUMENTS"\`\n\nSe o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:\n\n\`\`\`\ntrackfw não está instalado. Instale com uma das opções:\n\n curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh\n npm install -g trackfw\n pip install trackfw\n\`\`\``,
|
|
901
|
+
'req.md': `Execute o seguinte comando bash: \`trackfw req new "$ARGUMENTS"\`\n\nSe o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:\n\n\`\`\`\ntrackfw não está instalado. Instale com uma das opções:\n\n curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh\n npm install -g trackfw\n pip install trackfw\n\`\`\``,
|
|
902
|
+
'validate.md': `Execute o seguinte comando bash: \`trackfw validate\`\n\nSe o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:\n\n\`\`\`\ntrackfw não está instalado. Instale com uma das opções:\n\n curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh\n npm install -g trackfw\n pip install trackfw\n\`\`\``,
|
|
903
|
+
'status.md': `Execute o seguinte comando bash: \`trackfw status\`\n\nSe o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:\n\n\`\`\`\ntrackfw não está instalado. Instale com uma das opções:\n\n curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh\n npm install -g trackfw\n pip install trackfw\n\`\`\``,
|
|
904
|
+
'move.md': `Execute o seguinte comando bash: \`trackfw roadmap move $ARGUMENTS\`\n\nO formato esperado é: \`<nome-do-roadmap> <estado>\`\nEstados válidos: \`backlog\`, \`wip\`, \`blocked\`, \`done\`, \`abandoned\`\n\nSe o comando falhar, instale trackfw com:\n curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh`,
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
for (const [filename, content] of Object.entries(commands)) {
|
|
908
|
+
fs.writeFileSync(path.join(dir, filename), content, 'utf8')
|
|
909
|
+
}
|
|
910
|
+
console.log(` ✓ .claude/commands/trackfw/ (${Object.keys(commands).length} slash commands sobrescritos)`)
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* installSkillsForce — sobrescreve ~/.claude/skills/trackfw/SKILL.md sempre.
|
|
915
|
+
*/
|
|
916
|
+
function installSkillsForce() {
|
|
917
|
+
const skillDir = path.join(os.homedir(), '.claude', 'skills', 'trackfw')
|
|
918
|
+
fs.mkdirSync(skillDir, { recursive: true })
|
|
919
|
+
|
|
920
|
+
const content = `---
|
|
921
|
+
name: trackfw
|
|
922
|
+
description: "trackfw — Governed Software Delivery: ADR → REQ → ROADMAP → kanban"
|
|
923
|
+
signature: "📦 trackfw - Governed Delivery"
|
|
924
|
+
---
|
|
925
|
+
|
|
926
|
+
# trackfw — Modo de Operação
|
|
927
|
+
|
|
928
|
+
Este projeto usa **trackfw** para governança de entrega de software.
|
|
929
|
+
Cadeia: **ADR → REQ → ROADMAP** · Estados: \`backlog / wip / blocked / done / abandoned\`
|
|
930
|
+
|
|
931
|
+
## Comandos principais
|
|
932
|
+
|
|
933
|
+
- \`trackfw context\` — contexto de trabalho atual (sempre execute primeiro)
|
|
934
|
+
- \`trackfw status\` — todos os artefatos e estados
|
|
935
|
+
- \`trackfw validate\` — valida consistência de governança
|
|
936
|
+
- \`trackfw roadmap move <nome> <estado>\` — transição de estado
|
|
937
|
+
- \`trackfw serve\` — board Kanban em http://localhost:4080
|
|
938
|
+
|
|
939
|
+
## Protocolo de agente
|
|
940
|
+
|
|
941
|
+
1. Antes de iniciar: \`trackfw context\` + ler \`docs/agents-working-context.md\`
|
|
942
|
+
2. Após concluir: atualizar \`docs/agents-working-context.md\`
|
|
943
|
+
3. Antes de PR: \`trackfw validate\` deve passar com zero violations
|
|
944
|
+
`
|
|
945
|
+
|
|
946
|
+
const dest = path.join(skillDir, 'SKILL.md')
|
|
947
|
+
fs.writeFileSync(dest, content, 'utf8')
|
|
948
|
+
console.log(` ✓ skill global atualizada em ${dest}`)
|
|
734
949
|
}
|
|
735
950
|
|
|
736
951
|
module.exports = {
|
|
@@ -743,10 +958,15 @@ module.exports = {
|
|
|
743
958
|
generateCommitMsgHook,
|
|
744
959
|
generateClaudeMD,
|
|
745
960
|
generateClaudeCommands,
|
|
961
|
+
generateClaudeCommandsForce,
|
|
962
|
+
installSkillsForce,
|
|
746
963
|
installAgents,
|
|
747
964
|
installGemini,
|
|
748
965
|
installCursor,
|
|
749
966
|
installCopilot,
|
|
750
967
|
installWindsurf,
|
|
751
968
|
installAmazonQ,
|
|
969
|
+
injectRulesForTool,
|
|
970
|
+
injectRulesDetected,
|
|
971
|
+
trackfwRulesBlock,
|
|
752
972
|
}
|