@polymorphism-tech/morph-spec 5.0.1 → 7.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 (38) hide show
  1. package/README.md +19 -18
  2. package/docs/CHEATSHEET.md +3 -3
  3. package/docs/QUICKSTART.md +4 -4
  4. package/framework/CLAUDE.md +13 -0
  5. package/framework/MORPH.md +57 -36
  6. package/framework/commands/morph-apply.md +4 -21
  7. package/framework/commands/morph-archive.md +1 -1
  8. package/framework/commands/morph-proposal.md +2 -0
  9. package/framework/hooks/claude-code/core/enforce-phase-writes.js +1 -1
  10. package/framework/hooks/claude-code/core/protect-spec-files.js +1 -1
  11. package/framework/hooks/claude-code/core/state-sync.js +212 -0
  12. package/framework/hooks/shared/phase-utils.js +5 -4
  13. package/framework/hooks/shared/state-reader.js +1 -1
  14. package/framework/phases.json +1 -1
  15. package/framework/rules/morph-workflow.md +15 -34
  16. package/framework/schemas/tasks.schema.json +35 -0
  17. package/framework/skills/core/morph-apply/SKILL.md +154 -0
  18. package/framework/skills/core/morph-brainstorming/SKILL.md +53 -30
  19. package/framework/skills/core/morph-implement/SKILL.md +25 -14
  20. package/framework/skills/core/morph-plan/SKILL.md +91 -23
  21. package/framework/skills/core/morph-proposal/SKILL.md +137 -0
  22. package/framework/skills/core/morph-review/SKILL.md +43 -7
  23. package/framework/skills/core/morph-stack-scan/SKILL.md +40 -1
  24. package/framework/standards/STANDARDS.json +4 -5
  25. package/framework/templates/docs/onboarding.md +4 -4
  26. package/framework/templates/tasks.template.json +17 -0
  27. package/package.json +1 -1
  28. package/src/commands/project/init.js +16 -0
  29. package/src/commands/validation/validate-feature.js +1 -1
  30. package/src/core/paths/output-schema.js +6 -6
  31. package/src/core/state/state-manager.js +1 -1
  32. package/src/lib/detectors/design-system-detector.js +1 -1
  33. package/src/lib/installers/memory-installer.js +138 -0
  34. package/src/lib/phase-chain/phase-validator.js +4 -4
  35. package/src/lib/risk-detector.js +80 -0
  36. package/src/lib/tasks/tasks-json-parser.js +185 -0
  37. package/src/scripts/setup-infra.js +25 -0
  38. package/src/utils/hooks-installer.js +59 -10
package/README.md CHANGED
@@ -67,11 +67,11 @@ your-project/
67
67
  │ ├── context/ # Project context (README.md, standards.md)
68
68
  │ ├── features/ # Active features
69
69
  │ │ └── {feature}/
70
- │ │ ├── 0-proposal/ # User story + acceptance criteria
71
- │ │ ├── 1-ui/ # UI/UX design (optional, UI-heavy features)
72
- │ │ ├── 2-design/ # Technical spec, contracts, decisions
73
- │ │ ├── 3-tasks/ # Atomic task list
74
- │ │ └── 4-implement/ # Recap and implementation notes
70
+ │ │ ├── 0-proposal/ # Problem statement + acceptance criteria
71
+ │ │ ├── 1-design/ # UI/UX design (optional, UI-heavy features)
72
+ │ │ ├── 2-plan/ # spec.md + mandate.md + tasks.json
73
+ │ │ ├── 3-implement/ # Recap and implementation notes
74
+ │ │ └── 4-review/ # Review report + Gate 3
75
75
  │ └── state.json # READ-ONLY — managed by CLI only
76
76
  └── .claude/
77
77
  ├── commands/ # Slash commands
@@ -88,29 +88,30 @@ your-project/
88
88
  Features move through structured phases. Some are optional depending on feature type.
89
89
 
90
90
  ```
91
- proposal → [uiux] → design → plan → tasks → implement → [sync]
91
+ proposal → [design] → plan → implement → review
92
92
  ```
93
93
 
94
- Phases in brackets are optional. `uiux` applies to UI-heavy features. `sync` is a post-implementation reconciliation step.
94
+ `design` is optional — applies only to UI-heavy features.
95
95
 
96
96
  ### Phase outputs
97
97
 
98
98
 
