trackfw 3.0.0 → 4.0.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.
Files changed (59) hide show
  1. package/README.md +94 -3
  2. package/package.json +1 -1
  3. package/src/commands/barrier.js +358 -0
  4. package/src/commands/discover.js +18 -0
  5. package/src/commands/help.js +99 -9
  6. package/src/commands/index.js +3 -0
  7. package/src/commands/init.js +40 -2
  8. package/src/commands/log.js +2 -1
  9. package/src/commands/note.js +24 -0
  10. package/src/commands/req.js +7 -1
  11. package/src/commands/roadmap.js +4 -3
  12. package/src/commands/ship.js +49 -0
  13. package/src/commands/update-harness.js +208 -0
  14. package/src/commands/update.js +206 -72
  15. package/src/config/index.js +5 -2
  16. package/src/forge/adapter.js +189 -0
  17. package/src/forge/resolve.js +191 -0
  18. package/src/generators/adr.js +13 -4
  19. package/src/generators/date.js +23 -0
  20. package/src/generators/init.js +229 -39
  21. package/src/generators/note.js +154 -0
  22. package/src/generators/req.js +88 -5
  23. package/src/generators/roadmap.js +96 -20
  24. package/src/i18n/locales/en-US.json +2 -1
  25. package/src/i18n/locales/es-ES.json +2 -1
  26. package/src/i18n/locales/pt-BR.json +2 -1
  27. package/src/identity/preset.js +22 -0
  28. package/src/integrations/assets/agents/architect.md +35 -0
  29. package/src/integrations/assets/agents/backend.md +32 -0
  30. package/src/integrations/assets/agents/code-quality.md +32 -0
  31. package/src/integrations/assets/agents/data.md +32 -0
  32. package/src/integrations/assets/agents/dba.md +32 -0
  33. package/src/integrations/assets/agents/frontend.md +32 -0
  34. package/src/integrations/assets/agents/iac.md +46 -0
  35. package/src/integrations/assets/agents/infra.md +34 -0
  36. package/src/integrations/assets/agents/qa.md +32 -0
  37. package/src/integrations/assets/agents/security.md +32 -0
  38. package/src/integrations/assets/agents/tooling.md +47 -0
  39. package/src/integrations/assets/agents/ux.md +32 -0
  40. package/src/integrations/assets/catalog.json +16 -2
  41. package/src/integrations/assets/skills/architecture.md +66 -0
  42. package/src/integrations/assets/skills/backend.md +67 -0
  43. package/src/integrations/assets/skills/code-quality.md +78 -0
  44. package/src/integrations/assets/skills/data.md +75 -0
  45. package/src/integrations/assets/skills/dba.md +77 -0
  46. package/src/integrations/assets/skills/frontend.md +70 -0
  47. package/src/integrations/assets/skills/iac.md +90 -0
  48. package/src/integrations/assets/skills/infra.md +62 -0
  49. package/src/integrations/assets/skills/qa.md +63 -0
  50. package/src/integrations/assets/skills/security.md +74 -0
  51. package/src/integrations/assets/skills/tooling.md +80 -0
  52. package/src/integrations/assets/skills/ux.md +70 -0
  53. package/src/integrations/catalog.js +25 -1
  54. package/src/integrations/index.js +20 -2
  55. package/src/integrations/render.js +57 -6
  56. package/src/lib/update-engine.js +217 -0
  57. package/src/ship/runner.js +454 -0
  58. package/src/validator/index.js +323 -111
  59. package/src/validator/traceid.js +1 -1
@@ -13,6 +13,7 @@ const GOV_DIRS = [
13
13
  'docs/roadmaps/blocked',
14
14
  'docs/roadmaps/done',
15
15
  'docs/roadmaps/abandoned',
16
+ 'vault/notes',
16
17
  ]
17
18
 
18
19
  const GLOBAL_ADRS_DIRECTIVE = 'Obrigatório: Inspecione e respeite todos os ADRs globais nos diretórios listados em adr_dirs (inclusive caminhos ~/...) antes de propor alterações de arquitetura.'
@@ -28,6 +29,7 @@ async function scaffold(cfg, cwd) {
28
29
  console.log(` ✓ ${dir}`)
29
30
  }
30
31
 
32
+ generateVaultIndex(root)
31
33
  writeTrackfwConfig(cfg, root)
32
34
  generateValidateScript(cfg, root)
33
35
  generateAttentionScripts(cfg, root)
@@ -40,6 +42,29 @@ async function scaffold(cfg, cwd) {
40
42
  injectHooksDetected(root)
41
43
  }
42
44
 
