ganbatte-os 0.2.41 → 0.2.42

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 (78) hide show
  1. package/.gos/README.md +2 -6
  2. package/.gos/agents/profiles/ganbatte-os-master.md +91 -58
  3. package/.gos/agents/profiles/index.json +3 -1
  4. package/.gos/agents/profiles/perf-optimizer.md +10 -0
  5. package/.gos/agents/profiles/po.md +1 -1
  6. package/.gos/agents/profiles/security-auditor.md +11 -0
  7. package/.gos/agents/profiles/sm.md +4 -4
  8. package/.gos/agents/profiles/squad-creator.md +2 -2
  9. package/.gos/config.json +23 -2
  10. package/.gos/docs/curation.md +8 -6
  11. package/.gos/docs/gos_installation_guide.md +1 -1
  12. package/.gos/docs/plan-distribuicao-publica.md +2 -3
  13. package/.gos/docs/toolchain-map.md +2 -2
  14. package/.gos/libraries/doc-sync-policy.md +31 -0
  15. package/.gos/libraries/lazy-dev-policy.md +38 -0
  16. package/.gos/libraries/lucide-icons-policy.md +1 -1
  17. package/.gos/libraries/performance-audit-playbook.md +54 -0
  18. package/.gos/libraries/security-audit-playbook.md +63 -0
  19. package/.gos/manifests/g-os-runtime-manifest.json +29 -8
  20. package/.gos/playbooks/plan-creation-playbook.md +3 -5
  21. package/.gos/prompts/01-search.md +2 -2
  22. package/.gos/prompts/03-tasks.md +4 -4
  23. package/.gos/prompts/05-reviews.md +1 -1
  24. package/.gos/scripts/cli/gos-cli.js +16 -0
  25. package/.gos/scripts/hooks/claude-stop-summary.js +0 -16
  26. package/.gos/scripts/integrations/check-plan.js +15 -5
  27. package/.gos/scripts/integrations/setup-ide-adapters.js +72 -75
  28. package/.gos/scripts/tools/model-router.js +122 -0
  29. package/.gos/skills/execute-plan/SKILL.md +37 -23
  30. package/.gos/skills/perf-review/SKILL.md +58 -0
  31. package/.gos/skills/plan-blueprint/SKILL.md +26 -26
  32. package/.gos/skills/plan-to-tasks/SKILL.md +4 -1
  33. package/.gos/skills/progress-tracker/SKILL.md +3 -3
  34. package/.gos/skills/registry.json +3 -4
  35. package/.gos/skills/security-review/SKILL.md +59 -0
  36. package/.gos/skills/simplify-review/SKILL.md +59 -0
  37. package/.gos/skills/validate-plan/SKILL.md +29 -30
  38. package/.gos/squads/code-quality/README.md +20 -0
  39. package/.gos/squads/code-quality/squad.yaml +32 -0
  40. package/.gos/squads/code-quality/workflows/wf-code-quality.yaml +19 -0
  41. package/.gos/squads/design-delivery/README.md +1 -1
  42. package/.gos/squads/design-delivery/squad.yaml +4 -3
  43. package/.gos/squads/design-delivery/workflows/wf-design-delivery.yaml +6 -6
  44. package/.gos/templates/planTemplate.md +14 -5
  45. package/.gos/templates/specTemplate.md +68 -0
  46. package/.gos/templates/taskTemplate.md +8 -5
  47. package/AGENTS.md +0 -2
  48. package/CLAUDE.md +25 -9
  49. package/GEMINI.md +3 -3
  50. package/LICENSE +1 -1
  51. package/README.md +6 -8
  52. package/package.json +2 -3
  53. package/.gos/docs/slack-notifications.md +0 -219
  54. package/.gos/playbooks/sprint-planner-playbook.md +0 -127
  55. package/.gos/scripts/hooks/post-commit-notify.js +0 -175
  56. package/.gos/scripts/tools/clickup-preprocess.js +0 -218
  57. package/.gos/scripts/tools/clickup.js +0 -1058
  58. package/.gos/scripts/tools/slack-notify.js +0 -271
  59. package/.gos/skills/clickup/SKILL.md +0 -151
  60. package/.gos/skills/slack-review/SKILL.md +0 -91
  61. package/.gos/skills/sprint-planner/SKILL.md +0 -434
  62. package/.gos/skills/weekly-update/CHANGELOG.md +0 -165
  63. package/.gos/skills/weekly-update/SKILL.md +0 -361
  64. package/.gos/squads/sprint-planning/agents/sprint-chief.md +0 -47
  65. package/.gos/squads/sprint-planning/agents/sprint-planner-agent.md +0 -43
  66. package/.gos/squads/sprint-planning/agents/sprint-tracker.md +0 -43
  67. package/.gos/squads/sprint-planning/agents/task-importer.md +0 -44
  68. package/.gos/squads/sprint-planning/checklists/sprint-readiness.md +0 -27
  69. package/.gos/squads/sprint-planning/config/config.yaml +0 -65
  70. package/.gos/squads/sprint-planning/data/clickup-field-mapping.yaml +0 -94
  71. package/.gos/squads/sprint-planning/squad.yaml +0 -52
  72. package/.gos/squads/sprint-planning/tasks/close-sprint.md +0 -43
  73. package/.gos/squads/sprint-planning/tasks/create-sprint.md +0 -42
  74. package/.gos/squads/sprint-planning/tasks/import-tasks.md +0 -39
  75. package/.gos/squads/sprint-planning/tasks/sync-status.md +0 -31
  76. package/.gos/squads/sprint-planning/workflows/wf-sprint-creation.yaml +0 -59
  77. package/.gos/squads/sprint-planning/workflows/wf-sprint-sync.yaml +0 -35
  78. package/.gos/templates/sprint-clickup.template.md +0 -80