99
- | Phase | Directory | Key files |
100
- | --------- | -------------- | ------------------------------------------------------------- |
101
- | Proposal | `0-proposal/` | `proposal.md` |
102
- | UI/UX | `1-ui/` | `design-system.md`, `mockups.md`, `components.md`, `flows.md` |
103
- | Design | `2-design/` | `spec.md`, `contracts.cs`, `decisions.md` |
104
- | Plan | `3-plan/` | `plan.md` |
105
- | Tasks | `4-tasks/` | `tasks.md` |
106
- | Implement | `5-implement/` | `recap.md` |
99
+ | Phase | Directory | Key files |
100
+ | --------- | --------------- | ------------------------------------------------------------------ |
101
+ | Proposal | `0-proposal/` | `proposal.md`, `stack-scan.md`, `migration-plan.md` (optional) |
102
+ | Design | `1-design/` | `design-system.md`, `mockups.md`, `components.md`, `flows.md` |
103
+ | Plan | `2-plan/` | `spec.md`, `mandate.md`, `tasks.json`, `decisions.md` |
104
+ | Implement | `3-implement/` | `recap.md` + source code |
105
+ | Review | `4-review/` | `review-report.md` |
107
106
 
108
107
 
109
108
  ### Approval gates
110
109
 
111
- - **Design gate** — Spec must be approved before moving to Plan.
112
- - **Plan gate** — Plan must be approved before moving to Tasks.
113
- - **Tasks gate** — Task list must be approved before implementation starts.
110
+ - **Gate 1 (Proposal)** — Problem statement must be approved before plan.
111
+ - **Gate 2 (Plan)** — Spec + mandate + tasks must be approved before implement.
112
+ - **Gate 3 (Review)** — Review report must be approved before archive.
113
+
114
+ In `trust: "auto"` mode (default), gates auto-pass without risk signals. See `framework/MORPH.md` for risk-signal details.
114
115
 
115
116
  Check gate status:
116
117
 
@@ -25,11 +25,11 @@ Phases in brackets are optional.
25
25
  | Phase | Directory | Output files | Gate |
26
26
  |-------|-----------|--------------|------|
27
27
  | proposal | `0-proposal/` | `proposal.md` | ✅ Approval |
28
- | uiux *(optional)* | `1-ui/` | `design-system.md`, `mockups.md`, `components.md`, `flows.md` | ✅ Approval |
28
+ | uiux *(optional)* | `1-design/` | `design-system.md`, `mockups.md`, `components.md`, `flows.md` | ✅ Approval |
29
29
  | design | `2-design/` | `spec.md`, `contracts.cs`, `decisions.md` | ✅ Approval |
30
30
  | plan | `3-plan/` | `plan.md` | ✅ Approval |
31
31
  | tasks | `4-tasks/` | `tasks.md` | ✅ Approval |
32
- | implement | `5-implement/` | code + `recap.md` | — |
32
+ | implement | `3-implement/` | code + `recap.md` | — |
33
33
  | sync *(optional)* | — | standards updated | — |
34
34
 
35
35
  ---
@@ -154,7 +154,7 @@ morph-spec approval-status {feature} # show gate status
154
154
  ├── features/
155
155
  │ └── {feature}/
156
156
  │ ├── 0-proposal/proposal.md
157
- │ ├── 1-ui/design-system.md, mockups.md, components.md, flows.md
157
+ │ ├── 1-design/design-system.md, mockups.md, components.md, flows.md
158
158
  │ ├── 2-design/spec.md, contracts.cs, decisions.md
159
159
  │ ├── 3-tasks/tasks.md
160
160
  │ └── 4-implement/recap.md
@@ -57,10 +57,10 @@ Loads project context from `.morph/context/`, confirms stack and active agents.
57
57
  ### Phase 2 — UI/UX (conditional)
58
58
 
59
59
  Only runs if frontend agents are active. Claude generates:
60
- - `1-ui/design-system.md` — colors, typography, spacing
61
- - `1-ui/mockups.md` — ASCII wireframes
62
- - `1-ui/components.md` — component specs
63
- - `1-ui/flows.md` — user flows and edge cases
60
+ - `1-design/design-system.md` — colors, typography, spacing
61
+ - `1-design/mockups.md` — ASCII wireframes
62
+ - `1-design/components.md` — component specs
63
+ - `1-design/flows.md` — user flows and edge cases
64
64
 
65
65
  You approve the UI design before design phase begins.
66
66
 
@@ -52,4 +52,17 @@ Se não houver feature ativa, pergunte ao usuário qual feature trabalhar.
52
52
  7 personas de domínio dispatchávels via Agent tool:
53
53
  `dotnet-senior`, `ef-modeler`, `maf-expert`, `nextjs-expert`, `ui-designer`, `infra-engineer`, `evaluator`.
54
54
 
55
+ ## Regra de precedência de skills
56
+
57
+ Em projetos morph-spec, prefira as skills `morph-*` sobre as equivalentes `superpowers:*`:
58
+
59
+ | Em vez de | Use |
60
+ |-----------|-----|
61
+ | `superpowers:brainstorming` | `morph-brainstorming` |
62
+ | `superpowers:writing-plans` | `morph-plan` |
63
+ | `superpowers:executing-plans` | `morph-apply` |
64
+ | `superpowers:test-driven-development` | seguir `mandate.md` (TDD está embutido) |
65
+
66
+ As skills `morph-*` aplicam Gates, leem o estado da feature em `.morph/` e produzem outputs com os paths corretos. As `superpowers:*` são genéricas e não conhecem o contexto morph-spec.
67
+
55
68
  *MORPH-SPEC v5 by Polymorphism Tech*