45
+ /**
46
+ * generateVaultIndex — cria vault/notes/index.md se ainda não existir.
47
+ * @param {string} root
48
+ */
49
+ function generateVaultIndex(root) {
50
+ const indexPath = path.join(root || process.cwd(), 'vault', 'notes', 'index.md')
51
+ if (fs.existsSync(indexPath)) return
52
+ const content = `# Vault de Conhecimento
53
+
54
+ > Ponto de entrada de conhecimento do projeto para agentes e pessoas.
55
+ > Cada nota documenta uma causa-raiz, decisão técnica ou restrição não óbvia.
56
+ > Crie notas com: trackfw note new "<título>"
57
+
58
+ ## Índice
59
+
60
+ <!-- As notas serão listadas abaixo. Exemplo:
61
+ - [nome-da-nota-YYYY-MM-DD](nome-da-nota-YYYY-MM-DD.md)
62
+ -->
63
+ `
64
+ fs.writeFileSync(indexPath, content, 'utf8')
65
+ console.log(' ✓ vault/notes/index.md')
66
+ }
67
+
43
68
  // ---------------------------------------------------------------------------
44
69
  // trackfw.yaml
45
70
  // ---------------------------------------------------------------------------
@@ -54,7 +79,7 @@ backend: ${cfg.backend || ''}
54
79
  backend_framework: ${cfg.backendFramework || ''}
55
80
  pkg_manager: ${cfg.pkgManager || ''}
56
81
  hooks: ${cfg.hooks || ''}
57
- ci: ${cfg.ci || ''}
82
+ ci: ${cfg.ci || ''}${cfg.forge ? `\nforge: ${cfg.forge}` : ''}
58
83
  require_req_in_commit: ${cfg.requireReqInCommit ? 'true' : 'false'}
59
84
 
60
85
  # governance paths (edit to match your project structure)
@@ -76,13 +101,26 @@ roadmap_namespacing: flat
76
101
  // scripts/trackfw-validate.sh
77
102
  // ---------------------------------------------------------------------------
78
103
 
