@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.
Files changed (43) hide show
  1. package/README.md +11 -8
  2. package/bin/morph-spec.js +37 -11
  3. package/claude-plugin.json +1 -1
  4. package/docs/CHEATSHEET.md +12 -7
  5. package/docs/QUICKSTART.md +19 -10
  6. package/framework/CLAUDE.md +9 -6
  7. package/framework/MORPH.md +5 -3
  8. package/framework/commands/morph-archive.md +11 -4
  9. package/framework/commands/morph-hotfix.md +1 -1
  10. package/framework/hooks/claude-code/core/state-sync.js +41 -9
  11. package/framework/hooks/shared/state-writer.js +14 -3
  12. package/framework/schemas/feature.schema.json +17 -4
  13. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  14. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  15. package/framework/skills/core/morph-apply/SKILL.md +8 -5
  16. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  17. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  18. package/framework/skills/core/morph-hotfix/SKILL.md +5 -5
  19. package/framework/skills/core/morph-implement/SKILL.md +1 -1
  20. package/framework/skills/core/morph-plan/SKILL.md +1 -1
  21. package/framework/skills/core/morph-proposal/SKILL.md +4 -4
  22. package/framework/skills/core/morph-review/SKILL.md +4 -2
  23. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  24. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  25. package/package.json +1 -1
  26. package/src/commands/project/doctor.js +28 -0
  27. package/src/commands/project/worktree.js +154 -357
  28. package/src/commands/state/advance.js +17 -0
  29. package/src/commands/state/approve.js +13 -0
  30. package/src/commands/state/archive.js +148 -70
  31. package/src/commands/state/create.js +67 -3
  32. package/src/commands/state/delete.js +143 -0
  33. package/src/commands/state/finish.js +422 -0
  34. package/src/commands/state/list.js +110 -0
  35. package/src/core/state/feature-identity.js +36 -0
  36. package/src/core/state/gate-order.js +51 -0
  37. package/src/core/state/lifecycle-audit.js +79 -0
  38. package/src/core/state/state-manager.js +49 -14
  39. package/src/dashboard/scanner/state-scanner.js +1 -1
  40. package/src/lib/generators/handoff-generator.js +2 -2
  41. package/src/lib/git/default-branch.js +73 -0
  42. package/src/lib/worktree/env-allocator.js +1 -1
  43. 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.3.0"
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.3.0"
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.3.0"
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
- - Sinalizar: "Feature {nome} concluída. Rode `/morph-archive {feature}` para arquivar."
225
- - Não arquivar automaticamente.
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 pronta para `morph-spec archive` (que carimba `status: "completed"` + `archivedAt`).
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.3.0"
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.3.0"
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.3.0"
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 os gates `proposal` e `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.
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
- - Sinalize ao usuário: commit do fix e `morph-spec archive {feature}` (ou `morph-spec worktree finish {feature}` se a feature nasceu em worktree — ver `MORPH.md` §2.2) estão prontos.
107
- - Não arquive automaticamente — usuário decide quando.
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 execução de cada tarefa de implementação com standard e
4
4
  version: core
5
5
  when-to-invoke: ao iniciar cada task de implementação listada em tasks.json
6
6
  user-invokable: false
7
- cliVersion: "8.3.0"
7
+ cliVersion: "8.5.0"
8
8
  ---
9
9
 
10
10
  # morph-implement
@@ -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.3.0"
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.3.0"
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>` diretamente quando o tipo é óbvio pelo pedido — ex.: o usuário já diz "isso é um hotfix").
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>`. 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.
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.3.0"
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 feature como completed, habilitar /morph-archive" }
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.3.0"
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.3.0"
7
+ cliVersion: "8.5.0"
8
8
  ---
9
9
 
10
10
  # morph-standards
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "8.3.0",
3
+ "version": "8.5.0",
4
4
  "description": "MORPH-SPEC: NLH (Natural Language Harness) for spec-driven development with Claude Code",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -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) {