@@ -15,7 +15,7 @@ Entre gates, você opera com autonomia total. O dev valida. Você executa.
15
15
  | Situação | O que você faz |
16
16
  |-----------------------------------------------------------------------|-------------------------------------------------------------------------------|
17
17
  | Gate 1 / 2 / 3 aprovado | Avançar para próxima fase imediatamente |
18
- | Tarefa completada na fase implement | Iniciar a próxima tarefa do tasks.md sem aguardar instrução |
18
+ | Tarefa completada na fase implement | Iniciar a próxima task do tasks.json sem aguardar instrução |
19
19
  | Ambiguidade de escopo coberta pelo mandate | Resolver conservadoramente e registrar em decisions.md |
20
20
  | Ambiguidade bloqueante (requisito ausente ou contraditório) | UMA pergunta via AskUserQuestion |
21
21
  | Sub-agent com auto-score ≥ 7 | Integrar ao recap.md e continuar |
@@ -76,14 +76,14 @@ Os papéis não são exclusivos — numa sessão longa você transita entre Orch
76
76
 
77
77
  O fluxo padrão de uma feature tem quatro fases. Cada fase tem uma pasta dedicada em `.morph/features/{feature}/`.
78
78
 
79
- | Fase | Pasta | Gate | O que termina a fase |
80
- |-------------|----------------|-------------------|-----------------------------------------------|
81
- | proposal | `0-proposal/` | Aprovação humana | `proposal.md` aprovado e commitado |
82
- | plan | `2-plan/` | Aprovação humana | `spec.md`, `mandate.md`, `tasks.md` aprovados |
83
- | implement | `3-implement/` | Nenhum | Todas as tarefas do tasks.md com status Done |
84
- | review | `4-review/` | Aprovação humana | `review-report.md` aprovado e commitado |
79
+ | Fase | Pasta | Gate | O que termina a fase |
80
+ |-------------|----------------|-----------------------|-------------------------------------------------|
81
+ | proposal | `0-proposal/` | Gate 1 (trust-aware) | `proposal.md` aprovado e commitado |
82
+ | plan | `2-plan/` | Gate 2 (trust-aware) | `spec.md`, `mandate.md`, `tasks.json` aprovados |
83
+ | implement | `3-implement/` | Nenhum | Todas as tasks do tasks.json com status `done` |
84
+ | review | `4-review/` | Gate 3 (trust-aware) | `review-report.md` aprovado e commitado |
85
85
 
86
- A fase `1-ui/` (design system, mockups, flows) é opcional — aplica-se apenas a features com componentes de UI novos e deve ser explicitamente requisitada pelo usuário.
86
+ A fase `1-design/` (design system, mockups, flows) é opcional — aplica-se apenas a features com componentes de UI novos e deve ser explicitamente requisitada pelo usuário.
87
87
 
88
88
  Não avance de fase sem o gate correspondente ter sido confirmado.
89
89
 
@@ -104,7 +104,7 @@ Não invente caminhos alternativos.
104
104
 
105
105
  - `mandate.md` — contrato de implementação: stack exata, standards obrigatórios (com links), patterns explicitamente proibidos, checklist de done com critérios verificáveis. O mandate.md é lido no início de cada tarefa de implementação — deve ser específico o suficiente para resolver ambiguidades sem consultar o Orchestrator.
106
106
 
107
- - `tasks.md` — lista ordenada de tarefas com IDs únicos (T1, T2...), dependências explícitas entre tarefas, estimativa de esforço, critério de done verificável por tarefa. Cada entrada no recap.md deve referenciar um ID do tasks.md.
107
+ - `tasks.json` — task list estruturada validada contra `framework/schemas/tasks.schema.json`. Cada task tem `id` (T1, T2...), `title`, `description`, `dependencies` (array de IDs), `effort` (S/M/L/XL), `doneCriteria`, `status` (pending/in_progress/done/skipped/blocked) e `outputs` (paths esperados). Cada entrada no recap.md deve referenciar um ID do tasks.json.
108
108
 
109
109
  - `decisions.md` — log de decisões técnicas: qual era a alternativa, por que foi descartada, quem decidiu. Criado quando surgir a primeira decisão não trivial. Não é obrigatório — só existe se houver decisões que precisam de rastreabilidade.
110
110
 
@@ -148,29 +148,42 @@ O agente responsável por um domínio está listado em `framework/agents.json`.
148
148
 