@@ -1,219 +0,0 @@
1
- # Slack Notifications — Pipeline com aprovação
2
-
3
- Workflow de notificações Slack que disparam a partir de commits com `T-NNN` no message. Tudo passa por uma fila de aprovação — nada é enviado sem revisão humana.
4
-
5
- ## Overview
6
-
7
- ```
8
- git commit -m "fix: ... Refs T-NNN"
9
-
10
-
11
- .git/hooks/post-commit (shim bash, define GANBATTE_ROOT)
12
-
13
-
14
- scripts/hooks/post-commit-sync.js
15
- │ 1. extrai T-NNN do message
16
- │ 2. lê registry.taskDetails + taskStatus
17
- │ 3. constrói payload via slack-notify.buildTaskDonePayload
18
- │ (sanitiza texto com text-sanitize.js)
19
- │ 4. chama slack-notify.enqueueDraft
20
-
21
- .gos/slack-queue/<timestamp>-<taskId>-<hash>.json (status: pending)
22
-
23
- │ [commit termina — nada foi enviado]
24
-
25
-
26
- /slack-review (Douglas roda quando quiser)
27
- │ lista drafts, mostra preview, AskUserQuestion
28
- │ ações: approve / edit / reject / skip
29
-
30
- node slack-queue.js approve <id>
31
- │ POST webhook Slack
32
-
33
- Slack #cspo-tech ← notificação enriquecida e revisada
34
-
35
-
36
- .gos/slack-queue/sent/<id>.json (histórico)
37
- ```
38
-
39
- ## Anatomia do payload
40
-
41
- Campos extraídos de `data/sprints/registry.json`:
42
-
43
- | Fonte | Campo | Uso no payload |
44
- |---|---|---|
45
- | `taskDetails[T-NNN].name` | nome da task | linha 2 do payload |
46
- | `taskDetails[T-NNN].assignee` | responsável | linha meta (primeiro nome) |
47
- | `taskDetails[T-NNN].sprint` | sprint | linha meta |
48
- | `taskDetails[T-NNN].ac[]` | array de ACs | rodapé — "N ACs" |
49
- | `taskStatus[T-NNN].points` | story points | linha meta |
50
- | `taskStatus[T-NNN].dueDate` | prazo | linha meta (MM/DD) |
51
- | `taskMap[T-NNN]` | ID ClickUp | link ClickUp no rodapé |
52
-
53
- Formato renderizado:
54
-
55
- ```
56
- :white_check_mark: T-110 concluída — S07 · Douglas · 8 pts · due 04/17
57
- Resolver drift TypeScript + instalar pre-commit hook
58
- > Commit: 54d8fe6 — fix: drift resolvido
59
- > 7 ACs · por Douglas Oliveira · <ClickUp>
60
- ```
61
-
62
- ## Pipeline de sanitização
63
-
64
- `text-sanitize.js` aplica, em ordem, sobre qualquer texto que entra em payload:
65
-
66
- 1. **Protege code fences** (```` ``` ````) e inline code (`` ` ``).
67
- 2. **P17 emoji-bullets**: remove emojis (✅ ❌ ⚠ 🚀 ⭐ 🎯 💡 🔧 🎉 🔥 👍 👌) no início de linhas.
68
- 3. **P14 em-dash entre palavras**: `word—word` → `word-word` (mantém travessão legítimo com espaços).
69
- 4. **Acentos pt-BR**: dicionário determinístico — `concluida → concluída`, `atualizacao → atualização`, ~80 termos.
70
- 5. **P07 vocabulário IA**: `aprimorar → melhorar`, `fomentar → estimular`, `crucial → importante`, ~25 termos com preservação de flexão (gerúndio, plural) e case.
71
- 6. **Restaura code spans** intactos.
72
-
73
- Estender dicionários: editar `AI_VOCAB` e `MISSING_ACCENTS` em `.gos/scripts/tools/text-sanitize.js`.
74
-
75
- ## Fila de aprovação
76
-
77
- **Localização**: `.gos/slack-queue/` (gitignored)
78
-
79
- **Estados**:
80
-
81
- | Estado | Diretório | Remoção |
82
- |---|---|---|
83
- | `pending` | `.gos/slack-queue/*.json` | manual (approve/reject) |
84
- | `sent` | `.gos/slack-queue/sent/*.json` | manual, após confirmação |
85
- | `rejected` | `.gos/slack-queue/rejected/*.json` | auditoria, manter histórico |
86
-
87
- **TTL**: sem expiração automática. Limpar manualmente `sent/` e `rejected/` a cada sprint via `rm -rf .gos/slack-queue/{sent,rejected}`.
88
-
89
- **Estrutura do draft**:
90
-
91
- ```json
92
- {
93
- "id": "20260417T143100-T110-54d8fe6",
94
- "createdAt": "2026-04-17T14:31:00Z",
95
- "taskId": "T-110",
96
- "commit": "54d8fe6",
97
- "channel": "default",
98
- "author": "Douglas Oliveira",
99
- "payload": { "text": "..." },
100
- "status": "pending"
101
- }
102
- ```
103
-
104
- ## Comandos
105
-
106
- ### slack-queue.js
107
-
108
- ```bash
109
- # Listar pendentes
110
- node .gos/scripts/tools/slack-queue.js list
111
- node .gos/scripts/tools/slack-queue.js list --json
112
-
113
- # Mostrar um draft
114
- node .gos/scripts/tools/slack-queue.js show <id>
115
-
116
- # Editar inline (abre $EDITOR / VISUAL / notepad no Windows)
117
- node .gos/scripts/tools/slack-queue.js edit <id>
118
-
119
- # Aprovar e enviar
120
- node .gos/scripts/tools/slack-queue.js approve <id>
121
-
122
- # Rejeitar
123
- node .gos/scripts/tools/slack-queue.js reject <id> --reason "duplicate"
124
-
125
- # Aprovar todos pendentes (CI, depois de revisão visual)
126
- node .gos/scripts/tools/slack-queue.js flush
127
- ```
128
-
129
- ### slack-notify.js
130
-
131
- ```bash
132
- # Enfileirar manualmente (default)
133
- node .gos/scripts/tools/slack-notify.js task-done \
134
- --task T-110 --commit 54d8fe6 --author "Douglas Oliveira" \
135
- --registry data/sprints/registry.json
136
-
137
- # Envio imediato sem fila (bypass revisão — usar só em CI)
138
- node .gos/scripts/tools/slack-notify.js task-done \
139
- --task T-110 --commit 54d8fe6 --author "Douglas Oliveira" \
140
- --registry data/sprints/registry.json --send-now
141
-
142
- # Dry-run (monta payload sem enviar nem enfileirar)
143
- node .gos/scripts/tools/slack-notify.js task-done \
144
- --task T-110 --commit 54d8fe6 --author "Douglas Oliveira" \
145
- --registry data/sprints/registry.json --send-now --dry-run
146
- ```
147
-
148
- ### text-sanitize.js
149
-
150
- ```bash
151
- # CLI
152
- node .gos/scripts/tools/text-sanitize.js --text "Task concluida aprimorando"
153
- node .gos/scripts/tools/text-sanitize.js --file path/to/content.md --json
154
- echo "texto sujo" | node .gos/scripts/tools/text-sanitize.js --stdin
155
-
156
- # Como módulo
157
- const { sanitize } = require('./.gos/scripts/tools/text-sanitize.js')
158
- const { text, changes } = sanitize(input)
159
- ```
160
-
161
- ## Skill `/slack-review`
162
-
163
- Ver `.gos/skills/slack-review/SKILL.md`. Wrapper interativo do `slack-queue.js list|show|edit|approve|reject` com preview renderizado e `AskUserQuestion` para cada ação.
164
-
165
- ## Como pular aprovação
166
-
167
- **CI / automação** onde revisão humana não faz sentido:
168
-
169
- ```bash
170
- node .gos/scripts/tools/slack-notify.js <cmd> --send-now
171
- ```
172
-
173
- **Flush programado** (ex: cron de fim de dia):
174
-
175
- ```bash
176
- node .gos/scripts/tools/slack-queue.js flush
177
- ```
178
-
179
- Usar com cuidado — fila existe justamente para evitar envio acidental.
180
-
181
- ## Troubleshooting
182
-
183
- ### Commit rodou mas fila não tem drafts
184
-
185
- - Verificar que o commit message contém `T-NNN` (regex `\bT-\d{3}\b`).
186
- - Confirmar hook instalado: `ls packages/fractus/.git/hooks/post-commit`.
187
- - Confirmar hook aponta para `$GANBATTE_ROOT/scripts/hooks/post-commit-sync.js` e exporta `GANBATTE_ROOT`.
188
- - Rodar manual: `cd packages/fractus && GANBATTE_ROOT=$(git rev-parse --show-superproject-working-tree || pwd) node ../../scripts/hooks/post-commit-sync.js`.
189
-
190
- ### Approve falha com "SLACK_WEBHOOK_URL not set"
191
-
192
- - Arquivo `.env` na raiz (`e:\Github\Ganbatte\.env`) contém `SLACK_WEBHOOK_URL=...`?
193
- - `slack-queue.js` carrega `.env` automaticamente via `loadRootEnv()` — se variável está no `.env` mas não é lida, conferir formatação (sem aspas extras, `KEY=VALUE` puro).
194
-
195
- ### Draft stuck em pending após approve
196
-
197
- - Abrir o JSON em `.gos/slack-queue/sent/<id>.json` — se existe, o envio OK mas `unlink` do original falhou (permission issue Windows). Remover manualmente.
198
- - Se não existe, o POST webhook falhou — ver output do comando (status HTTP + body).
199
-
200
- ### Edição travada
201
-
202
- - `edit` abre `$VISUAL` → `$EDITOR` → `notepad` (Windows) / `vi` (Unix). Se o editor não fechar, o comando fica bloqueado.
203
- - Alternativa: editar o JSON direto em `.gos/slack-queue/<id>.json` e rodar approve em seguida.
204
-
205
- ### Texto sanitizado incorretamente
206
-
207
- - Ver `changes[]` do sanitize: `node .gos/scripts/tools/text-sanitize.js --text "..." --json`.
208
- - Se uma substituição está errada, remover do dicionário em `text-sanitize.js:AI_VOCAB` / `MISSING_ACCENTS`.
209
- - Code spans (`` ` `` e ```` ``` ````) são preservados — se precisar isolar um termo, envolver em backticks.
210
-
211
- ## Referências
212
-
213
- - [`text-sanitize.js`](../scripts/tools/text-sanitize.js) — sanitizador
214
- - [`slack-queue.js`](../scripts/tools/slack-queue.js) — fila
215
- - [`slack-notify.js`](../scripts/tools/slack-notify.js) — payload + envio
216
- - [`post-commit-sync.js`](../../scripts/hooks/post-commit-sync.js) — hook
217
- - [`ai-writing-patterns.md`](../libraries/content/ai-writing-patterns.md) — catálogo base
218
- - [`humanizer`](../skills/humanizer/SKILL.md) — skill de humanização criativa
219
- - [`slack-review`](../skills/slack-review/SKILL.md) — skill de aprovação interativa
@@ -1,127 +0,0 @@
1
- # Sprint Planner — Playbook Operacional
2
-
3
- > Guia a execucao completa do sprint-planner: do input ate sprint montada com PRD, ADR, roadmap e tasks.
4
-
5
- ## Objetivo
6
-
7
- Transformar qualquer input (caminho de projeto, design Figma, transcricao, documento)
8
- em um pacote completo de sprint com artefatos prontos para execucao.
9
-
10
- ## Pre-requisitos
11
-
12
- - [ ] Input disponivel (caminho de projeto, design, transcricao ou descricao)
13
- - [ ] Acesso ao projeto/codebase (se for project-path)
14
- - [ ] Usuario disponivel para loops de discovery (15-30 min)
15
- - [ ] Branch correta (`dev` para framework, feature branch para projetos)
16
-
17
- ## Step 1 — Triage do Input (5 min)
18
-
19
- - [ ] Classificar tipo: project-path | design | transcription | document | free-text | mixed
20
- - [ ] Se project-path: executar `/project-brief <path>` para contexto
21
- - [ ] Se design: analise visual — extrair telas, fluxos, componentes
22
- - [ ] Se transcription: extrair requisitos, fluxos, restricoes, decisoes
23
- - [ ] Se document: ler, sumarizar, identificar gaps
24
- - [ ] Gerar `input-analysis.md`
25
- - [ ] Apresentar resumo ao usuario
26
-
27
- ## Step 2 — Discovery Loops (15-30 min)
28
-
29
- - [ ] Loop 1: Contexto e Objetivo (SCQA + Analise de Premissas)
30
- - [ ] Loop 2: Usuarios e Escopo (Task-Oriented Thought + Brainstorming)
31
- - [ ] Loop 3: Fluxos e Regras (Verificacao de Consistencia)
32
- - [ ] Loop 4 (se necessario): Dados e Restricoes (ReAct + Feynman)
33
- - [ ] Avaliar clarity checklist (>= 70%?)
34
- - [ ] Se < 70% apos 4 loops: consolidar e sinalizar gaps
35
-
36
- ## Step 3 — PRD (20-30 min)
37
-
38
- - [ ] Gerar `sprint-planner/<slug>/PRD.md`
39
- - [ ] Escopo IN/OUT explicito
40
- - [ ] Criterios de aceite verificaveis (Given/When/Then)
41
- - [ ] Decisoes menores embedded (contexto, opcoes, escolha)
42
- - [ ] **GATE: Usuario aprova PRD**
43
-
44
- ## Step 4 — Arquitetura & Schema (15-30 min)
45
-
46
- - [ ] Identificar decisoes arquiteturais significativas
47
- - [ ] Gerar `ADR-NNN.md` para cada decisao com 3+ opcoes e trade-offs
48
- - [ ] Se projeto envolve banco: gerar `schema.dbml`
49
- - [ ] Se projeto envolve APIs: listar endpoints com contratos
50
- - [ ] **GATE: Usuario aprova ADRs e schema**
51
-
52
- ## Step 5 — Roadmap (10 min)
53
-
54
- - [ ] Classificar complexidade: simples | medio | complexo
55
- - [ ] Gerar `ROADMAP.md` com fases, duracoes e entregaveis
56
- - [ ] Validar: soma duracoes <= total + 20% margem
57
- - [ ] Validar: cada fase tem pelo menos 1 entregavel concreto
58
- - [ ] **GATE: Fases e prazos validados**
59
-
60
- ## Step 6 — Task Decomposition (15-20 min)
61
-
62
- - [ ] Executar `/plan-to-tasks` no PRD
63
- - [ ] Validar: cada task max 1 dia, DoD mensuravel
64
- - [ ] User stories em Given/When/Then
65
- - [ ] Complexidade scoring (1-25) por story
66
- - [ ] Ordenar por dependencias
67
-
68
- ## Step 7 — Setup Tasks (10 min)
69
-
70
- - [ ] Detectar necessidades: contas, credenciais, infra, repos
71
- - [ ] Gerar tasks P0 com area devops/general
72
- - [ ] Incluir instrucoes passo-a-passo
73
- - [ ] Vincular como pre-requisitos das tasks de dev
74
-
75
- ## Step 8 — Sprint Assembly (10 min)
76
-
77
- - [ ] Gerar `SPRINT-OVERVIEW.md` consolidando tudo
78
- - [ ] Registrar decisoes no `memory/decision-log.json`
79
- - [ ] Apresentar resumo final ao usuario
80
- - [ ] Indicar proximos passos (qual skill usar para executar)
81
-
82
- ## Armadilhas Comuns
83
-
84
- | Armadilha | Sintoma | Solucao |
85
- |-----------|---------|---------|
86
- | Discovery infinito | Mais de 5 loops sem convergir | Consolidar o que tem, sinalizar gaps |
87
- | Scope creep no PRD | PRD com 20+ tasks | Dividir em 2+ sprints |
88
- | ADR para tudo | ADR para decisoes triviais | Embedded no PRD se < 3 opcoes |
89
- | Schema sem RLS | Tabelas sem politicas de seguranca | Sempre incluir nota sobre RLS |
90
- | Setup esquecido | Dev trava por falta de credencial | Phase 6 existe para isso |
91
- | Pular gates | Avancar sem aprovacao | Cada fase TEM que ter aprovacao |
92
-
93
- ## Tempo Estimado
94
-
95
- | Complexidade | Tempo total |
96
- |-------------|-------------|
97
- | Simples (escopo claro, 3-5 tasks) | 45-60 min |
98
- | Medio (ambiguidade moderada, 5-15 tasks) | 60-90 min |
99
- | Complexo (multi-dominio, 15+ tasks) | 90-150 min |
100
-
101
- ## Continuacao
102
-
103
- Apos sprint-planner concluir, o usuario escolhe como executar:
104
-
105
- | Objetivo | Comando |
106
- |----------|---------|
107
- | Executar spec-driven (completo) | `/sdd sprint-planner/<slug>/PRD.md` |
108
- | Orquestrar execucao (composicao) | `/compose TASK-YYYYMM-001` |
109
- | Refinar backlog | `@sm` ou `@po` |
110
- | Frontend direto | `/fe` com tasks geradas |
111
- | Backend direto | `/be` com tasks geradas |
112
-
113
- ## Referencias
114
-
115
- - `skills/sprint-planner/SKILL.md` — skill completa
116
- - `templates/adr-tmpl.yaml` — template ADR
117
- - `playbooks/story-creation-playbook.md` — formato de stories
118
- - `playbooks/gsd-agent-decomposition-playbook.md` — padrao de handoff por artefatos
119
- - `skills/sdd/SKILL.md` — para continuacao com execucao
120
- - `skills/plan-to-tasks/SKILL.md` — decomposicao em tasks
121
-
122
- ## Cadencia Sugerida
123
-
124
- - Ao iniciar qualquer projeto novo (greenfield)
125
- - Ao receber novo escopo ou fase de projeto existente (brownfield)
126
- - Quando receber designs Figma ou transcricoes de reuniao para planejar
127
- - Antes de sprints que envolvem multiplos dominios (FE + BE + infra)
@@ -1,175 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // post-commit-notify.js — Post-commit hook: marks tasks done in ClickUp + notifies Slack
4
- // Trigger: Claude Code Stop hook or git post-commit
5
- // Rule: ALWAYS exit 0 (observation hook, never blocks)
6
-
7
- const { execFileSync } = require('node:child_process')
8
- const { existsSync, readFileSync } = require('node:fs')
9
- const { resolve } = require('node:path')
10
-
11
- // Find repo root
12
- function findRepoRoot() {
13
- try {
14
- return execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf-8' }).trim()
15
- } catch {
16
- return process.cwd()
17
- }
18
- }
19
-
20
- // Parse last commit
21
- function getLastCommit() {
22
- try {
23
- const log = execFileSync('git', ['log', '-1', '--format=%H|%s|%an'], { encoding: 'utf-8' }).trim()
24
- const sepIdx = log.indexOf('|')
25
- const hash = log.slice(0, sepIdx)
26
- const rest = log.slice(sepIdx + 1)
27
- const lastSep = rest.lastIndexOf('|')
28
- const message = rest.slice(0, lastSep)
29
- const author = rest.slice(lastSep + 1)
30
- return { hash, message, author }
31
- } catch {
32
- return null
33
- }
34
- }
35
-
36
- // Extract task refs from commit message (T-NNN pattern)
37
- function extractTaskRefs(message) {
38
- const matches = message.match(/\bT-(\d{3})\b/g)
39
- return matches ? [...new Set(matches)] : []
40
- }
41
-
42
- // Load sprint registry to resolve local IDs -> ClickUp IDs
43
- function loadRegistry(repoRoot) {
44
- const paths = [
45
- resolve(repoRoot, 'data/sprints/registry.json'),
46
- resolve(repoRoot, '.gos/data/sprints/registry.json'),
47
- ]
48
- for (const p of paths) {
49
- if (existsSync(p)) {
50
- try {
51
- return { data: JSON.parse(readFileSync(p, 'utf-8')), path: p }
52
- } catch { continue }
53
- }
54
- }
55
- return { data: { version: '1.0', sprints: [], taskMap: {}, taskSprintMap: {} }, path: paths[0] }
56
- }
57
-
58
- // Run a CLI tool safely (no shell injection)
59
- function runTool(repoRoot, tool, toolArgs) {
60
- const toolPaths = [
61
- resolve(repoRoot, `.gos/scripts/tools/${tool}`),
62
- resolve(repoRoot, `scripts/tools/${tool}`),
63
- ]
64
- const toolPath = toolPaths.find(p => existsSync(p))
65
- if (!toolPath) return null
66
-
67
- try {
68
- const result = execFileSync('node', [toolPath, ...toolArgs], {
69
- encoding: 'utf-8',
70
- timeout: 15000,
71
- env: process.env,
72
- })
73
- return JSON.parse(result)
74
- } catch (e) {
75
- return { error: e.message }
76
- }
77
- }
78
-
79
- // Detect if commit implies task completion
80
- function isCompletionCommit(message) {
81
- const completionPatterns = [
82
- /^feat[:(]/i,
83
- /^fix[:(]/i,
84
- /\b(close[sd]?|complete[sd]?|finish|done|resolve[sd]?)\b/i,
85
- ]
86
- return completionPatterns.some(p => p.test(message))
87
- }
88
-
89
- // Detect if commit is a start/WIP commit
90
- function isStartCommit(message) {
91
- const startPatterns = [
92
- /^(wip|chore|progress|draft|start|refactor|test|docs|style)[:(]/i,
93
- /\b(wip|in.?progress|draft|start)\b/i,
94
- ]
95
- return startPatterns.some(p => p.test(message))
96
- }
97
-
98
- // Find sprint for a task reference
99
- function findSprintForTask(registry, taskRef) {
100
- if (registry.taskSprintMap?.[taskRef]) {
101
- return registry.sprints.find(s => s.id === registry.taskSprintMap[taskRef]) || null
102
- }
103
- return registry.sprints.filter(s => !s.end || new Date(s.end) >= new Date())
104
- .sort((a, b) => new Date(b.start) - new Date(a.start))[0] || null
105
- }
106
-
107
- async function main() {
108
- const repoRoot = findRepoRoot()
109
- const commit = getLastCommit()
110
- if (!commit) return
111
-
112
- const taskRefs = extractTaskRefs(commit.message)
113
- if (taskRefs.length === 0) return
114
-
115
- const hasClickUp = !!process.env.CLICKUP_API_KEY
116
- const hasSlack = !!process.env.SLACK_WEBHOOK_URL
117
- if (!hasClickUp && !hasSlack) return
118
-
119
- const { data: registry } = loadRegistry(repoRoot)
120
- const shouldComplete = isCompletionCommit(commit.message)
121
- const shouldStart = isStartCommit(commit.message)
122
-
123
- for (const ref of taskRefs) {
124
- const clickupId = registry.taskMap?.[ref]
125
-
126
- // Update ClickUp task status
127
- if (hasClickUp && clickupId) {
128
- if (shouldComplete) {
129
- runTool(repoRoot, 'clickup.js', ['task', 'update', '--task-id', clickupId, '--status', 'complete'])
130
- } else if (shouldStart) {
131
- runTool(repoRoot, 'clickup.js', ['task', 'update', '--task-id', clickupId, '--status', 'in progress'])
132
- }
133
- }
134
-
135
- // Notify Slack
136
- if (hasSlack) {
137
- const status = shouldComplete ? 'concluida' : shouldStart ? 'em andamento' : 'atualizada'
138
- runTool(repoRoot, 'slack-notify.js', [
139
- 'task-update',
140
- '--task', ref,
141
- '--status', status,
142
- '--commit', commit.hash,
143
- '--author', commit.author,
144
- '--message', commit.message,
145
- ])
146
- }
147
-
148
- // Sprint completion check (if task completed)
149
- if (shouldComplete) {
150
- const sprint = findSprintForTask(registry, ref)
151
- if (sprint) {
152
- const tasksInSprint = Object.entries(registry.taskSprintMap || {})
153
- .filter(([, sid]) => sid === sprint.id)
154
- .map(([tid]) => tid)
155
- const completedTasks = tasksInSprint.filter(tid => {
156
- const cuId = registry.taskMap?.[tid]
157
- if (!cuId) return false
158
- return true
159
- })
160
- if (tasksInSprint.length > 0 && completedTasks.length === tasksInSprint.length) {
161
- if (hasSlack) {
162
- runTool(repoRoot, 'slack-notify.js', [
163
- 'sprint-complete',
164
- '--sprint', sprint.id,
165
- '--name', sprint.name,
166
- '--tasks', tasksInSprint.join(', '),
167
- ])
168
- }
169
- }
170
- }
171
- }
172
- }
173
- }
174
-
175
- main().catch(() => {}).finally(() => process.exit(0))