@polymorphism-tech/morph-spec 9.1.0 → 9.3.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/CLAUDE.md +14 -78
- package/README.md +2 -2
- package/bin/morph-spec.js +14 -1
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +4 -3
- package/framework/MORPH.md +7 -10
- package/framework/agents.json +15 -12
- package/framework/commands/morph-status.md +2 -2
- package/framework/docs/CLI.md +24 -16
- package/framework/evals/review-checklist.md +15 -2
- package/framework/hooks/README.md +8 -44
- package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
- package/framework/hooks/claude-code/core/state-sync.js +1 -1
- package/framework/hooks/claude-code/core/worktree-context.js +23 -0
- package/framework/hooks/claude-code/statusline.py +3 -2
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/shared/gate-event.js +18 -0
- package/framework/hooks/shared/next-step.js +107 -0
- package/framework/hooks/shared/slice-progress.js +18 -5
- package/framework/hooks/shared/state-writer.js +6 -1
- package/framework/mcp/registry.json +31 -1
- package/framework/rules/nextjs-standards.md +1 -1
- package/framework/schemas/feature.schema.json +1 -0
- 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 +6 -4
- package/framework/skills/core/morph-hotfix/SKILL.md +3 -3
- package/framework/skills/core/morph-machine/SKILL.md +1 -1
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +8 -6
- package/framework/skills/core/morph-review/SKILL.md +9 -6
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +2 -1
- package/framework/standards/STANDARDS.json +2 -2
- package/framework/standards/STANDARDS.meta.json +1 -1
- package/framework/standards/ai-agents/setup.md +2 -0
- package/framework/standards/backend/dotnet/testing.md +10 -4
- package/framework/standards/frontend/nextjs/testing.md +10 -6
- package/framework/standards/integration/mcp/mcp-tools.md +3 -1
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/docs/plan.md +3 -1
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +1 -1
- package/src/commands/observability/cost.js +12 -0
- package/src/commands/project/status.js +6 -68
- package/src/commands/state/advance.js +1 -1
- package/src/commands/state/approve.js +2 -2
- package/src/commands/state/gate-check.js +2 -2
- package/src/commands/state/gate-decision.js +4 -1
- package/src/commands/state/next.js +24 -0
- package/src/commands/state/report-check.js +3 -1
- package/src/commands/validation/mutate.js +9 -6
- package/src/commands/validation/plan-check.js +4 -2
- package/src/commands/validation/tests-audit.js +7 -0
- package/src/commands/validation/validate-feature.js +4 -2
- package/src/commands/validation/verify.js +21 -16
- package/src/core/state/state-manager.js +4 -0
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/FeatureDetail.jsx +6 -2
- package/src/dashboard/scanner/features-scanner.js +5 -2
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/ci/workflow-scaffold.js +12 -0
- package/src/lib/e2e/applicability.js +37 -0
- package/src/lib/generators/handoff-generator.js +11 -25
- package/src/lib/mutation/adapters.js +6 -17
- package/src/lib/mutation/runner.js +23 -75
- package/src/lib/mutation/trx.js +0 -1
- package/src/lib/next-step.js +10 -0
- package/src/lib/plan/checks.js +29 -2
- package/src/lib/plan/plan-parser.js +6 -2
- package/src/lib/review-reports.js +6 -3
- package/src/lib/risk-detector.js +20 -7
- package/src/lib/stack/stack-scan.js +13 -1
- package/src/lib/telemetry/metrics.js +46 -0
- package/src/lib/tests-audit/audit.js +96 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
- package/src/lib/validators/validation-runner.js +6 -38
- package/src/lib/validators/verify-runner.js +37 -22
- package/src/utils/agents-installer.js +24 -1
- package/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
- package/framework/hooks/git/pre-commit/agents.sh +0 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
- package/framework/hooks/git/pre-push/run-tests.sh +0 -44
|
@@ -1,226 +1,226 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Design System - {Project Name}
|
|
3
|
-
*
|
|
4
|
-
* CSS Variables generated from design-system.md
|
|
5
|
-
* Use estas variáveis em todo o projeto para manter consistência visual.
|
|
6
|
-
*
|
|
7
|
-
* Template MORPH-SPEC by Polymorphism Tech
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
:root {
|
|
11
|
-
/* ========================================
|
|
12
|
-
* CORES PRINCIPAIS
|
|
13
|
-
* ======================================== */
|
|
14
|
-
|
|
15
|
-
--color-primary: #{hex da cor primária};
|
|
16
|
-
--color-primary-hover: #{hex da cor primária mais escura};
|
|
17
|
-
--color-primary-active: #{hex da cor primária ainda mais escura};
|
|
18
|
-
|
|
19
|
-
--color-secondary: #{hex da cor secundária};
|
|
20
|
-
--color-secondary-hover: #{hex};
|
|
21
|
-
--color-secondary-active: #{hex};
|
|
22
|
-
|
|
23
|
-
/* ========================================
|
|
24
|
-
* CORES DE ESTADO
|
|
25
|
-
* ======================================== */
|
|
26
|
-
|
|
27
|
-
--color-success: #{hex};
|
|
28
|
-
--color-success-bg: #{hex com transparência ou shade mais claro};
|
|
29
|
-
--color-success-border: #{hex};
|
|
30
|
-
|
|
31
|
-
--color-error: #{hex};
|
|
32
|
-
--color-error-bg: #{hex};
|
|
33
|
-
--color-error-border: #{hex};
|
|
34
|
-
|
|
35
|
-
--color-warning: #{hex};
|
|
36
|
-
--color-warning-bg: #{hex};
|
|
37
|
-
--color-warning-border: #{hex};
|
|
38
|
-
|
|
39
|
-
--color-info: #{hex};
|
|
40
|
-
--color-info-bg: #{hex};
|
|
41
|
-
--color-info-border: #{hex};
|
|
42
|
-
|
|
43
|
-
/* ========================================
|
|
44
|
-
* ESCALA DE NEUTROS (Cinzas)
|
|
45
|
-
* ======================================== */
|
|
46
|
-
|
|
47
|
-
--color-gray-50: #{hex};
|
|
48
|
-
--color-gray-100: #{hex};
|
|
49
|
-
--color-gray-200: #{hex};
|
|
50
|
-
--color-gray-300: #{hex};
|
|
51
|
-
--color-gray-400: #{hex};
|
|
52
|
-
--color-gray-500: #{hex};
|
|
53
|
-
--color-gray-600: #{hex};
|
|
54
|
-
--color-gray-700: #{hex};
|
|
55
|
-
--color-gray-800: #{hex};
|
|
56
|
-
--color-gray-900: #{hex};
|
|
57
|
-
|
|
58
|
-
/* ========================================
|
|
59
|
-
* TIPOGRAFIA - FONTES
|
|
60
|
-
* ======================================== */
|
|
61
|
-
|
|
62
|
-
--font-sans: '{Font Name}', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
63
|
-
--font-serif: '{Font Name}', Georgia, 'Times New Roman', serif;
|
|
64
|
-
--font-mono: '{Font Name}', 'Fira Code', 'Courier New', Consolas, monospace;
|
|
65
|
-
|
|
66
|
-
/* ========================================
|
|
67
|
-
* TIPOGRAFIA - TAMANHOS
|
|
68
|
-
* ======================================== */
|
|
69
|
-
|
|
70
|
-
--text-xs: 0.75rem; /* 12px */
|
|
71
|
-
--text-sm: 0.875rem; /* 14px */
|
|
72
|
-
--text-base: 1rem; /* 16px */
|
|
73
|
-
--text-lg: 1.125rem; /* 18px */
|
|
74
|
-
--text-xl: 1.25rem; /* 20px */
|
|
75
|
-
--text-2xl: 1.5rem; /* 24px */
|
|
76
|
-
--text-3xl: 1.875rem; /* 30px */
|
|
77
|
-
--text-4xl: 2.25rem; /* 36px */
|
|
78
|
-
--text-5xl: 3rem; /* 48px */
|
|
79
|
-
|
|
80
|
-
/* ========================================
|
|
81
|
-
* TIPOGRAFIA - LINE HEIGHTS
|
|
82
|
-
* ======================================== */
|
|
83
|
-
|
|
84
|
-
--leading-none: 1;
|
|
85
|
-
--leading-tight: 1.25;
|
|
86
|
-
--leading-snug: 1.375;
|
|
87
|
-
--leading-normal: 1.5;
|
|
88
|
-
--leading-relaxed: 1.625;
|
|
89
|
-
--leading-loose: 2;
|
|
90
|
-
|
|
91
|
-
/* ========================================
|
|
92
|
-
* TIPOGRAFIA - FONT WEIGHTS
|
|
93
|
-
* ======================================== */
|
|
94
|
-
|
|
95
|
-
--font-light: 300;
|
|
96
|
-
--font-regular: 400;
|
|
97
|
-
--font-medium: 500;
|
|
98
|
-
--font-semibold: 600;
|
|
99
|
-
--font-bold: 700;
|
|
100
|
-
--font-extrabold: 800;
|
|
101
|
-
|
|
102
|
-
/* ========================================
|
|
103
|
-
* ESPAÇAMENTO
|
|
104
|
-
* Baseado em múltiplos de {base}px (ex: 4px)
|
|
105
|
-
* ======================================== */
|
|
106
|
-
|
|
107
|
-
--space-0: 0;
|
|
108
|
-
--space-1: 0.25rem; /* 4px */
|
|
109
|
-
--space-2: 0.5rem; /* 8px */
|
|
110
|
-
--space-3: 0.75rem; /* 12px */
|
|
111
|
-
--space-4: 1rem; /* 16px */
|
|
112
|
-
--space-5: 1.25rem; /* 20px */
|
|
113
|
-
--space-6: 1.5rem; /* 24px */
|
|
114
|
-
--space-7: 1.75rem; /* 28px */
|
|
115
|
-
--space-8: 2rem; /* 32px */
|
|
116
|
-
--space-10: 2.5rem; /* 40px */
|
|
117
|
-
--space-12: 3rem; /* 48px */
|
|
118
|
-
--space-16: 4rem; /* 64px */
|
|
119
|
-
--space-20: 5rem; /* 80px */
|
|
120
|
-
--space-24: 6rem; /* 96px */
|
|
121
|
-
|
|
122
|
-
/* ========================================
|
|
123
|
-
* BORDER RADIUS
|
|
124
|
-
* ======================================== */
|
|
125
|
-
|
|
126
|
-
--rounded-none: 0;
|
|
127
|
-
--rounded-sm: 0.125rem; /* 2px */
|
|
128
|
-
--rounded-md: 0.375rem; /* 6px */
|
|
129
|
-
--rounded-lg: 0.5rem; /* 8px */
|
|
130
|
-
--rounded-xl: 0.75rem; /* 12px */
|
|
131
|
-
--rounded-2xl: 1rem; /* 16px */
|
|
132
|
-
--rounded-full: 9999px;
|
|
133
|
-
|
|
134
|
-
/* ========================================
|
|
135
|
-
* SOMBRAS (Shadows)
|
|
136
|
-
* ======================================== */
|
|
137
|
-
|
|
138
|
-
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
139
|
-
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
140
|
-
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
141
|
-
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
142
|
-
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
143
|
-
|
|
144
|
-
/* ========================================
|
|
145
|
-
* Z-INDEX LAYERS
|
|
146
|
-
* ======================================== */
|
|
147
|
-
|
|
148
|
-
--z-0: 0;
|
|
149
|
-
--z-10: 10;
|
|
150
|
-
--z-20: 20;
|
|
151
|
-
--z-30: 30;
|
|
152
|
-
--z-40: 40;
|
|
153
|
-
--z-50: 50; /* Modals, dropdowns */
|
|
154
|
-
--z-100: 100; /* Tooltips */
|
|
155
|
-
--z-max: 9999; /* Toasts, notifications */
|
|
156
|
-
|
|
157
|
-
/* ========================================
|
|
158
|
-
* TRANSITIONS / ANIMATIONS
|
|
159
|
-
* ======================================== */
|
|
160
|
-
|
|
161
|
-
--transition-fast: 150ms ease-in-out;
|
|
162
|
-
--transition-base: 250ms ease-in-out;
|
|
163
|
-
--transition-slow: 350ms ease-in-out;
|
|
164
|
-
|
|
165
|
-
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
166
|
-
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
167
|
-
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
168
|
-
|
|
169
|
-
/* ========================================
|
|
170
|
-
* BREAKPOINTS (informativo - usar em media queries)
|
|
171
|
-
* ======================================== */
|
|
172
|
-
|
|
173
|
-
/* @media (min-width: 640px) - sm */
|
|
174
|
-
/* @media (min-width: 768px) - md */
|
|
175
|
-
/* @media (min-width: 1024px) - lg */
|
|
176
|
-
/* @media (min-width: 1280px) - xl */
|
|
177
|
-
/* @media (min-width: 1536px) - 2xl */
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/* ========================================
|
|
181
|
-
* MODO ESCURO (Dark Mode)
|
|
182
|
-
* Opcional - ajuste as cores para dark theme
|
|
183
|
-
* ======================================== */
|
|
184
|
-
|
|
185
|
-
@media (prefers-color-scheme: dark) {
|
|
186
|
-
:root {
|
|
187
|
-
/* Inverter cores conforme necessário */
|
|
188
|
-
--color-gray-50: #{hex do gray-900};
|
|
189
|
-
--color-gray-900: #{hex do gray-50};
|
|
190
|
-
/* ... outras inversões */
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/* ========================================
|
|
195
|
-
* CLASSES UTILITÁRIAS (Exemplo)
|
|
196
|
-
* ======================================== */
|
|
197
|
-
|
|
198
|
-
/* Exemplo de uso das variáveis */
|
|
199
|
-
.btn-primary {
|
|
200
|
-
background-color: var(--color-primary);
|
|
201
|
-
color: white;
|
|
202
|
-
padding: var(--space-2) var(--space-4);
|
|
203
|
-
border-radius: var(--rounded-md);
|
|
204
|
-
font-weight: var(--font-semibold);
|
|
205
|
-
transition: background-color var(--transition-base);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.btn-primary:hover {
|
|
209
|
-
background-color: var(--color-primary-hover);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.card {
|
|
213
|
-
background-color: white;
|
|
214
|
-
padding: var(--space-6);
|
|
215
|
-
border-radius: var(--rounded-lg);
|
|
216
|
-
box-shadow: var(--shadow-md);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.text-muted {
|
|
220
|
-
color: var(--color-gray-600);
|
|
221
|
-
font-size: var(--text-sm);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/* ========================================
|
|
225
|
-
* FIM DO DESIGN SYSTEM
|
|
226
|
-
* ======================================== */
|
|
1
|
+
/**
|
|
2
|
+
* Design System - {Project Name}
|
|
3
|
+
*
|
|
4
|
+
* CSS Variables generated from design-system.md
|
|
5
|
+
* Use estas variáveis em todo o projeto para manter consistência visual.
|
|
6
|
+
*
|
|
7
|
+
* Template MORPH-SPEC by Polymorphism Tech
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
/* ========================================
|
|
12
|
+
* CORES PRINCIPAIS
|
|
13
|
+
* ======================================== */
|
|
14
|
+
|
|
15
|
+
--color-primary: #{hex da cor primária};
|
|
16
|
+
--color-primary-hover: #{hex da cor primária mais escura};
|
|
17
|
+
--color-primary-active: #{hex da cor primária ainda mais escura};
|
|
18
|
+
|
|
19
|
+
--color-secondary: #{hex da cor secundária};
|
|
20
|
+
--color-secondary-hover: #{hex};
|
|
21
|
+
--color-secondary-active: #{hex};
|
|
22
|
+
|
|
23
|
+
/* ========================================
|
|
24
|
+
* CORES DE ESTADO
|
|
25
|
+
* ======================================== */
|
|
26
|
+
|
|
27
|
+
--color-success: #{hex};
|
|
28
|
+
--color-success-bg: #{hex com transparência ou shade mais claro};
|
|
29
|
+
--color-success-border: #{hex};
|
|
30
|
+
|
|
31
|
+
--color-error: #{hex};
|
|
32
|
+
--color-error-bg: #{hex};
|
|
33
|
+
--color-error-border: #{hex};
|
|
34
|
+
|
|
35
|
+
--color-warning: #{hex};
|
|
36
|
+
--color-warning-bg: #{hex};
|
|
37
|
+
--color-warning-border: #{hex};
|
|
38
|
+
|
|
39
|
+
--color-info: #{hex};
|
|
40
|
+
--color-info-bg: #{hex};
|
|
41
|
+
--color-info-border: #{hex};
|
|
42
|
+
|
|
43
|
+
/* ========================================
|
|
44
|
+
* ESCALA DE NEUTROS (Cinzas)
|
|
45
|
+
* ======================================== */
|
|
46
|
+
|
|
47
|
+
--color-gray-50: #{hex};
|
|
48
|
+
--color-gray-100: #{hex};
|
|
49
|
+
--color-gray-200: #{hex};
|
|
50
|
+
--color-gray-300: #{hex};
|
|
51
|
+
--color-gray-400: #{hex};
|
|
52
|
+
--color-gray-500: #{hex};
|
|
53
|
+
--color-gray-600: #{hex};
|
|
54
|
+
--color-gray-700: #{hex};
|
|
55
|
+
--color-gray-800: #{hex};
|
|
56
|
+
--color-gray-900: #{hex};
|
|
57
|
+
|
|
58
|
+
/* ========================================
|
|
59
|
+
* TIPOGRAFIA - FONTES
|
|
60
|
+
* ======================================== */
|
|
61
|
+
|
|
62
|
+
--font-sans: '{Font Name}', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
63
|
+
--font-serif: '{Font Name}', Georgia, 'Times New Roman', serif;
|
|
64
|
+
--font-mono: '{Font Name}', 'Fira Code', 'Courier New', Consolas, monospace;
|
|
65
|
+
|
|
66
|
+
/* ========================================
|
|
67
|
+
* TIPOGRAFIA - TAMANHOS
|
|
68
|
+
* ======================================== */
|
|
69
|
+
|
|
70
|
+
--text-xs: 0.75rem; /* 12px */
|
|
71
|
+
--text-sm: 0.875rem; /* 14px */
|
|
72
|
+
--text-base: 1rem; /* 16px */
|
|
73
|
+
--text-lg: 1.125rem; /* 18px */
|
|
74
|
+
--text-xl: 1.25rem; /* 20px */
|
|
75
|
+
--text-2xl: 1.5rem; /* 24px */
|
|
76
|
+
--text-3xl: 1.875rem; /* 30px */
|
|
77
|
+
--text-4xl: 2.25rem; /* 36px */
|
|
78
|
+
--text-5xl: 3rem; /* 48px */
|
|
79
|
+
|
|
80
|
+
/* ========================================
|
|
81
|
+
* TIPOGRAFIA - LINE HEIGHTS
|
|
82
|
+
* ======================================== */
|
|
83
|
+
|
|
84
|
+
--leading-none: 1;
|
|
85
|
+
--leading-tight: 1.25;
|
|
86
|
+
--leading-snug: 1.375;
|
|
87
|
+
--leading-normal: 1.5;
|
|
88
|
+
--leading-relaxed: 1.625;
|
|
89
|
+
--leading-loose: 2;
|
|
90
|
+
|
|
91
|
+
/* ========================================
|
|
92
|
+
* TIPOGRAFIA - FONT WEIGHTS
|
|
93
|
+
* ======================================== */
|
|
94
|
+
|
|
95
|
+
--font-light: 300;
|
|
96
|
+
--font-regular: 400;
|
|
97
|
+
--font-medium: 500;
|
|
98
|
+
--font-semibold: 600;
|
|
99
|
+
--font-bold: 700;
|
|
100
|
+
--font-extrabold: 800;
|
|
101
|
+
|
|
102
|
+
/* ========================================
|
|
103
|
+
* ESPAÇAMENTO
|
|
104
|
+
* Baseado em múltiplos de {base}px (ex: 4px)
|
|
105
|
+
* ======================================== */
|
|
106
|
+
|
|
107
|
+
--space-0: 0;
|
|
108
|
+
--space-1: 0.25rem; /* 4px */
|
|
109
|
+
--space-2: 0.5rem; /* 8px */
|
|
110
|
+
--space-3: 0.75rem; /* 12px */
|
|
111
|
+
--space-4: 1rem; /* 16px */
|
|
112
|
+
--space-5: 1.25rem; /* 20px */
|
|
113
|
+
--space-6: 1.5rem; /* 24px */
|
|
114
|
+
--space-7: 1.75rem; /* 28px */
|
|
115
|
+
--space-8: 2rem; /* 32px */
|
|
116
|
+
--space-10: 2.5rem; /* 40px */
|
|
117
|
+
--space-12: 3rem; /* 48px */
|
|
118
|
+
--space-16: 4rem; /* 64px */
|
|
119
|
+
--space-20: 5rem; /* 80px */
|
|
120
|
+
--space-24: 6rem; /* 96px */
|
|
121
|
+
|
|
122
|
+
/* ========================================
|
|
123
|
+
* BORDER RADIUS
|
|
124
|
+
* ======================================== */
|
|
125
|
+
|
|
126
|
+
--rounded-none: 0;
|
|
127
|
+
--rounded-sm: 0.125rem; /* 2px */
|
|
128
|
+
--rounded-md: 0.375rem; /* 6px */
|
|
129
|
+
--rounded-lg: 0.5rem; /* 8px */
|
|
130
|
+
--rounded-xl: 0.75rem; /* 12px */
|
|
131
|
+
--rounded-2xl: 1rem; /* 16px */
|
|
132
|
+
--rounded-full: 9999px;
|
|
133
|
+
|
|
134
|
+
/* ========================================
|
|
135
|
+
* SOMBRAS (Shadows)
|
|
136
|
+
* ======================================== */
|
|
137
|
+
|
|
138
|
+
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
139
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
140
|
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
141
|
+
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
142
|
+
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
143
|
+
|
|
144
|
+
/* ========================================
|
|
145
|
+
* Z-INDEX LAYERS
|
|
146
|
+
* ======================================== */
|
|
147
|
+
|
|
148
|
+
--z-0: 0;
|
|
149
|
+
--z-10: 10;
|
|
150
|
+
--z-20: 20;
|
|
151
|
+
--z-30: 30;
|
|
152
|
+
--z-40: 40;
|
|
153
|
+
--z-50: 50; /* Modals, dropdowns */
|
|
154
|
+
--z-100: 100; /* Tooltips */
|
|
155
|
+
--z-max: 9999; /* Toasts, notifications */
|
|
156
|
+
|
|
157
|
+
/* ========================================
|
|
158
|
+
* TRANSITIONS / ANIMATIONS
|
|
159
|
+
* ======================================== */
|
|
160
|
+
|
|
161
|
+
--transition-fast: 150ms ease-in-out;
|
|
162
|
+
--transition-base: 250ms ease-in-out;
|
|
163
|
+
--transition-slow: 350ms ease-in-out;
|
|
164
|
+
|
|
165
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
166
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
167
|
+
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
168
|
+
|
|
169
|
+
/* ========================================
|
|
170
|
+
* BREAKPOINTS (informativo - usar em media queries)
|
|
171
|
+
* ======================================== */
|
|
172
|
+
|
|
173
|
+
/* @media (min-width: 640px) - sm */
|
|
174
|
+
/* @media (min-width: 768px) - md */
|
|
175
|
+
/* @media (min-width: 1024px) - lg */
|
|
176
|
+
/* @media (min-width: 1280px) - xl */
|
|
177
|
+
/* @media (min-width: 1536px) - 2xl */
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* ========================================
|
|
181
|
+
* MODO ESCURO (Dark Mode)
|
|
182
|
+
* Opcional - ajuste as cores para dark theme
|
|
183
|
+
* ======================================== */
|
|
184
|
+
|
|
185
|
+
@media (prefers-color-scheme: dark) {
|
|
186
|
+
:root {
|
|
187
|
+
/* Inverter cores conforme necessário */
|
|
188
|
+
--color-gray-50: #{hex do gray-900};
|
|
189
|
+
--color-gray-900: #{hex do gray-50};
|
|
190
|
+
/* ... outras inversões */
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* ========================================
|
|
195
|
+
* CLASSES UTILITÁRIAS (Exemplo)
|
|
196
|
+
* ======================================== */
|
|
197
|
+
|
|
198
|
+
/* Exemplo de uso das variáveis */
|
|
199
|
+
.btn-primary {
|
|
200
|
+
background-color: var(--color-primary);
|
|
201
|
+
color: white;
|
|
202
|
+
padding: var(--space-2) var(--space-4);
|
|
203
|
+
border-radius: var(--rounded-md);
|
|
204
|
+
font-weight: var(--font-semibold);
|
|
205
|
+
transition: background-color var(--transition-base);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.btn-primary:hover {
|
|
209
|
+
background-color: var(--color-primary-hover);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.card {
|
|
213
|
+
background-color: white;
|
|
214
|
+
padding: var(--space-6);
|
|
215
|
+
border-radius: var(--rounded-lg);
|
|
216
|
+
box-shadow: var(--shadow-md);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.text-muted {
|
|
220
|
+
color: var(--color-gray-600);
|
|
221
|
+
font-size: var(--text-sm);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* ========================================
|
|
225
|
+
* FIM DO DESIGN SYSTEM
|
|
226
|
+
* ======================================== */
|
package/package.json
CHANGED
|
@@ -145,6 +145,18 @@ function printMetricsBody(m) {
|
|
|
145
145
|
? trees.map(([tree, s]) => `${tree} rodou ${s.ran}, pulou ${s.skipped}`).join(' · ')
|
|
146
146
|
: 'nenhum evento Verify na janela'}`);
|
|
147
147
|
for (const [reason, n] of Object.entries(m.reuse.skipReasons)) console.log(chalk.gray(` pulou ${n}×: ${reason}`));
|
|
148
|
+
const gates = Object.entries(m.gates);
|
|
149
|
+
if (!gates.length) {
|
|
150
|
+
console.log(' gates: nenhum evento Gate na janela');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
for (const [gate, g] of gates) {
|
|
154
|
+
console.log(` gate ${gate}: ${g.decisions} decisões, ${g.paused} pausas → ${g.approvedAfterPause} aprovadas como estavam, `
|
|
155
|
+
+ `${g.reworkedAfterPause} retrabalhadas${g.unapproved ? `, ${g.unapproved} desaprovações` : ''}`);
|
|
156
|
+
for (const [signal, s] of Object.entries(g.bySignal)) {
|
|
157
|
+
console.log(chalk.gray(` ${signal}: ${s.paused} pausas, ${s.approvedAfterPause} aprovadas como estavam, ${s.reworkedAfterPause} retrabalhadas`));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
148
160
|
}
|
|
149
161
|
|
|
150
162
|
function printMetrics(feature, options, cwd) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { loadState, getFeature, derivePhase, deriveOutputs } from '../../core/state/state-manager.js';
|
|
3
3
|
import { sliceProgress } from '../../../framework/hooks/shared/slice-progress.js';
|
|
4
|
+
import { formatNext } from '../../../framework/hooks/shared/next-step.js';
|
|
5
|
+
import { nextStepFor } from '../../lib/next-step.js';
|
|
4
6
|
|
|
5
7
|
const PHASE_SYMBOLS = {
|
|
6
8
|
completed: '✅',
|
|
@@ -87,60 +89,6 @@ function calculateCompletionPercentage(feature) {
|
|
|
87
89
|
return Math.round((completedPhases / totalPhases) * 100);
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
function getNextSteps(feature) {
|
|
91
|
-
const steps = [];
|
|
92
|
-
|
|
93
|
-
const phaseApprovalMap = {
|
|
94
|
-
plan: 'plan',
|
|
95
|
-
uiux: 'uiux',
|
|
96
|
-
implement: 'plan',
|
|
97
|
-
review: 'review'
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const relevantGate = phaseApprovalMap[feature.phase];
|
|
101
|
-
const approvalGates = feature.approvalGates || {};
|
|
102
|
-
|
|
103
|
-
if (relevantGate && approvalGates[relevantGate] && !approvalGates[relevantGate].approved) {
|
|
104
|
-
steps.push({
|
|
105
|
-
type: 'approval',
|
|
106
|
-
message: `Approve ${relevantGate} to advance`,
|
|
107
|
-
command: `morph-spec approve ${feature.name || 'feature'} ${relevantGate}`
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const requiredOutputs = feature.phase === 'uiux' ? [] : PHASE_OUTPUTS[feature.phase] || [];
|
|
112
|
-
const missingOutputs = requiredOutputs.filter(o => !feature.outputs[o]?.created);
|
|
113
|
-
|
|
114
|
-
if (missingOutputs.length > 0) {
|
|
115
|
-
steps.push({
|
|
116
|
-
type: 'output',
|
|
117
|
-
message: `Create missing outputs: ${missingOutputs.join(', ')}`,
|
|
118
|
-
command: null
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const hasApprovalPending = relevantGate && approvalGates[relevantGate] && !approvalGates[relevantGate].approved;
|
|
123
|
-
if (missingOutputs.length === 0 && !hasApprovalPending) {
|
|
124
|
-
const currentPhaseIndex = PHASE_ORDER.findIndex(p => p.key === feature.phase);
|
|
125
|
-
if (currentPhaseIndex >= 0 && currentPhaseIndex < PHASE_ORDER.length - 1) {
|
|
126
|
-
const nextPhase = PHASE_ORDER[currentPhaseIndex + 1];
|
|
127
|
-
steps.push({
|
|
128
|
-
type: 'advance',
|
|
129
|
-
message: `Advance to ${nextPhase.name}`,
|
|
130
|
-
command: `morph-spec phase advance ${feature.name || 'feature'}`
|
|
131
|
-
});
|
|
132
|
-
} else if (currentPhaseIndex === PHASE_ORDER.length - 1) {
|
|
133
|
-
steps.push({
|
|
134
|
-
type: 'complete',
|
|
135
|
-
message: 'Feature complete! Consider archiving.',
|
|
136
|
-
command: null
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return steps;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
92
|
export async function statusCommand(featureName, options = {}) {
|
|
145
93
|
if (!featureName) {
|
|
146
94
|
console.error(chalk.red('✗ Error: Feature name required'));
|
|
@@ -191,7 +139,7 @@ export async function statusCommand(featureName, options = {}) {
|
|
|
191
139
|
})),
|
|
192
140
|
slices,
|
|
193
141
|
approvals: feature.approvalGates || {},
|
|
194
|
-
|
|
142
|
+
next: nextStepFor(featureName, process.cwd())
|
|
195
143
|
};
|
|
196
144
|
|
|
197
145
|
console.log(JSON.stringify(status, null, 2));
|
|
@@ -235,6 +183,7 @@ export async function statusCommand(featureName, options = {}) {
|
|
|
235
183
|
console.log(` Total: ${slices.total}`);
|
|
236
184
|
console.log(chalk.green(` ✓ Feitas: ${slices.done} (${percentage}%)`));
|
|
237
185
|
if (slices.partial > 0) console.log(chalk.cyan(` ▶ Parciais: ${slices.partial}`));
|
|
186
|
+
if (slices.blocked > 0) console.log(chalk.yellow(` ⏸ Bloqueadas (esperam decisão): ${slices.blocked}`));
|
|
238
187
|
if (slices.pending > 0) console.log(chalk.gray(` ⬜ Pendentes: ${slices.pending}`));
|
|
239
188
|
console.log('');
|
|
240
189
|
}
|
|
@@ -258,19 +207,8 @@ export async function statusCommand(featureName, options = {}) {
|
|
|
258
207
|
console.log('');
|
|
259
208
|
}
|
|
260
209
|
|
|
261
|
-
const
|
|
262
|
-
if (
|
|
263
|
-
console.log(chalk.white.bold('Next Steps:'));
|
|
264
|
-
nextSteps.forEach((step, index) => {
|
|
265
|
-
console.log(chalk.yellow(` ${index + 1}. ${step.message}`));
|
|
266
|
-
if (step.command) {
|
|
267
|
-
console.log(chalk.gray(` → ${step.command}`));
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
console.log('');
|
|
271
|
-
} else {
|
|
272
|
-
console.log(chalk.green('✓ Nada pendente.\n'));
|
|
273
|
-
}
|
|
210
|
+
const next = nextStepFor(featureName, process.cwd());
|
|
211
|
+
if (next) console.log(chalk.yellow(`${formatNext(next)}\n`));
|
|
274
212
|
|
|
275
213
|
console.log(chalk.gray('─'.repeat(60)));
|
|
276
214
|
console.log(chalk.gray('Run with --verbose for detailed output'));
|
|
@@ -143,7 +143,7 @@ export async function advanceCommand(featureName, options = {}) {
|
|
|
143
143
|
process.exit(1);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
console.error(chalk.red(`\n❌ A fase "${phase}" não pode ser encerrada — artefato(s) obrigatório(s) ausente(s) ou
|
|
146
|
+
console.error(chalk.red(`\n❌ A fase "${phase}" não pode ser encerrada — artefato(s) obrigatório(s) ausente(s), PARCIAL ou BLOQUEADO:`));
|
|
147
147
|
for (const rel of missingArtifacts) console.error(chalk.gray(` • ${rel}`));
|
|
148
148
|
console.error(chalk.gray('\n Produza o artefato e rode de novo, ou passe --force para avançar assim mesmo.\n'));
|
|
149
149
|
process.exit(1);
|
|
@@ -19,10 +19,10 @@ export { REVIEWED_SHA_TOKEN };
|
|
|
19
19
|
|
|
20
20
|
const SIGNED_OFF = { required: [], reports: {}, checks: { status: 'ok', total: 0, missing: [], notProven: [] } };
|
|
21
21
|
|
|
22
|
-
// The worst answer across every report present wins. `skip` (no
|
|
22
|
+
// The worst answer across every report present wins. `skip` (no report at all, no git) never
|
|
23
23
|
// refuses falsely.
|
|
24
24
|
function reviewStaleness(reports) {
|
|
25
|
-
if (reports.
|
|
25
|
+
if (Object.values(reports).every((r) => r.status === 'missing')) return { status: 'skip' };
|
|
26
26
|
const cwd = process.cwd();
|
|
27
27
|
let head;
|
|
28
28
|
try {
|
|
@@ -189,10 +189,10 @@ export async function gateCheckCommand(featureName, gateName, options = {}) {
|
|
|
189
189
|
const computed = shouldPauseGate({ trust }, signals);
|
|
190
190
|
const manual = feature.gateDecisions?.[gateName];
|
|
191
191
|
const manualPause = manual?.source === 'manual' && manual.pause === true;
|
|
192
|
-
const { pause, reason } = manualPause ? { pause: true, reason: manual.reason } : computed;
|
|
192
|
+
const { pause, reason, signal } = manualPause ? { pause: true, reason: manual.reason, signal: 'manual' } : computed;
|
|
193
193
|
|
|
194
194
|
const entry = await persistGateDecision(featureName, gateName, {
|
|
195
|
-
pause, reason, signals, trust, cwd, source: manualPause ? 'manual' : 'gate-check',
|
|
195
|
+
pause, reason, signal, signals, trust, cwd, source: manualPause ? 'manual' : 'gate-check',
|
|
196
196
|
});
|
|
197
197
|
|
|
198
198
|
if (options.json) {
|
|
@@ -4,6 +4,7 @@ import { join } from 'path';
|
|
|
4
4
|
import { getFeature, updateFeature } from '../../core/state/state-manager.js';
|
|
5
5
|
import { assertOwnerTree, ownerTreeRefusalLines } from '../../lib/worktree/feature-truth.js';
|
|
6
6
|
import { mockupsHash } from '../../lib/specs/screen-checklist.js';
|
|
7
|
+
import { recordGateEvent } from '../../../framework/hooks/shared/gate-event.js';
|
|
7
8
|
|
|
8
9
|
export const VALID_GATES = ['plan', 'uiux', 'review'];
|
|
9
10
|
|
|
@@ -31,7 +32,7 @@ export function readTrustFromConfig() {
|
|
|
31
32
|
* The ONE write path of `gateDecisions.{gate}`, shared by `gate-decision` and `gate-check`.
|
|
32
33
|
* Does not validate `gateName`. A uiux decision records the `mockupsHash` it saw.
|
|
33
34
|
*/
|
|
34
|
-
export async function persistGateDecision(featureName, gateName, { pause, reason, signals = {}, trust, cwd = process.cwd(), source } = {}) {
|
|
35
|
+
export async function persistGateDecision(featureName, gateName, { pause, reason, signal, signals = {}, trust, cwd = process.cwd(), source } = {}) {
|
|
35
36
|
const entry = {
|
|
36
37
|
pause,
|
|
37
38
|
reason: reason || (pause ? 'risco detectado' : 'nenhum sinal de risco'),
|
|
@@ -43,6 +44,7 @@ export async function persistGateDecision(featureName, gateName, { pause, reason
|
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
await updateFeature(featureName, `gateDecisions.${gateName}`, entry);
|
|
47
|
+
recordGateEvent(cwd, { feature: featureName, gate: gateName, step: 'decision', pause, signal, source });
|
|
46
48
|
return entry;
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -91,6 +93,7 @@ export async function gateDecisionCommand(featureName, gateName, options = {}) {
|
|
|
91
93
|
const entry = await persistGateDecision(featureName, gateName, {
|
|
92
94
|
pause,
|
|
93
95
|
reason: options.reason,
|
|
96
|
+
signal: 'manual',
|
|
94
97
|
signals,
|
|
95
98
|
trust: options.trust,
|
|
96
99
|
source: 'manual',
|