149
149
  ---
150
150
 
151
- ## 5. Gates de Aprovação
151
+ ## 5. Gates de Aprovação (Trust Mode)
152
152
 
153
- Gates são pontos obrigatórios de pausa. Não avance sem confirmação humana explícita.
153
+ Gates são pontos de **pausa potencial**. Em `trust: "auto"` (default), gates **auto-passam** se nenhum sinal de risco for detectado — apenas exibem um summary curto. Em `trust: "manual"` OU se um sinal de risco fizer fire, o gate pausa via `AskUserQuestion` com options padrão:
154
154
 
155
- **Gate 1 — Proposta aprovada**
156
- Condição: o usuário leu e aprovou o `proposal.md`.
157
- Como ativar: apresente o proposal, aguarde resposta explícita ("aprovado", "pode avançar", "lgtm" ou equivalente).
158
- Nunca assuma aprovação silenciosa. Se o usuário responder com uma pergunta, responda a pergunta e reapresente o gate.
159
- Sinal de gate aberto: resposta que confirma que pode avançar para o planejamento.
155
+ ```
156
+ - "aprovado, prosseguir"
157
+ - "preciso ajustar"
158
+ - "cancelar feature" (Gate 3 usa "rollback" em vez de "cancelar")
159
+ ```
160
160
 
161
- **Gate 2 — Plano aprovado**
162
- Condição: o usuário leu e aprovou `spec.md`, `mandate.md` e `tasks.md`.
163
- Como ativar: use o template de apresentação do Gate 2 em `framework/skills/core/morph-plan/SKILL.md` passo 5. Apresente o gate completo — spec em uma frase, mandate resumido, tasks com estimativa, decisões de arquitetura se houver.
164
- Se o usuário pedir ajustes, aplique e reapresente o gate completo antes de avançar.
165
- Sinal de gate aberto: aprovação explícita de todos os três artefatos, ou "pode implementar".
166
- Atenção: aprovação parcial ("o spec está bom") não abre o gate — todos os três precisam ser confirmados.
161
+ **Sinais de risco que forçam pausa em auto** (detectados via `src/lib/risk-detector.js`):
167
162
 
168
- **Gate 3 — Review aprovado**
169
- Condição: o usuário leu e aprovou o `review-report.md`.
170
- Como ativar: apresente o relatório com scores e feedback. Se houver itens bloqueantes (score < 6), não apresente o gate — corrija primeiro, reavalite, então apresente o relatório final.
171
- Sinal de gate aberto: aprovação do review-report.md com ciência dos scores.
163
+ | Sinal | Threshold | Quando aplica |
164
+ |-------|-----------|---------------|
165
+ | `designSystemDivergence` | true | Brainstorming detecta fontes conflitantes (spec antigo vs bundle local) |
166
+ | `standardsViolations` | array.length > 0 | Mandate ou implementation viola padrões proibidos |
167
+ | `evalScore` | < 8 | morph-eval/morph-review produz score abaixo do mínimo |
168
+ | `taskCount` | > 20 | Escopo grande — provavelmente vale revisar antes de implementar |
172
169
 
173
- **Comportamento padrão fora de gate:** trabalhe com autonomia total. Gates só existem nestes três pontos. Não pause para confirmação no meio de implementação a menos que encontre uma ambiguidade de escopo que o mandate não cobre — nesse caso, registre a ambiguidade no decisions.md, resolva da forma mais conservadora possível, e sinalize na entrega da tarefa.
170
+ **Gate 1 — Proposta**
171
+ - Sinais: `designSystemDivergence`, `standardsViolations` (improvável).
172
+ - Skill responsável: `morph-brainstorming`.
173
+
174
+ **Gate 2 — Plano**
175
+ - Sinais: todos do Gate 1 + `taskCount`, `standardsViolations` em mandate.
176
+ - Skill responsável: `morph-plan`.
177
+
178
+ **Gate 3 — Review**
179
+ - Sinais: `evalScore` composite, `standardsViolations` detectadas em implementation.
180
+ - Skill responsável: `morph-review`.
181
+
182
+ Para alterar o modo: editar `.morph/config/config.json → trust` (`"auto"` ou `"manual"`). Configs sem o campo `trust` defaultam para `"auto"`.
183
+
184
+ **Comportamento padrão fora de gate:** trabalhe com autonomia total. Gates só existem nestes três pontos. Não pause para confirmação no meio de implementação a menos que encontre uma ambiguidade de escopo que o mandate não cobre — nesse caso, registre a ambiguidade no decisions.md, resolva da forma mais conservadora possível, e sinalize na entrega da task.
185
+
186
+ **O hook state-sync.js** detecta as respostas dos Gates automaticamente: quando uma `AskUserQuestion` é respondida com label começando em "aprovado", marca o gate correspondente em `.morph/state.json`. Em modo auto sem AskUserQuestion, a skill atualiza state.json diretamente (allowlist permite Edit em `.morph/state.json`).
174
187
 