79
- function generateValidateScript(cfg) {
80
- fs.mkdirSync('scripts', { recursive: true })
104
+ // generateValidateScript — cwd is optional and defaults to process.cwd() so
105
+ // existing callers (scaffold(), which always runs with process.cwd() already
106
+ // at the project root) keep working unchanged. `trackfw update`'s
107
+ // validate-script target passes cwd explicitly so this can be applied
108
+ // against a --dry-run sandbox root without ever touching the real project
109
+ // tree — this is the SAME canonical generator scaffold() uses for `init`,
110
+ // not a separate copy (see npm/src/commands/discover.js's writeValidateScript,
111
+ // which is a different, simpler generator used only by `discover`/legacy
112
+ // paths and must never be reused here — that mismatch was the ML-6H
113
+ // validate-script parity bug: init wrote the rich per-backend script,
114
+ // `update` overwrote it with the static 3-line one, so idempotent re-runs
115
+ // reported "updated" instead of "skipped").
116
+ function generateValidateScript(cfg, cwd) {
117
+ const root = cwd || process.cwd()
118
+ fs.mkdirSync(path.join(root, 'scripts'), { recursive: true })
81
119
 
82
120
  const script = buildValidateScript(cfg)
83
- const scriptPath = path.join('scripts', 'trackfw-validate.sh')
121
+ const scriptPath = path.join(root, 'scripts', 'trackfw-validate.sh')
84
122
  fs.writeFileSync(scriptPath, script, { encoding: 'utf8', mode: 0o755 })
85
- console.log(` ✓ ${scriptPath}`)
123
+ console.log(` ✓ ${path.join('scripts', 'trackfw-validate.sh')}`)
86
124
  }
87
125
 
88
126
  function buildValidateScript(cfg) {
@@ -356,14 +394,19 @@ This project uses **trackfw** for AI-native delivery governance.
356
394
  Chain: \`ADR → REQ → ROADMAP\` · States: \`backlog / analyzing / wip / blocked / done / abandoned\`
357
395
 
358
396
  ### Agent Protocol
359
- 1. **Before starting:** run \`trackfw context\` · read \`docs/agents-working-context.md\`
360
- 2. **After finishing:** update \`docs/agents-working-context.md\` with what changed
361
- 3. **Before PR:** \`trackfw validate\` must pass
362
- 4. **ML lifecycle — mandatory:**
397
+ 1. **Before any implementation (mandatory):** create governance artifacts FIRST, then branch:
398
+ \`trackfw req new "title"\` → \`trackfw roadmap new "title"\` → \`trackfw roadmap move <name> wip\` → \`git checkout -b feat/<branch>\`
399
+ ❌ Never create a branch before REQ + ROADMAP are in wip/
400
+ ❌ Never defer REQ/ROADMAP creation to a future task — they are prerequisites, not deliverables
401
+ ✓ \`trackfw validate\` enforces this via \`branch_has_wip_roadmap\` rule (v2.7.0+)
402
+ 2. **Before starting:** run \`trackfw context\` · read \`docs/agents-working-context.md\`
403
+ 3. **After finishing:** update \`docs/agents-working-context.md\` with what changed
404
+ 4. **Before PR:** \`trackfw validate\` must pass
405
+ 5. **ML lifecycle — mandatory:**
363
406
  - Starting a ML: edit roadmap \`**Status:** ⬜ Pendente\` → \`**Status:** 🔄 Em andamento\` + commit.
364
407
  - Completing a ML: edit roadmap → \`**Status:** ✅ Concluído\` + include in ML commit.
365
408
  - Analyzing a roadmap: move from \`backlog/\` to \`analyzing/\`; to \`wip/\` only when coding starts.
366
- 5. **${GLOBAL_ADRS_DIRECTIVE}**
409
+ 6. **${GLOBAL_ADRS_DIRECTIVE}**
367
410
 
368
411
  ### Attention Signal (when you need user input during a task)
369
412
  Write \`docs/roadmaps/.trackfw-attention.json\`:
@@ -386,6 +429,13 @@ Delete the file when resolved. Visible as a live banner in \`trackfw serve\`.
386
429
  - **Security wave:** include a red-team review wave in every feature roadmap
387
430
  - **Test coverage:** TDD for critical logic; min 60% (prototype) / 80% (production)
388
431
  - Use \`/trackfw:architect\` to define stack before the first REQ
432
+
433
+ ### Key Commands
434
+ - \`trackfw context\` — current governance state (always run first)
435
+ - \`trackfw status\` — all artifacts and states
436
+ - \`trackfw validate\` — governance consistency check
437
+ - \`trackfw roadmap move <name> <state>\` — transition roadmap state
438
+ - \`trackfw serve\` — live Kanban board at http://localhost:4080
389
439
  ` + RULES_END
390
440
  }
391
441
 
@@ -504,7 +554,8 @@ function generateClaudeMD(cfg) {
504
554
  content += '| `/trackfw:roadmap <req>` | Generate AI roadmap from a REQ |\n'
505
555
  content += '| `/trackfw:move <name> <state>` | Move roadmap between states manually |\n'
506
556
  content += '| `/trackfw:validate` | Run governance validation |\n'
507
- content += '| `/trackfw:status` | Check what is in flight |\n\n'
557
+ content += '| `/trackfw:status` | Check what is in flight |\n'
558
+ content += '| `/trackfw:barrier` | Run the wave-release checklist before liberating the next wave |\n\n'
508
559
 
509
560
  content += '## CLI commands (terminal / CI)\n\n'
510
561
  content += '| Command | When to use |\n'
@@ -585,6 +636,66 @@ function generateClaudeMD(cfg) {
585
636
  content += 'No CI gate configured.\n'
586
637
  }
587
638
 
639
+ // Harness sections — derived from project governance conventions
640
+ content += '\n## Branch strategy\n\n'
641
+ content += 'One active branch at a time. Name it `feat/<slug>`, `fix/<slug>` or `refactor/<slug>`. '
642
+ content += 'Before creating a new branch, verify no other is genuinely open: run `git fetch origin --prune`, '
643
+ content += 'then `git branch -r --no-merged origin/main`, then for each candidate `git diff origin/main <branch> --stat`. '
644
+ content += 'An empty diff means it was squash-merged — ignore it. '
645
+ content += 'Squash merges do not mark a branch as merged, so `--no-merged` alone is not evidence. '
646
+ content += 'If the branch is stale and the diff looks inflated by main\'s own evolution, '
647
+ content += 'compare only the files the branch itself touched since the merge base.\n\n'
648
+
649
+ content += '## Definition of done\n\n'
650
+ content += 'Green build and tests do not close a microbatch. '
651
+ content += 'It is done when the requirement and the roadmap sit in the correct state folder, '
652
+ content += 'their declared status matches that folder, the final validation is recorded with evidence, '
653
+ content += 'no duplicate copy remains in another state, and `trackfw validate` reports no violations.\n\n'
654
+
655
+ content += '## Requirement scope\n\n'
656
+ content += 'Every requirement must declare an explicit negative scope: what must not be implemented. '
657
+ content += 'Boundaries prevent an implementing agent from inventing work.\n\n'
658
+
659
+ content += '## State requirements\n\n'
660
+ content += '`blocked` requires a reason and an owner. '
661
+ content += '`abandoned` requires a reason and a successor. '
662
+ content += '`wip` must reflect work that is genuinely active; '
663
+ content += 'anything stalled moves to `blocked` or `abandoned` instead of rotting in `wip`.\n\n'
664
+
665
+ content += '## Roadmap format\n\n'
666
+ content += 'Organize work as waves of microbatches. '
667
+ content += 'A wave groups microbatches that can run in parallel; a barrier separates waves. '
668
+ content += 'Microbatches sharing any file — including generated trees and build outputs — must be sequential, '
669
+ content += 'and the reason is documented. '
670
+ content += 'Each microbatch declares exact files, exact actions, measurable acceptance criteria and exact validation commands, '
671
+ content += 'so that a small model can execute it without guessing.\n\n'
672
+
673
+ content += '## When governance is not required\n\n'
674
+ content += 'A closed list of exemptions: a typo or local variable rename; a documentation-only change; '
675
+ content += 'a configuration tweak with no runtime effect; a direct revert; '
676
+ content += 'answering a question or reviewing without changes. '
677
+ content += 'Additionally, when the user reports a concrete bug, fix it directly and do not open an architectural analysis for it. '
678
+ content += '**This section takes precedence over the general rule that requires a requirement and a roadmap.** '
679
+ content += 'Anything touching business logic, an API contract, a data schema, authentication or authorization, '
680
+ content += 'localization, or user-facing behavior always requires governance, regardless of how few files it touches.\n\n'
681
+
682
+ content += '## Production incidents\n\n'
683
+ content += 'Inspect the live environment before proposing a fix: real variables, active credentials, '
684
+ content += 'granted permissions, running processes. '
685
+ content += 'Confirm the root cause against real evidence, then implement the smallest fix. '
686
+ content += 'Never edit static configuration files as a response to a root cause that has not been confirmed in the running environment.\n\n'
687
+
688
+ content += '## Iterative prototyping\n\n'
689
+ content += 'For complex or uncertain user-facing work, validate the concept with a disposable, isolated prototype '
690
+ content += 'that the user reviews visually, and only then write the decision record and the production roadmap. '
691
+ content += 'Build and test success is not evidence that an interface is right.\n\n'
692
+
693
+ content += '## Autopilot\n\n'
694
+ content += 'Ask everything you need before starting. '
695
+ content += 'Once started, do not interrupt for confirmations that could have been anticipated. '
696
+ content += 'Decide low-risk details autonomously following existing project conventions, '
697
+ content += 'and record autonomous decisions in the commit message.\n'
698
+
588
699
  injectOrUpdateRules('CLAUDE.md', content)
589
700
  console.log(' ✓ CLAUDE.md')
590
701
  }
@@ -613,14 +724,20 @@ function backendCommands(cfg) {
613
724
  }
614
725
 
615
726
  // ---------------------------------------------------------------------------
616
- // .claude/commands/trackfw/ — 7 slash commands
727
+ // .claude/commands/trackfw/ — slash commands
728
+ //
729
+ // CLAUDE_COMMANDS is the single source of truth for the set of slash
730
+ // commands installed by trackfw. Both generateClaudeCommands (normal path,
731
+ // idempotent — never overwrites an existing file) and
732
+ // generateClaudeCommandsForce (force path — always overwrites) install
733
+ // from this same map; they only differ in overwrite behavior. This mirrors
734
+ // the Go CLI's installSkillsInner(force) and the Python CLI's single
735
+ // generate_claude_commands — one list, one force flag. Do not fork this map
736
+ // again: a prior divergence let the force path fall behind the normal path
737
+ // (missing roadmap.md, implement.md, barrier.md) undetected.
617
738
  // ---------------------------------------------------------------------------
618
739
 
619
- function generateClaudeCommands() {
620
- const dir = '.claude/commands/trackfw'
621
- fs.mkdirSync(dir, { recursive: true })
622
-
623
- const commands = {
740
+ const CLAUDE_COMMANDS = {
624
741
  'adr.md': `Execute o seguinte comando bash: \`trackfw adr new "$ARGUMENTS"\`
625
742
 
626
743
  Se o comando falhar com \`trackfw: command not found\` ou similar, informe ao usuário:
@@ -700,9 +817,16 @@ trackfw não está instalado. Instale com:
700
817
  Com base no conteúdo da REQ, gere um roadmap seguindo **estritamente** este formato:
701
818
 
702
819
  \`\`\`markdown
820
+ ---
821
+ status: backlog
822
+ date: <YYYY-MM-DD>
823
+ req: "docs/req/<arquivo-selecionado>.md"
824
+ squad: ""
825
+ ---
826
+
703
827
  # Roadmap: <título derivado da REQ>
704
828
 
705
- > Criado em: <YYYY-MM-DD> | Status: ⬜ Backlog
829
+ > Created: <YYYY-MM-DD> | Status: backlog
706
830
 
707
831
  ## Diagnóstico / Contexto
708
832
  <resumo do problema, motivação e escopo extraídos da REQ>
@@ -720,6 +844,13 @@ trackfw não está instalado. Instale com:
720
844
  - [ ] build sem erros
721
845
  - [ ] testes verdes
722
846
  **Comandos de validação:** \`<comando de build e teste do projeto>\`
847
+
848
+ ### ML-1B — <título> (se independente de ML-1A)
849
+ ...
850
+
851
+ ## Wave 2 — <nome> (depende de Wave 1)
852
+ > Dependências: Wave 1 completa
853
+ ...
723
854
  \`\`\`
724
855
 
725
856
  **Princípios obrigatórios:**
@@ -732,10 +863,12 @@ trackfw não está instalado. Instale com:
732
863
  4. **Salvar o arquivo**
733
864
  - Calcule o slug: título em lowercase, espaços → hifens, remova caracteres especiais
734
865
  - Crie o arquivo em \`docs/roadmaps/backlog/ROADMAP-<YYYY-MM-DD>-<slug>.md\`
866
+ - Preencha \`req:\` com o caminho relativo completo da REQ selecionada
735
867
  - Use a data de hoje
736
868
 
737
869
  5. **Confirmar**
738
- Informe o caminho do arquivo criado e um resumo das Waves e total de MLs gerados.`,
870
+ Informe o caminho do arquivo criado e um resumo das Waves e total de MLs gerados.
871
+ `,
739
872
 
740
873
  'implement.md': `Você é o orquestrador de implementação do trackfw. Siga o fluxo abaixo **sem pular etapas**.
741
874
 
@@ -848,6 +981,51 @@ Roadmap: docs/roadmaps/done/<nome>.md
848
981
  Próximo passo: abrir PR com gh pr create
849
982
  \`\`\``,
850
983
 
984
+ 'barrier.md': `Você é o \`trackfw_architect\`, a única autoridade Git deste projeto. Este comando executa o checklist operacional de liberação de uma wave — nenhum outro agente commita, faz push ou libera a próxima wave.
985
+
986
+ ## Argumento
987
+
988
+ \`$ARGUMENTS\` no formato \`<roadmap> <wave>\`. Se ausente ou incompleto, pergunte ao usuário qual roadmap (em \`docs/roadmaps/wip/\`) e qual número de wave validar.
989
+
990
+ ---
991
+
992
+ ## Núcleo determinístico
993
+
994
+ Execute primeiro:
995
+ \`\`\`bash
996
+ trackfw barrier <roadmap> --wave <n> --json
997
+ \`\`\`
998
+
999
+ Este comando é **necessário mas não suficiente**. Ele verifica MLs concluídos, evidências e \`trackfw validate\`, mas não substitui as inspeções especializadas nem a auditoria de diff abaixo — nenhuma delas é avaliada pelo binário. Consulte a seção \`trackfw barrier\` em \`docs/cli-parity.md\` para o contrato completo (estados, exit codes, saída JSON).
1000
+
1001
+ Se o comando retornar exit code não-zero (\`blocked\` ou erro de resolução): pare, reporte a falha ao usuário e não prossiga no checklist até que a wave passe.
1002
+
1003
+ ---
1004
+
1005
+ ## Definição de pronto da barrier — checklist completo
1006
+
1007
+ Antes de liberar a próxima wave, confirme cada item com evidência concreta — não presuma:
1008
+
1009
+ 1. **Todos os MLs da wave concluídos e marcados** — cada ML da wave está com \`**Status:** ✅ Concluído\` no roadmap.
1010
+ 2. **Testes unitários e E2E aplicáveis executados** — rode os comandos de validação declarados em cada ML.
1011
+ 3. **Build aplicável sem erros** — rode o comando de build do(s) workspace(s) afetado(s).
1012
+ 4. **Cada critério de aceite inspecionado com evidência** — leia os arquivos modificados e confirme contra os critérios listados, não apenas contra os testes.
1013
+ 5. **Agente code-quality reportou conformidade, performance, robustez e clareza** — invoque o agente \`code-quality\` quando a mudança introduzir lógica nova, duplicação relevante ou risco de manutenibilidade.
1014
+ 6. **Agente security reportou SAST, privilégios, controle de acesso e camadas aplicáveis** — invoque o agente \`security\` quando a mudança tocar autenticação, segredos, entrada externa ou permissões.
1015
+ 7. **Gates pré-commit declarados pelo projeto executados** — rode os hooks/gates configurados (lint, format, testes de contrato).
1016
+ 8. **\`trackfw validate --json\` aprovado** — execute e confirme zero violações.
1017
+ 9. **Diff auditado contra o escopo** — revise o diff completo; confirme que não há alterações de agentes concorrentes nem arquivos fora do escopo do ML (ex: \`docs/adr/\`, \`docs/req/\`, \`docs/roadmaps/\` quando não autorizado ao especialista).
1018
+ 10. **Resultado registrado antes de liberar a próxima wave** — anote no roadmap ou na resposta ao usuário que a wave passou, com a evidência de cada item acima.
1019
+
1020
+ Se qualquer item falhar: bloqueie a próxima wave, identifique o item e o agente responsável, e despache um microlote corretivo. Só repita o checklist depois que o corretivo for concluído.
1021
+
1022
+ ---
1023
+
1024
+ ## Autoridade Git
1025
+
1026
+ Somente o \`trackfw_architect\` cria branch, audita diff, commita e faz push. Especialistas entregam trabalho sem commit — cabe a este papel revisar, commitar e sugerir a abertura de PR/MR (sem abrir automaticamente sem autorização do usuário).
1027
+ `,
1028
+
851
1029
  'architect.md': `Você é o guia de arquitetura do trackfw. Ajude o usuário a escolher a stack correta e arquitetar a aplicação em linguagem simples, acessível para times não técnicos.
852
1030
 
853
1031
  ## Passo 1 — Descoberta de Negócio
@@ -926,13 +1104,21 @@ Oriente o usuário:
926
1104
  2. Gere o roadmap em microlotes com /trackfw:roadmap
927
1105
  3. Inicie a implementação com /trackfw:implement
928
1106
  \`\`\``,
929
- }
1107
+ }
1108
+
1109
+ /**
1110
+ * installClaudeCommandsInner — fonte única de escrita dos slash commands.
1111
+ * @param {string} dir diretório de destino (já resolvido)
1112
+ * @param {boolean} force quando true, sobrescreve arquivos existentes
1113
+ */
1114
+ function installClaudeCommandsInner(dir, force) {
1115
+ fs.mkdirSync(dir, { recursive: true })
930
1116
 
931
1117
  let created = 0
932
1118
  let skipped = 0
933
- for (const [filename, content] of Object.entries(commands)) {
1119
+ for (const [filename, content] of Object.entries(CLAUDE_COMMANDS)) {
934
1120
  const filePath = path.join(dir, filename)
935
- if (fs.existsSync(filePath)) {
1121
+ if (!force && fs.existsSync(filePath)) {
936
1122
  skipped++
937
1123
  continue
938
1124
  }
@@ -940,13 +1126,28 @@ Oriente o usuário:
940
1126
  created++
941
1127
  }
942
1128
 
943
- if (skipped > 0) {
1129
+ if (force) {
1130
+ console.log(` ✓ ${dir} (${created} slash commands sobrescritos)`)
1131
+ } else if (skipped > 0) {
944
1132
  console.log(` ✓ ${dir} (${created} slash commands criados, ${skipped} já existiam — não sobrescritos)`)
945
1133
  } else {
946
1134
  console.log(` ✓ ${dir} (${created} slash commands)`)
947
1135
  }
948
1136
  }
949
1137
 
1138
+ /**
1139
+ * generateClaudeCommands — instala os slash commands de forma idempotente:
1140
+ * nunca sobrescreve um arquivo já existente. Honra o `rootDir` recebido
1141
+ * (mesma convenção do gêmeo forçado generateClaudeCommandsForce e do
1142
+ * generate_claude_commands(cwd) do Python); quando omitido, cai no
1143
+ * caminho relativo ao cwd do processo, preservando o comportamento
1144
+ * histórico consumido pelos testes que chamam sem argumento.
1145
+ */
1146
+ function generateClaudeCommands(rootDir) {
1147
+ const dir = rootDir ? path.join(rootDir, '.claude', 'commands', 'trackfw') : '.claude/commands/trackfw'
1148
+ installClaudeCommandsInner(dir, false)
1149
+ }
1150
+
950
1151
  // ---------------------------------------------------------------------------
951
1152
  // AI tool installers
952
1153
  // ---------------------------------------------------------------------------
@@ -1039,25 +1240,13 @@ async function installIntegrationTarget(target, cwd = process.cwd(), scope = 'pr
1039
1240
  }
1040
1241
 
1041
1242
  /**
1042
- * generateClaudeCommandsForce — re-gera todos os slash commands, sobrescrevendo arquivos existentes.
1243
+ * generateClaudeCommandsForce — re-gera todos os slash commands, sobrescrevendo
1244
+ * arquivos existentes. Instala exatamente o mesmo conjunto de CLAUDE_COMMANDS
1245
+ * usado por generateClaudeCommands — só o comportamento de sobrescrita difere.
1043
1246
  */
1044
1247
  function generateClaudeCommandsForce(rootDir) {
1045
1248
  const dir = rootDir ? path.join(rootDir, '.claude', 'commands', 'trackfw') : '.claude/commands/trackfw'
1046
- fs.mkdirSync(dir, { recursive: true })
1047
-
1048
- const commands = {
1049
- '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\`\`\``,
1050
- '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\`\`\``,
1051
- '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\`\`\``,
1052
- '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\`\`\``,
1053
- 'move.md': `Execute o seguinte comando bash: \`trackfw roadmap move $ARGUMENTS\`\n\nO formato esperado é: \`<nome-do-roadmap> <estado>\`\nEstados válidos: \`backlog\`, \`analyzing\`, \`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`,
1054
- 'architect.md': `Você é o guia de arquitetura do trackfw. Ajude o usuário a escolher a stack correta e arquitetar a aplicação em linguagem simples, acessível para times não técnicos.\n\n## Passo 1 — Descoberta de Negócio\n\nFaça ao usuário as seguintes perguntas em linguagem simples, uma por vez:\n\n1. "O que sua aplicação vai fazer? Descreva em 2-3 frases como se fosse explicar para alguém de fora da TI."\n2. "Quantas pessoas vão usar esse sistema simultaneamente? (< 10 pessoas / 10-100 pessoas / > 100 pessoas)"\n3. "Esse sistema vai para produção de verdade ou é um protótipo para validar uma ideia?"\n4. "Você precisa de login/autenticação de usuários? (Sim / Não / Não sei)"\n5. "Tem alguma restrição de tecnologia ou preferência da empresa? (ex: só Java, só Microsoft, etc.)"\n\n---\n\n## Passo 2 — Recomendação de Stack\n\nCom base nas respostas, escolha **UM** dos combos pré-validados:\n\n### Combo A — Protótipo Rápido\n**Quando usar:** prototipagem, validação de ideia, até ~10 usuários, sem pressão de produção.\n- **Frontend:** React + Vite\n- **Backend:** FastAPI (Python) ou Express (Node.js)\n- **Banco:** SQLite + SQLAlchemy / Prisma\n- **Auth:** JWT simples quando necessário\n- **Docker:** Dockerfile básico para o backend\n\n### Combo B — Sistema Pequeno/Médio em Produção\n**Quando usar:** sistema real, 10-100 usuários, robustez e manutenibilidade.\n- **Frontend:** Next.js (SSR + rotas prontas)\n- **Backend:** FastAPI (Python) ou NestJS (Node.js)\n- **Banco:** PostgreSQL + ORM (SQLAlchemy / Prisma / TypeORM)\n- **Auth:** OAuth2 com JWT (Supabase Auth ou Auth0)\n- **Docker:** docker-compose com frontend + backend + banco\n\n### Combo C — Enterprise / Java\n**Quando usar:** integração com sistemas corporativos, > 100 usuários, exigência de Java.\n- **Frontend:** Angular\n- **Backend:** Spring Boot\n- **Banco:** PostgreSQL + Hibernate\n- **Auth:** Spring Security + OAuth2 (Keycloak ou Azure AD)\n- **Docker:** docker-compose com todos os serviços\n\nApresente o combo recomendado com explicação simples do motivo.\n\n---\n\n## Passo 3 — Arquitetura em Camadas (explicação simples)\n\nExplique a arquitetura com uma metáfora de negócio:\n\n"Pense na aplicação como um restaurante:\n- **Frontend** = o salão: o que o cliente vê e interage\n- **Backend** = a cozinha: onde as regras de negócio acontecem, nunca exposta diretamente\n- **Banco de dados** = a despensa: onde os dados ficam guardados, acessada só pela cozinha"\n\nReforce as **Architecture Directives** já injetadas no CLAUDE.md deste projeto: separação em 3 camadas sem dados em memória (sempre DB + ORM), auth + Docker + .env desde o dia 1, validação em 2 camadas, contrato OpenAPI antes de codar, wave de segurança em todo roadmap e cobertura mínima de testes (60% protótipo / 80% produção).\n\n---\n\n## Passo 4 — Gerar o ADR de Stack\n\nExecute \`/trackfw:adr\` com o título: \`"Stack e arquitetura em camadas — [nome do projeto]"\`\n\nO ADR deve registrar a stack escolhida (combo e componentes), motivação baseada nas respostas, alternativas descartadas e princípios de arquitetura adotados.\n\n---\n\n## Passo 5 — Próximos Passos\n\nOriente o usuário:\n\n\`\`\`\n✅ Stack definida. Próximos passos:\n\n1. Crie a REQ da primeira feature com /trackfw:req\n2. Gere o roadmap em microlotes com /trackfw:roadmap\n3. Inicie a implementação com /trackfw:implement\n\`\`\``,
1055
- }
1056
-
1057
- for (const [filename, content] of Object.entries(commands)) {
1058
- fs.writeFileSync(path.join(dir, filename), content, 'utf8')
1059
- }
1060
- console.log(` ✓ .claude/commands/trackfw/ (${Object.keys(commands).length} slash commands sobrescritos)`)
1249
+ installClaudeCommandsInner(dir, true)
1061
1250
  }
1062
1251
 
1063
1252
  /**
@@ -1139,6 +1328,7 @@ module.exports = {
1139
1328
  generateClaudeMD,
1140
1329
  generateClaudeCommands,
1141
1330
  generateClaudeCommandsForce,
1331
+ generateVaultIndex,
1142
1332
  installSkillsForce,
1143
1333
  installAgents,
1144
1334
  installGemini,
@@ -0,0 +1,154 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+ const { localDateISO } = require('./date')
6
+
7
+ const VAULT_DIR = 'vault/notes'
8
+ const INDEX_FILE = 'vault/notes/index.md'
9
+
10
+ /**
11
+ * Converte título em slug kebab-case lowercase sem acentos.
12
+ * Reutiliza a mesma lógica do adr.js (toSlug).
13
+ * @param {string} s
14
+ * @returns {string}
15
+ */
16
+ function toSlug(s) {
17
+ // NFKD normalization + remove combining marks (diacríticos) + lowercase + non-alphanumeric → hífen
18
+ return s
19
+ .normalize('NFKD')
20
+ .replace(/[̀-ͯ]/g, '')
21
+ .toLowerCase()
22
+ .replace(/[^a-z0-9]+/g, '-')
23
+ .replace(/^-+|-+$/g, '')
24
+ }
25
+
26
+ /**
27
+ * Retorna a data LOCAL atual no formato YYYY-MM-DD.
28
+ * Delega para localDateISO() — usa getDate/getMonth/getFullYear (hora local),
29
+ * não toISOString (UTC).
30
+ * @returns {string}
31
+ */
32
+ function today() {
33
+ return localDateISO()
34
+ }
35
+
36
+ /**
37
+ * Cria uma nova nota em vault/notes/<slug>-YYYY-MM-DD.md e linka no index.md.
38
+ * Idempotente: falha com erro claro se a nota já existir.
39
+ * @param {string} title
40
+ * @param {string} [cwd]
41
+ */
42
+ function newNote(title, cwd) {
43
+ const root = cwd || process.cwd()
44
+ const vaultDir = path.join(root, VAULT_DIR)
45
+ fs.mkdirSync(vaultDir, { recursive: true })
46
+
47
+ const slug = toSlug(title)
48
+ const date = today()
49
+ const filename = `${slug}-${date}.md`
50
+ const notePath = path.join(vaultDir, filename)
51
+
52
+ if (fs.existsSync(notePath)) {
53
+ throw new Error(`nota "${filename}" já existe — não sobrescrita`)
54
+ }
55
+
56
+ const body = `---
57
+ title: "${title}"
58
+ tags: []
59
+ date: ${date}
60
+ related: []
61
+ ---
62
+
63
+ # ${title}
64
+
65
+ ## Problem
66
+
67
+ <!-- Descreva o problema ou situação que motivou esta nota. -->
68
+
69
+ ## Root cause
70
+
71
+ <!-- Qual foi a causa raiz identificada? -->
72
+
73
+ ## Solution
74
+
75
+ <!-- Como foi resolvido ou mitigado? O que deve ser feito? -->
76
+ `
77
+
78
+ fs.writeFileSync(notePath, body, 'utf8')
79
+ appendNoteToIndex(filename, root)
80
+ console.log(`created ${path.join(VAULT_DIR, filename)}`)
81
+ }
82
+
83
+ /**
84
+ * Acrescenta link para filename no vault/notes/index.md.
85
+ * Cria o index.md se não existir. Não duplica se já estiver linkado.
86
+ * @param {string} filename
87
+ * @param {string} [cwd]
88
+ */
89
+ function appendNoteToIndex(filename, cwd) {
90
+ const root = cwd || process.cwd()
91
+ const indexPath = path.join(root, INDEX_FILE)
92
+
93
+ if (!fs.existsSync(indexPath)) {
94
+ const initial = `# Vault de Conhecimento
95
+
96
+ > Ponto de entrada de conhecimento do projeto para agentes e pessoas.
97
+
98
+ ## Índice
99
+
100
+ `
101
+ fs.writeFileSync(indexPath, initial, 'utf8')
102
+ }
103
+
104
+ const content = fs.readFileSync(indexPath, 'utf8')
105
+ const nameWithoutExt = filename.replace(/\.md$/, '')
106
+
107
+ // Verifica se já linkado (link markdown ou wikilink)
108
+ if (
109
+ content.includes(`(${filename})`) ||
110
+ content.includes(`[[${nameWithoutExt}]]`) ||
111
+ content.includes(`[[${filename}]]`)
112
+ ) {
113
+ return
114
+ }
115
+
116
+ const link = `- [${nameWithoutExt}](${filename})\n`
117
+ fs.appendFileSync(indexPath, link, 'utf8')
118
+ }
119
+
120
+ /**
121
+ * Retorna todos os arquivos .md em vault/notes/ exceto index.md.
122
+ * Retorna [] se o diretório não existir.
123
+ * @param {string} [cwd]
124
+ * @returns {string[]}
125
+ */
126
+ function noteFiles(cwd) {
127
+ const root = cwd || process.cwd()
128
+ const vaultDir = path.join(root, VAULT_DIR)
129
+ if (!fs.existsSync(vaultDir)) return []
130
+ return fs
131
+ .readdirSync(vaultDir)
132
+ .filter((f) => f.endsWith('.md') && f !== 'index.md')
133
+ }
134
+
135
+ /**
136
+ * Retorna true se o index.md referencia filename.
137
+ * @param {string} filename
138
+ * @param {string} [cwd]
139
+ * @returns {boolean}
140
+ */
141
+ function indexContains(filename, cwd) {
142
+ const root = cwd || process.cwd()
143
+ const indexPath = path.join(root, INDEX_FILE)
144
+ if (!fs.existsSync(indexPath)) return false
145
+ const content = fs.readFileSync(indexPath, 'utf8')
146
+ const nameWithoutExt = filename.replace(/\.md$/, '')
147
+ return (
148
+ content.includes(`(${filename})`) ||
149
+ content.includes(`[[${nameWithoutExt}]]`) ||
150
+ content.includes(`[[${filename}]]`)
151
+ )
152
+ }
153
+
154
+ module.exports = { newNote, appendNoteToIndex, noteFiles, indexContains, toSlug, today }