@polymorphism-tech/morph-spec 8.3.0 → 8.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -8
- package/bin/morph-spec.js +37 -11
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +12 -7
- package/docs/QUICKSTART.md +19 -10
- package/framework/CLAUDE.md +9 -6
- package/framework/MORPH.md +5 -3
- package/framework/commands/morph-archive.md +11 -4
- package/framework/commands/morph-hotfix.md +1 -1
- package/framework/hooks/claude-code/core/state-sync.js +41 -9
- package/framework/hooks/shared/state-writer.js +14 -3
- package/framework/schemas/feature.schema.json +17 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +8 -5
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +5 -5
- package/framework/skills/core/morph-implement/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +1 -1
- package/framework/skills/core/morph-proposal/SKILL.md +4 -4
- package/framework/skills/core/morph-review/SKILL.md +4 -2
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/commands/project/doctor.js +28 -0
- package/src/commands/project/worktree.js +154 -357
- package/src/commands/state/advance.js +17 -0
- package/src/commands/state/approve.js +13 -0
- package/src/commands/state/archive.js +148 -70
- package/src/commands/state/create.js +67 -3
- package/src/commands/state/delete.js +143 -0
- package/src/commands/state/finish.js +422 -0
- package/src/commands/state/list.js +110 -0
- package/src/core/state/feature-identity.js +36 -0
- package/src/core/state/gate-order.js +51 -0
- package/src/core/state/lifecycle-audit.js +79 -0
- package/src/core/state/state-manager.js +49 -14
- package/src/dashboard/scanner/state-scanner.js +1 -1
- package/src/lib/generators/handoff-generator.js +2 -2
- package/src/lib/git/default-branch.js +73 -0
- package/src/lib/worktree/env-allocator.js +1 -1
- package/src/utils/file-copier.js +2 -2
|
@@ -4,7 +4,7 @@ description: Guia a criação de uma landing page nova ponta-a-ponta a partir do
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar um novo projeto de LP com o template Umbraco genérico
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# create-umbraco-lp
|
|
@@ -4,7 +4,7 @@ description: Migra uma landing page existente (React/Vite, Next.js estático ou
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /migrate-lp-to-umbraco {projeto}" do usuário, ou quando o usuário descrever necessidade de migrar uma LP para Umbraco
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# migrate-lp-to-umbraco
|
|
@@ -4,7 +4,7 @@ description: Orquestra a execução autônoma de tasks de uma feature morph-spec
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: após Gate 2 aprovado, ao receber instrução "use /morph-apply" ou "implementar feature"
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-apply
|
|
@@ -218,11 +218,14 @@ O comando grava `gateDecisions.review = { pause, reason, signals, trust, decided
|
|
|
218
218
|
- Pause: `AskUserQuestion` com options `["aprovado, fechar feature", "preciso ajustar", "rollback"]`.
|
|
219
219
|
- Auto: exibir summary do review-report, aprovar via `morph-spec approve {feature} review --mode auto`, e prosseguir.
|
|
220
220
|
|
|
221
|
-
### 6. Pós Gate 3
|
|
221
|
+
### 6. Pós Gate 3 — encerramento
|
|
222
222
|
|
|
223
223
|
- Aprovar o Gate 3: em auto, `morph-spec approve {feature} review --mode auto`; em manual, o hook state-sync registra a resposta "aprovado" em AskUserQuestion. O gate fica gravado no `feature.json` autoritativo da feature — nunca via Edit à mão de `state.json`.
|
|
224
|
-
-
|
|
225
|
-
-
|
|
224
|
+
- **Fechar a feature** com `morph-spec finish {feature} --pr|--merge` — um passo só: arquiva commitando `features/{f} → archive/{f}` dentro de `morph/{f}`, integra e desmonta o worktree (se houver). Escolha o modo com `AskUserQuestion` (header `"Integração"`):
|
|
225
|
+
- **Abrir PR** (`--pr`): faz `push` de `morph/{f}` + `gh pr create` com base na default — para review por outro humano/CI antes do merge. Exige `origin` + `gh` autenticado (checados **antes** de arquivar; se faltarem, `finish` recusa sem efeito colateral — caia para `--merge`). A branch é preservada e a sessão fica em `morph/{f}`.
|
|
226
|
+
- **Merge local** (`--merge`): merge `--no-ff` na default **localmente**, sem push — para o fluxo single-user direto. Remove a branch e o worktree.
|
|
227
|
+
- Não integre automaticamente sem a escolha do modo: `finish` toca o remoto (`--pr`) ou a branch default (`--merge`) — é uma ação de saída que pede confirmação.
|
|
228
|
+
- Feature **legada** (criada antes do modelo "nasce numa branch", sem `morph/{f}`): `finish` recusa e roteia para `morph-spec archive {feature}` (arquivar-sem-integrar); nesse caso, arquive.
|
|
226
229
|
|
|
227
230
|
## Anti-padrões
|
|
228
231
|
|
|
@@ -240,7 +243,7 @@ O comando grava `gateDecisions.review = { pause, reason, signals, trust, decided
|
|
|
240
243
|
- `.morph/features/{feature}/3-implement/recap.md` produzido por morph-implement.
|
|
241
244
|
- `.morph/features/{feature}/4-review/review-report.md` produzido por morph-review.
|
|
242
245
|
- Gate 3 registrado aprovado em `.morph/features/{feature}/feature.json` (autoritativo) — via `morph-spec approve` em auto, ou pelo hook state-sync no caminho manual.
|
|
243
|
-
- Feature com Gate 3 aprovado e
|
|
246
|
+
- Feature com Gate 3 aprovado e **fechada** por `morph-spec finish --pr|--merge` (arquiva carimbando `status: "completed"` + `archivedAt`, integra e desmonta num passo) — ou, se legada, por `morph-spec archive`.
|
|
244
247
|
|
|
245
248
|
## Referências
|
|
246
249
|
|
|
@@ -4,7 +4,7 @@ description: Entende o negócio, os usuários e a arquitetura antes de qualquer
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber um novo request de feature, antes de morph-plan
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-brainstorming
|
|
@@ -4,7 +4,7 @@ description: Avalia a qualidade de uma tarefa ou fase com rubricas graduadas 0-1
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao completar uma tarefa ou ao finalizar uma fase de implementação
|
|
6
6
|
user-invokable: false
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-eval
|
|
@@ -4,7 +4,7 @@ description: ADW cirúrgico de hotfix — resolve uma queda/bug crítico de prod
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber "/morph-hotfix {feature}", quando a morph-proposal classifica o pedido como workType hotfix (Passo 0), ou o usuário diz "produção caiu / hotfix / urgente"
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-hotfix
|
|
@@ -28,10 +28,10 @@ Resolver uma queda ou bug crítico de produção o mais rápido possível — pr
|
|
|
28
28
|
### 1. Nascimento da feature
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
morph-spec create {feature} --type hotfix
|
|
31
|
+
morph-spec create {feature} --type hotfix --description "<o incidente: o que quebrou / sintoma>"
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Carimba
|
|
34
|
+
Carimba `name` (o slug) + `description` (obrigatória no nascimento — descreva o incidente) e os gates `proposal`/`plan` como `approvedBy: "policy:hotfix"`, e cria as pastas `0-proposal/`, `2-plan/`, `3-implement/` num passo só — a feature já nasce em `implement` (fase derivada é gate-aware). Se a feature já existe, siga adiante sem recriar.
|
|
35
35
|
|
|
36
36
|
### 2. Scout — mapa do território (obrigatório)
|
|
37
37
|
|
|
@@ -103,8 +103,8 @@ options:
|
|
|
103
103
|
### 8. Pós-gate (o "test loop → ship" de `MORPH.md` §2.1)
|
|
104
104
|
|
|
105
105
|
- Rode a suíte completa uma vez: `morph-spec verify {feature}` (sem escopo de task — cobertura da feature inteira, agora que o Gate 3 está aprovado).
|
|
106
|
-
-
|
|
107
|
-
- Não
|
|
106
|
+
- Feche com `morph-spec finish {feature} --pr|--merge` — o mesmo encerramento único das demais features (arquiva commitando dentro de `morph/{f}`, integra, desmonta). Num hotfix urgente o `--merge` (local, direto na default) costuma ser o caminho; use `--pr` quando o fix precisa passar por CI/review antes do merge. Ver `MORPH.md` §2.2.
|
|
107
|
+
- Não integre automaticamente — o usuário decide quando e por qual modo (`finish` toca a default ou o remoto). Feature legada sem `morph/{f}`: `finish` roteia para `morph-spec archive {feature}`.
|
|
108
108
|
|
|
109
109
|
## Anti-padrões
|
|
110
110
|
|
|
@@ -4,7 +4,7 @@ description: Guia a produção dos três artefatos de planejamento de uma featur
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase plan de uma feature, após o Gate 1 (proposal aprovado)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -4,7 +4,7 @@ description: Orquestra a fase de proposta+plano de uma feature morph-spec. Encad
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /morph-proposal" do usuário, ou ao iniciar uma nova feature
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-proposal
|
|
@@ -38,10 +38,10 @@ Antes de qualquer trabalho de negócio, classifique o pedido. Se `{feature-name}
|
|
|
38
38
|
morph-spec create {feature-name} --request "<pedido do usuário>"
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
(ou `--type <tipo
|
|
41
|
+
(ou `--type <tipo> --description "<o quê/porquê>"` diretamente quando o tipo é óbvio pelo pedido — ex.: o usuário já diz "isso é um hotfix"). O `--request` **serve de semente da descrição**: toda feature nasce com `name` (o slug) e `description` (obrigatória) carimbados. Sem `--request` nem `--description`, o `create` recusa — nada de scaffolds anônimos.
|
|
42
42
|
|
|
43
43
|
- **Classificação `high` confidence** — a feature nasce com o `workType` decidido pelo detector determinístico (keywords: `hotfix` — "produção caiu/urgente/incident/p0"; `bug` — "bug/corrigir/exception/regressão"; `chore` — "typo/rename/bump/config/docs/cleanup"). Prossiga para o branch correspondente abaixo.
|
|
44
|
-
- **Exit 2** (empate `tie` ou nenhum sinal `none`) — o comando sai sem criar a feature e imprime `{ needsDecision, candidates, matched }`. **Você é o roteador**: decida o tipo entre os candidatos e re-rode com `morph-spec create {feature-name} --type <tipo
|
|
44
|
+
- **Exit 2** (empate `tie` ou nenhum sinal `none`) — o comando sai sem criar a feature e imprime `{ needsDecision, candidates, matched }`. **Você é o roteador**: decida o tipo entre os candidatos e re-rode com `morph-spec create {feature-name} --type <tipo> --request "<pedido do usuário>"` (o `--request` re-passado carimba a descrição). Só use `AskUserQuestion` para o usuário quando o pedido for genuinamente indeterminado — a maioria dos empates o roteador resolve sozinho pelo contexto da conversa.
|
|
45
45
|
|
|
46
46
|
**Branches por tipo** (dimensionamento completo em `MORPH.md` §2.1):
|
|
47
47
|
|
|
@@ -55,7 +55,7 @@ morph-spec create {feature-name} --request "<pedido do usuário>"
|
|
|
55
55
|
- Se argumento ausente: perguntar via `AskUserQuestion` (1 pergunta, header "Feature").
|
|
56
56
|
- Verificar `.morph/features/{feature-name}/`:
|
|
57
57
|
- Se `0-proposal/proposal.md` existe e tem conteúdo: pular para passo 3.
|
|
58
|
-
- Caso contrário: rode `morph-spec create {feature-name}` — cria `.morph/features/{feature-name}/0-proposal/` e o `feature.json` canônico (shape em `.morph/framework/schemas/feature.schema.json`) num passo só, server-side. Não crie a estrutura à mão nem dependa do nascimento implícito via hook no primeiro Write. Depois siga o passo 2.
|
|
58
|
+
- Caso contrário: rode `morph-spec create {feature-name} --description "<resumo do pedido do usuário>"` — cria `.morph/features/{feature-name}/0-proposal/` e o `feature.json` canônico (shape em `.morph/framework/schemas/feature.schema.json`) num passo só, server-side, com `name`+`description` carimbados. A `--description` é **obrigatória** no nascimento (ou `--request`, que a semeia). Não crie a estrutura à mão nem dependa do nascimento implícito via hook no primeiro Write. Depois siga o passo 2.
|
|
59
59
|
|
|
60
60
|
### 2. Invocar `Skill(morph-brainstorming)`
|
|
61
61
|
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase de revisão e produz o review-report.md para o Gate 3
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase review, após todas as tasks de tasks.json estarem com status `done`
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-review
|
|
@@ -102,7 +102,7 @@ e o `recap.md` estar atualizado. Normalmente invocada pela skill orquestradora `
|
|
|
102
102
|
question: "Gate 3 — Review de {feature} aprovado?{ reason ? ' Sinal: ' + reason : '' }"
|
|
103
103
|
header: "Gate 3"
|
|
104
104
|
options:
|
|
105
|
-
- { label: "aprovado, fechar feature", description: "Marcar
|
|
105
|
+
- { label: "aprovado, fechar feature", description: "Marcar review aprovado; próximo passo é fechar com morph-spec finish --pr|--merge (ver morph-apply §6)" }
|
|
106
106
|
- { label: "preciso ajustar", description: "Apontar correções necessárias antes de fechar" }
|
|
107
107
|
- { label: "rollback", description: "Desfazer e voltar para implement" }
|
|
108
108
|
```
|
|
@@ -120,6 +120,8 @@ e o `recap.md` estar atualizado. Normalmente invocada pela skill orquestradora `
|
|
|
120
120
|
|
|
121
121
|
No caminho manual, o hook state-sync detecta a aprovação em answers de AskUserQuestion e grava `approvalGates.review = { approved: true, timestamp, approvedBy: "manual" }` no `feature.json` autoritativo da feature. Em auto sem AskUserQuestion, aprove via `morph-spec approve {feature} review --mode auto` — nunca via Edit à mão de state.json.
|
|
122
122
|
|
|
123
|
+
**Próximo passo (não é desta skill):** com o Gate 3 aprovado, a feature fecha por `morph-spec finish {feature} --pr|--merge` — a `morph-apply` §6 conduz a escolha PR vs merge. Não arquive nem integre aqui.
|
|
124
|
+
|
|
123
125
|
## Output esperado
|
|
124
126
|
- `.morph/features/{feature}/4-review/evaluator-report.md` — relatório bruto e autoritativo do
|
|
125
127
|
`morph-evaluator` despachado no passo 4 (canal durável, ver MORPH.md §6)
|
|
@@ -4,7 +4,7 @@ description: Varre o codebase existente, detecta stack atual, compara com o stac
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar uma feature em projeto brownfield (codebase já existente)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-stack-scan
|
|
@@ -4,7 +4,7 @@ description: Localiza e carrega um standard específico do STANDARDS.json sob de
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: quando precisar consultar um standard específico durante a implementação
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.5.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-standards
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { resetMorphSettings } from '../../utils/claude-settings-manager.js';
|
|
15
15
|
import { checkMissingAgents, checkAgentsDrift } from '../../utils/agents-installer.js';
|
|
16
16
|
import { getProjectTags } from '../../lib/stack-filter.js';
|
|
17
|
+
import { auditFeatureLifecycle } from '../../core/state/lifecycle-audit.js';
|
|
17
18
|
|
|
18
19
|
const isWindows = platform() === 'win32';
|
|
19
20
|
/**
|
|
@@ -896,6 +897,22 @@ export async function doctorCommand(options = {}) {
|
|
|
896
897
|
hasWarnings = true;
|
|
897
898
|
}
|
|
898
899
|
|
|
900
|
+
// Feature-lifecycle consistency — the consolidated inconsistency report:
|
|
901
|
+
// gate-order violations (N approved with N-1 pending), identity-less
|
|
902
|
+
// features (no description), orphan folders and stale index entries. Warn
|
|
903
|
+
// only (advisory); the per-feature detail is printed after the summary.
|
|
904
|
+
const lifecycleIssues = auditFeatureLifecycle(targetPath);
|
|
905
|
+
if (lifecycleIssues.length === 0) {
|
|
906
|
+
checks.push({ name: 'feature lifecycle', status: 'ok' });
|
|
907
|
+
} else {
|
|
908
|
+
checks.push({
|
|
909
|
+
name: 'feature lifecycle',
|
|
910
|
+
status: 'warn',
|
|
911
|
+
msg: `${lifecycleIssues.length} inconsistenc${lifecycleIssues.length === 1 ? 'y' : 'ies'} (see below)`,
|
|
912
|
+
});
|
|
913
|
+
hasWarnings = true;
|
|
914
|
+
}
|
|
915
|
+
|
|
899
916
|
// Check key templates exist (in framework package, not project copy)
|
|
900
917
|
const frameworkTemplatesRoot = join(import.meta.dirname, '..', '..', '..', 'framework', 'templates');
|
|
901
918
|
const keyTemplates = [
|
|
@@ -944,6 +961,17 @@ export async function doctorCommand(options = {}) {
|
|
|
944
961
|
}
|
|
945
962
|
}
|
|
946
963
|
|
|
964
|
+
// Per-feature detail for the lifecycle inconsistencies (item: doctor lists
|
|
965
|
+
// what's already wrong in the repo, e.g. plan approved with proposal pending).
|
|
966
|
+
if (lifecycleIssues.length) {
|
|
967
|
+
logger.blank();
|
|
968
|
+
console.log(chalk.yellow(' Feature lifecycle inconsistencies:'));
|
|
969
|
+
for (const issue of lifecycleIssues) {
|
|
970
|
+
console.log(chalk.gray(` • ${issue.feature} [${issue.type}] — ${issue.detail}`));
|
|
971
|
+
}
|
|
972
|
+
console.log(chalk.gray(" Fix: 'morph-spec approve' (order), '--description' on create, or 'morph-spec delete' for dead scaffolds."));
|
|
973
|
+
}
|
|
974
|
+
|
|
947
975
|
logger.blank();
|
|
948
976
|
|
|
949
977
|
if (hasErrors) {
|