175
188
  ---
176
189
 
@@ -219,15 +232,23 @@ O padrão de dispatch e o template de prompt para sub-agents estão detalhados e
219
232
  Skills são documentos de instrução que você invoca sob demanda. Eles ficam em `framework/skills/core/`.
220
233
  Não invoque uma skill fora do momento indicado.
221
234
 
222
- | Skill | Path | Quando invocar |
223
- |-----------------------|----------------------------------------------------|-------------------------------------------------------------|
224
- | morph-brainstorming | `framework/skills/core/morph-brainstorming/SKILL.md` | Ao receber um novo request de feature (antes de morph-plan) |
225
- | morph-stack-scan | `framework/skills/core/morph-stack-scan/SKILL.md` | Em projetos existentes, para detectar desvios de stack |
226
- | morph-plan | `framework/skills/core/morph-plan/SKILL.md` | Ao iniciar a fase de planejamento |
227
- | morph-implement | `framework/skills/core/morph-implement/SKILL.md` | Ao iniciar cada tarefa de implementação |
228
- | morph-eval | `framework/skills/core/morph-eval/SKILL.md` | Após concluir uma tarefa ou fase |
229
- | morph-review | `framework/skills/core/morph-review/SKILL.md` | Ao iniciar a fase de revisão |
230
- | morph-standards | `framework/skills/core/morph-standards/SKILL.md` | Quando precisar localizar ou aplicar um standard específico |
235
+ | Skill | Path | Quando invocar |
236
+ |-----------------------|----------------------------------------------------|-------------------------------------------------------------------------|
237
+ | **morph-proposal** | `framework/skills/core/morph-proposal/SKILL.md` | **Orquestrador**: brainstorming → Gate 1 → plan → Gate 2 (entry point) |
238
+ | **morph-apply** | `framework/skills/core/morph-apply/SKILL.md` | **Orquestrador**: DAG-adaptive implement loop → review → Gate 3 |
239
+ | morph-brainstorming | `framework/skills/core/morph-brainstorming/SKILL.md` | Invocada pela morph-proposal — entendimento de negócio + stack-scan |
240
+ | morph-stack-scan | `framework/skills/core/morph-stack-scan/SKILL.md` | Detecta stack atual; curto-circuita em greenfield |
241
+ | morph-plan | `framework/skills/core/morph-plan/SKILL.md` | Invocada pela morph-proposal — produz spec/mandate/tasks.json |
242
+ | morph-implement | `framework/skills/core/morph-implement/SKILL.md` | Invocada pela morph-apply — executa cada task |
243
+ | morph-eval | `framework/skills/core/morph-eval/SKILL.md` | Após concluir uma task ou fase |
244
+ | morph-review | `framework/skills/core/morph-review/SKILL.md` | Invocada pela morph-apply — produz review-report + Gate 3 |
245
+ | morph-standards | `framework/skills/core/morph-standards/SKILL.md` | Quando precisar localizar ou aplicar um standard específico |
246
+
247
+ **Entry points** para o usuário:
248
+ - `/morph-proposal {feature}` → invoca `Skill(morph-proposal)`, que orquestra brainstorming + plan
249
+ - `/morph-apply {feature}` → invoca `Skill(morph-apply)`, que orquestra implement + review
250
+
251
+ Os slash commands são atalhos: o agente pode chamar `Skill(morph-proposal)` diretamente quando o usuário pede "use /morph-proposal".
231
252
 
232
253
  Cada skill contém instruções de execução passo a passo. Leia, siga, não desvie sem justificativa registrada no recap.md.
233
254
 
@@ -6,7 +6,9 @@ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Agent, AskUserQuestion, Skil
6
6
 
7
7
  # /morph-apply — NLH Implementation
8
8
 
9
- Executa as tarefas do `tasks.md` em sequência sem pausa, depois apresenta o Gate 3.
9
+ Executa as tasks de uma feature até o Gate 3.
10
+
11
+ **Implementação:** este slash command é um atalho. O agente deve invocar `Skill(morph-apply)` com o nome da feature. A skill decide adaptativamente entre execução sequencial (auto-advance entre tasks) ou paralela (Agent dispatch para tasks independentes) baseado no DAG do `tasks.json`. Termina com `morph-review` + Gate 3 trust-aware.
10
12
 
11
13
  ## Argumentos
12
14
 
@@ -17,29 +19,10 @@ Executa as tarefas do `tasks.md` em sequência sem pausa, depois apresenta o Gat
17
19
  Antes de começar, verifique:
18
20
  - `.morph/features/{feature-name}/2-plan/spec.md` existe
19
21
  - `.morph/features/{feature-name}/2-plan/mandate.md` existe
20
- - `.morph/features/{feature-name}/2-plan/tasks.md` existe
21
- - `.morph/features/{feature-name}/3-implement/recap.md` existe ou pode ser criado
22
+ - `.morph/features/{feature-name}/2-plan/tasks.json` existe e é válido contra o schema
22
23
 
23
24
  Se algum estiver faltando, abortar e pedir ao usuário para rodar `/morph-proposal {feature-name}` primeiro.
24
25
 
25
- ## Fluxo
26
-
27
- 1. **Loop de tarefas** — para cada tarefa pendente em `tasks.md`:
28
- - Invocar a skill `morph-implement` em `framework/skills/core/morph-implement/`.
29
- - A skill executa a tarefa, registra em `recap.md`, atualiza o trace.
30
- - **Auto-advance:** ao concluir uma tarefa, passar imediatamente para a próxima sem aguardar instrução do usuário.
31
- - Pausar apenas se encontrar ambiguidade bloqueante não coberta pelo `mandate.md`.
32
-
33
- 2. **Após todas as tarefas concluídas, invocar `morph-review`** (skill em `framework/skills/core/morph-review/`):
34
- - Lê `mandate.md` e `recap.md`.
35
- - Aplica `morph-eval` para gerar scores por dimensão.
36
- - Produz `review-report.md` em `.morph/features/{feature-name}/4-review/`.
37
- - Apresenta o **Gate 3**.
38
-
39
- 3. **Aguardar aprovação do Gate 3.**
40
- - Resposta válida: "aprovado", "merge".
41
- - Se houver itens bloqueantes (score < 6): corrija antes de apresentar o gate.
42
-
43
26
  ## Anti-padrões
44
27
 
45
28
  - Não pausar entre tarefas para confirmação — o tasks.md já foi aprovado no Gate 2.
@@ -30,7 +30,7 @@ If any precondition fails, stop and report what is missing instead of archiving.
30
30
  .morph/features/{feature}/ → .morph/archive/{feature}/
31
31
  ```
32
32
  Use `Bash` (`mv` on POSIX, `Move-Item` on Windows). Preserve all phase subfolders
33
- (`0-proposal/`, `1-ui/`, `2-plan/`, `3-implement/`, `4-review/`).
33
+ (`0-proposal/`, `1-design/`, `2-plan/`, `3-implement/`, `4-review/`).
34
34
 
35
35
  3. **Update state.json**:
36
36
  - Set `features[name].status = 'completed'`
@@ -8,6 +8,8 @@ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Agent, AskUserQuestion, Skil
8
8
 
9
9
  Conduz a feature do request inicial até o Gate 2 (plano aprovado), sem intervenção do usuário entre os gates.
10
10
 
11
+ **Implementação:** este slash command é um atalho. O agente deve invocar `Skill(morph-proposal)` com o nome da feature como argumento. A skill encadeia automaticamente `morph-brainstorming` → Gate 1 → `morph-plan` → Gate 2. Em `trust: "auto"` (default), gates auto-passam sem sinais de risco.
12
+
11
13
  ## Argumentos
12
14
 
13
15
  `{feature-name}` — nome em kebab-case da feature.
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Ensures writes to .morph/features/{feature}/ go to the current phase's subfolder:
9
9
  * proposal → only 0-proposal/
10
- * uiux → only 1-ui/
10
+ * uiux → only 1-design/
11
11
  * plan → only 2-plan/
12
12
  * implement → 3-implement/ + any source code (unrestricted)
13
13
  * review → only 4-review/
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Blocks Write/Edit to spec artifacts after their approval gate has passed:
9
9
  * - 2-plan/spec.md, contracts.cs, tasks.md, etc. → blocked if 'plan' gate approved
10
- * - 1-ui/design-system.md, etc. → blocked if 'uiux' gate approved
10
+ * - 1-design/design-system.md, etc. → blocked if 'uiux' gate approved
11
11
  *
12
12
  * Fail-open: exits 0 on any error.
13
13
  */
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * state-sync.js — PostToolUse hook
4
+ *
5
+ * Keeps .morph/state.json in sync with the agent's actions, without requiring
6
+ * the agent to think about state. Fail-open: any error returns {} silently.
7
+ *
8
+ * Triggers:
9
+ * - Write/Edit of .morph/features/{feature}/0-proposal/proposal.md → register feature
10
+ * - Write/Edit of .morph/features/{feature}/{phase}/{output} → mark output created
11
+ * - AskUserQuestion answered with option starting "aprovado" → advance gate
12
+ */
13
+
14
+ import { readFileSync, existsSync, renameSync, writeFileSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { loadState, stateExists } from '../../shared/state-reader.js';
17
+
18
+ const STATE_FILE = '.morph/state.json';
19
+
20
+ const PHASE_FOLDERS = {
21
+ '0-proposal': 'proposal',
22
+ '1-design': 'design',
23
+ '1-ui': 'uiux', // legacy alias — still recognized during folder transition
24
+ '2-plan': 'plan',
25
+ '3-implement': 'implement',
26
+ '4-review': 'review',
27
+ '5-implement': 'implement', // legacy alias
28
+ };
29
+
30
+ function exit(output = {}) {
31
+ process.stdout.write(JSON.stringify(output));
32
+ process.exit(0);
33
+ }
34
+
35
+ function readStdin() {
36
+ try {
37
+ return JSON.parse(readFileSync(0, 'utf8') || '{}');
38
+ } catch {
39
+ return {};
40
+ }
41
+ }
42
+
43
+ function projectDir() {
44
+ return process.env.CLAUDE_PROJECT_DIR || process.cwd();
45
+ }
46
+
47
+ function extractFeatureName(filePath) {
48
+ if (!filePath) return null;
49
+ const normalized = String(filePath).replace(/\\/g, '/');
50
+ const match = normalized.match(/\.morph\/features\/([^/]+)\//);
51
+ return match ? match[1] : null;
52
+ }
53
+
54
+ function extractPhaseFolder(filePath) {
55
+ if (!filePath) return null;
56
+ const normalized = String(filePath).replace(/\\/g, '/');
57
+ const match = normalized.match(/\.morph\/features\/[^/]+\/([^/]+)\//);
58
+ if (!match) return null;
59
+ return PHASE_FOLDERS[match[1]] ?? null;
60
+ }
61
+
62
+ function extractFilename(filePath) {
63
+ const normalized = String(filePath).replace(/\\/g, '/');
64
+ return normalized.split('/').pop();
65
+ }
66
+
67
+ /**
68
+ * Atomic write — temp file then rename. Mirrors state-manager.js semantics.
69
+ */
70
+ function writeStateAtomic(cwd, state) {
71
+ const path = join(cwd, STATE_FILE);
72
+ const tmpPath = `${path}.tmp.${process.pid}`;
73
+ writeFileSync(tmpPath, JSON.stringify(state, null, 2), 'utf8');
74
+ renameSync(tmpPath, path);
75
+ }
76
+
77
+ function registerFeatureIfMissing(state, featureName) {
78
+ if (!state.features) state.features = {};
79
+ if (state.features[featureName]) return false;
80
+
81
+ const now = new Date().toISOString();
82
+ state.features[featureName] = {
83
+ status: 'in_progress',
84
+ createdAt: now,
85
+ updatedAt: now,
86
+ approvalGates: { proposal: false, plan: false, review: false },
87
+ outputs: {},
88
+ };
89
+
90
+ if (!state.metadata) state.metadata = {};
91
+ state.metadata.totalFeatures = Object.keys(state.features).length;
92
+ return true;
93
+ }
94
+
95
+ function trackOutput(state, featureName, filePath) {
96
+ const filename = extractFilename(filePath);
97
+ const feature = state.features[featureName];
98
+ if (!feature) return false;
99
+ feature.outputs ??= {};
100
+ const normalizedPath = String(filePath).replace(/\\/g, '/');
101
+ const wasMissing = !feature.outputs[filename]?.created;
102
+ feature.outputs[filename] = {
103
+ created: true,
104
+ path: normalizedPath,
105
+ };
106
+ feature.updatedAt = new Date().toISOString();
107
+ return wasMissing;
108
+ }
109
+
110
+ function findActiveFeature(state) {
111
+ if (!state.features) return null;
112
+ const entries = Object.entries(state.features);
113
+ const active = entries.find(([, f]) => f.status === 'in_progress');
114
+ if (active) return active[0];
115
+ return entries[0]?.[0] ?? null;
116
+ }
117
+
118
+ function isApprovalAnswer(answer) {
119
+ if (typeof answer !== 'string') return false;
120
+ const lower = answer.toLowerCase();
121
+ return (
122
+ lower.startsWith('aprovado') ||
123
+ lower.includes('pode avan') ||
124
+ lower.includes('pode implementar') ||
125
+ lower.includes('pode prosseguir')
126
+ );
127
+ }
128
+
129
+ function gateFromQuestion(question) {
130
+ if (typeof question !== 'string') return null;
131
+ const lower = question.toLowerCase();
132
+ if (lower.includes('gate 1') || lower.includes('proposta')) return 'proposal';
133
+ if (lower.includes('gate 2') || lower.includes('plano') || lower.includes('plan')) return 'plan';
134
+ if (lower.includes('gate 3') || lower.includes('review')) return 'review';
135
+ return null;
136
+ }
137
+
138
+ function handleWriteEdit(input, cwd) {
139
+ const filePath = input.tool_input?.file_path;
140
+ const featureName = extractFeatureName(filePath);
141
+ if (!featureName) return false;
142
+
143
+ const state = loadState(cwd);
144
+ if (!state) return false;
145
+
146
+ let changed = registerFeatureIfMissing(state, featureName);
147
+ const phase = extractPhaseFolder(filePath);
148
+ if (phase) {
149
+ const outputChanged = trackOutput(state, featureName, filePath);
150
+ changed = changed || outputChanged;
151
+ }
152
+
153
+ if (changed) {
154
+ writeStateAtomic(cwd, state);
155
+ }
156
+ return true;
157
+ }
158
+
159
+ function handleAskUserQuestion(input, cwd) {
160
+ const answers = input.tool_response?.answers ?? input.tool_response?.responses ?? {};
161
+ if (typeof answers !== 'object' || answers === null) return false;
162
+
163
+ const state = loadState(cwd);
164
+ if (!state) return false;
165
+
166
+ const featureName = findActiveFeature(state);
167
+ if (!featureName) return false;
168
+
169
+ let changed = false;
170
+ for (const [question, answer] of Object.entries(answers)) {
171
+ if (!isApprovalAnswer(answer)) continue;
172
+ const gate = gateFromQuestion(question);
173
+ if (!gate) continue;
174
+
175
+ state.features[featureName].approvalGates ??= {};
176
+ if (state.features[featureName].approvalGates[gate] !== true) {
177
+ state.features[featureName].approvalGates[gate] = true;
178
+ state.features[featureName].updatedAt = new Date().toISOString();
179
+ changed = true;
180
+ }
181
+ }
182
+
183
+ if (changed) {
184
+ writeStateAtomic(cwd, state);
185
+ }
186
+ return true;
187
+ }
188
+
189
+ async function main() {
190
+ const cwd = projectDir();
191
+ if (!stateExists(cwd)) {
192
+ exit();
193
+ return;
194
+ }
195
+
196
+ const input = readStdin();
197
+ const toolName = input.tool_name;
198
+
199
+ try {
200
+ if (toolName === 'Write' || toolName === 'Edit') {
201
+ handleWriteEdit(input, cwd);
202
+ } else if (toolName === 'AskUserQuestion') {
203
+ handleAskUserQuestion(input, cwd);
204
+ }
205
+ } catch {
206
+ // fail-open
207
+ }
208
+
209
+ exit();
210
+ }
211
+
212
+ main().catch(() => exit());
@@ -8,15 +8,16 @@
8
8
  */
9
9
 
10
10
  /** Phase order */
11
- export const PHASE_ORDER = ["proposal","uiux","plan","implement","review"];
11
+ export const PHASE_ORDER = ["proposal","uiux","plan","implement","review","sync"];
12
12
 
13
13
  /** Map phase → allowed output subdirectory */
14
14
  export const PHASE_DIRS = {
15
15
  proposal: '0-proposal',
16
- uiux: '1-ui',
16
+ uiux: '1-design',
17
17
  plan: '2-plan',
18
18
  implement: '3-implement',
19
19
  review: '4-review',
20
+ sync: '3-implement',
20
21
  };
21
22
 
22
23
  /** Map output type (camelCase) → phase that produces it */
@@ -47,7 +48,7 @@ export const FILENAME_TO_OUTPUT = {
47
48
  'flows.md': 'uiFlows',
48
49
  'spec.md': 'spec',
49
50
  'mandate.md': 'mandate',
50
- 'tasks.md': 'tasks',
51
+ 'tasks.json': 'tasks',
51
52
  'decisions.md': 'decisions',
52
53
  'recap.md': 'recap',
53
54
  'review-report.md': 'reviewReport',
@@ -61,7 +62,7 @@ export const PROTECTED_SPEC_FILES = {
61
62
  'flows.md': 'uiux',
62
63
  'spec.md': 'plan',
63
64
  'mandate.md': 'plan',
64
- 'tasks.md': 'plan',
65
+ 'tasks.json': 'plan',
65
66
  };
66
67
 
67
68
  /**
@@ -110,7 +110,7 @@ export function derivePhaseForFeature(featureName, projectPath) {
110
110
  ['4-review', 'review'],
111
111
  ['3-implement', 'implement'],
112
112
  ['2-plan', 'plan'],
113
- ['1-ui', 'uiux'],
113
+ ['1-design', 'uiux'],
114
114
  ['0-proposal', 'proposal'],
115
115
  ];
116
116
  for (const [folder, phase] of phaseMap) {
@@ -21,7 +21,7 @@
21
21
  "uiux": {
22
22
  "id": "uiux",
23
23
  "index": 1,
24
- "folder": "1-ui",
24
+ "folder": "1-design",
25
25
  "displayName": "UI/UX Design",
26
26
  "optional": true,
27
27
  "goals": [