@polymorphism-tech/morph-spec 9.7.0 → 10.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 (211) hide show
  1. package/CLAUDE.md +11 -11
  2. package/README.md +4 -4
  3. package/bin/morph-spec.js +41 -44
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +24 -30
  8. package/framework/MORPH.md +47 -123
  9. package/framework/agents.json +6 -374
  10. package/framework/commands/morph-apply.md +1 -1
  11. package/framework/commands/morph-archive.md +4 -3
  12. package/framework/commands/morph-hotfix.md +8 -30
  13. package/framework/commands/morph-infra.md +2 -2
  14. package/framework/commands/morph-media.md +10 -9
  15. package/framework/commands/morph-review.md +15 -0
  16. package/framework/commands/morph-status.md +1 -1
  17. package/framework/docs/CLI.md +100 -102
  18. package/framework/evals/review-checklist.md +46 -54
  19. package/framework/hooks/README.md +4 -4
  20. package/framework/hooks/claude-code/__pycache__/statusline.cpython-313.pyc +0 -0
  21. package/framework/hooks/claude-code/core/README.md +1 -1
  22. package/framework/hooks/claude-code/core/denylist.json +4 -4
  23. package/framework/hooks/claude-code/core/gate-guard.js +9 -0
  24. package/framework/hooks/claude-code/core/masked-exit.js +49 -0
  25. package/framework/hooks/claude-code/core/state-sync.js +4 -1
  26. package/framework/hooks/claude-code/core/telemetry-log.js +1 -2
  27. package/framework/hooks/claude-code/core/test-budget.js +10 -70
  28. package/framework/hooks/claude-code/core/validate-completion.js +11 -24
  29. package/framework/hooks/claude-code/core/worktree-context.js +5 -22
  30. package/framework/hooks/claude-code/core/worktree-create.js +6 -45
  31. package/framework/hooks/claude-code/core/worktree-env-inject.js +2 -10
  32. package/framework/hooks/shared/e2e-check.js +0 -0
  33. package/framework/hooks/shared/gate-event.js +2 -2
  34. package/framework/hooks/shared/graph-refresh.js +20 -3
  35. package/framework/hooks/shared/heavy-command.js +32 -1
  36. package/framework/hooks/shared/heavy-config.js +1 -1
  37. package/framework/hooks/shared/heavy-slots.js +41 -4
  38. package/framework/hooks/shared/next-step.js +63 -24
  39. package/framework/hooks/shared/phase-utils.js +6 -9
  40. package/framework/hooks/shared/report-progress.js +86 -0
  41. package/framework/hooks/shared/state-reader.js +3 -2
  42. package/framework/hooks/statusline.js +332 -0
  43. package/framework/phases.json +32 -10
  44. package/framework/rules/ai-agents-standards.md +9 -1
  45. package/framework/rules/csharp-standards.md +4 -0
  46. package/framework/rules/ef-standards.md +20 -0
  47. package/framework/rules/frontend-standards.md +1 -1
  48. package/framework/rules/implement-report.md +25 -0
  49. package/framework/rules/infrastructure-standards.md +2 -0
  50. package/framework/rules/nextjs-standards.md +7 -0
  51. package/framework/rules/plan-grammar.md +53 -0
  52. package/framework/rules/ui-design.md +27 -0
  53. package/framework/schemas/config.schema.json +12 -19
  54. package/framework/schemas/feature.schema.json +7 -1
  55. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  56. package/framework/skills/core/create-umbraco-lp/references/umbraco-lp-patterns.md +1 -1
  57. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +2 -2
  58. package/framework/skills/core/morph-apply/SKILL.md +38 -166
  59. package/framework/skills/core/morph-apply/references/debugging.md +8 -0
  60. package/framework/skills/core/morph-apply/references/hotfix.md +42 -0
  61. package/framework/skills/core/morph-apply/references/machine.md +29 -0
  62. package/framework/skills/core/{morph-media/SKILL.md → morph-apply/references/media.md} +11 -74
  63. package/framework/skills/core/morph-apply/references/review.md +65 -0
  64. package/framework/skills/core/morph-plan/SKILL.md +42 -108
  65. package/framework/skills/core/morph-plan/references/critique.md +40 -0
  66. package/framework/skills/core/morph-plan/references/interview.md +25 -0
  67. package/framework/skills/core/morph-uiux/SKILL.md +47 -64
  68. package/framework/skills/core/morph-uiux/surfaces.json +32 -0
  69. package/framework/standards/STANDARDS.json +32 -5
  70. package/framework/standards/STANDARDS.meta.json +5 -1
  71. package/framework/standards/ai-agents/agent-session.md +2 -3
  72. package/framework/standards/ai-agents/context-providers.md +2 -2
  73. package/framework/standards/ai-agents/durable-workflows-hitl.md +2 -2
  74. package/framework/standards/ai-agents/providers/model-registry.md +2 -2
  75. package/framework/standards/ai-agents/rag-custom-pgvector.md +6 -6
  76. package/framework/standards/ai-agents/setup.md +1 -1
  77. package/framework/standards/ai-agents/tool-adapters.md +2 -2
  78. package/framework/standards/architecture/stack-baseline.md +47 -0
  79. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -4
  80. package/framework/standards/frontend/design-system/ai-image-generation.md +51 -12
  81. package/framework/standards/frontend/design-system/ai-video-generation.md +50 -4
  82. package/framework/standards/frontend/design-system/art-direction.md +2 -2
  83. package/framework/standards/frontend/scroll-driven/frame-scrub.md +12 -2
  84. package/framework/standards/frontend/scroll-driven/scroll-components.md +76 -4
  85. package/framework/templates/.idea/morph-templates.xml +92 -0
  86. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  87. package/framework/templates/IDE-SNIPPETS.md +262 -262
  88. package/framework/templates/REGISTRY.json +1 -2
  89. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  90. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  91. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  92. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  93. package/framework/templates/context/ARCHITECTURE.md +1 -1
  94. package/framework/templates/docs/plan.md +12 -12
  95. package/framework/templates/docs/ui-mockups.md +17 -105
  96. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  97. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  98. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  99. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  100. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  101. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  102. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  103. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  104. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  105. package/framework/templates/state.template.json +17 -17
  106. package/framework/templates/ui/design-system.css +226 -226
  107. package/package.json +1 -1
  108. package/src/commands/e2e/e2e.js +88 -23
  109. package/src/commands/graph/diff.js +74 -0
  110. package/src/commands/graph/status.js +1 -1
  111. package/src/commands/observability/cost.js +2 -4
  112. package/src/commands/observability/telemetry.js +1 -1
  113. package/src/commands/project/doctor.js +23 -39
  114. package/src/commands/project/fleet.js +5 -6
  115. package/src/commands/project/init.js +63 -36
  116. package/src/commands/project/stack-scan.js +3 -42
  117. package/src/commands/project/stack-set.js +26 -0
  118. package/src/commands/project/status.js +12 -13
  119. package/src/commands/project/update.js +39 -3
  120. package/src/commands/project/worktree.js +27 -16
  121. package/src/commands/state/advance.js +17 -17
  122. package/src/commands/state/approve.js +0 -6
  123. package/src/commands/state/archive.js +27 -1
  124. package/src/commands/state/auto-approval.js +1 -1
  125. package/src/commands/state/create.js +0 -5
  126. package/src/commands/state/finish.js +43 -1
  127. package/src/commands/state/gate-check.js +37 -30
  128. package/src/commands/state/gate-decision.js +3 -2
  129. package/src/commands/state/next.js +1 -0
  130. package/src/commands/state/recap.js +67 -0
  131. package/src/commands/state/report-check.js +39 -146
  132. package/src/commands/validation/plan-check.js +16 -11
  133. package/src/commands/validation/validate-feature.js +3 -3
  134. package/src/commands/validation/verify.js +6 -6
  135. package/src/core/paths/output-schema.js +3 -3
  136. package/src/core/state/state-manager.js +2 -4
  137. package/src/dashboard/app/components/CommandPalette.jsx +2 -5
  138. package/src/dashboard/app/components/GatePauses.jsx +116 -0
  139. package/src/dashboard/app/components/SessionMap.jsx +77 -0
  140. package/src/dashboard/app/main.jsx +13 -13
  141. package/src/dashboard/app/pages/Activity.jsx +4 -0
  142. package/src/dashboard/app/pages/AgentMap.jsx +1 -2
  143. package/src/dashboard/app/pages/FeatureDetail.jsx +129 -186
  144. package/src/dashboard/app/pages/Features.jsx +7 -7
  145. package/src/dashboard/app/pages/PhasePipeline.jsx +1 -1
  146. package/src/dashboard/app/pages/Portfolio.jsx +40 -5
  147. package/src/dashboard/scanner/activity-scanner.js +29 -0
  148. package/src/dashboard/scanner/agents-scanner.js +11 -14
  149. package/src/dashboard/scanner/features-scanner.js +45 -24
  150. package/src/dashboard/scanner/project-api.js +11 -2
  151. package/src/dashboard/scanner/skills-scanner.js +11 -1
  152. package/src/dashboard/vite.config.js +24 -24
  153. package/src/lib/e2e/applicability.js +3 -1
  154. package/src/lib/git/tree-state.js +1 -16
  155. package/src/lib/graph/diff-tree.js +127 -0
  156. package/src/lib/graph/graphify-runtime.js +12 -5
  157. package/src/lib/heavy/gate.js +22 -1
  158. package/src/lib/installers/memory-installer.js +2 -2
  159. package/src/lib/installers/rules-installer.js +57 -0
  160. package/src/lib/installers/stack-assets.js +17 -0
  161. package/src/lib/installers/stack-sync.js +219 -0
  162. package/src/lib/plan/checks.js +55 -110
  163. package/src/lib/plan/critique.js +28 -0
  164. package/src/lib/plan/media.js +42 -0
  165. package/src/lib/plan/plan-html.js +125 -0
  166. package/src/lib/plan/plan-parser.js +34 -45
  167. package/src/lib/recap/piper.js +36 -0
  168. package/src/lib/recap/recap.js +232 -0
  169. package/src/lib/review-reports.js +33 -7
  170. package/src/lib/risk-detector.js +90 -11
  171. package/src/lib/specs/screen-checklist.js +33 -48
  172. package/src/lib/stack/dotnet-build-ignores.js +8 -9
  173. package/src/lib/tasks/test-nodes.js +24 -6
  174. package/src/lib/tasks/test-runner.js +40 -1
  175. package/src/lib/telemetry/metrics.js +27 -29
  176. package/src/lib/validators/reuse/reuse-validator.js +1 -9
  177. package/src/lib/validators/verify-runner.js +50 -19
  178. package/src/lib/worktree/fleet-scanner.js +7 -20
  179. package/src/lib/worktree/worktree-audit.js +0 -37
  180. package/src/scripts/setup-infra.js +15 -50
  181. package/src/utils/agents-installer.js +27 -201
  182. package/src/utils/hooks-installer.js +11 -95
  183. package/framework/hooks/claude-code/core/warn-bash-source-write.js +0 -23
  184. package/framework/hooks/claude-code/statusline.py +0 -699
  185. package/framework/hooks/claude-code/statusline.sh +0 -11
  186. package/framework/hooks/shared/agent-reap.js +0 -74
  187. package/framework/hooks/shared/slice-progress.js +0 -110
  188. package/framework/skills/core/morph-hotfix/SKILL.md +0 -133
  189. package/framework/skills/core/morph-machine/SKILL.md +0 -46
  190. package/framework/skills/core/morph-review/SKILL.md +0 -129
  191. package/framework/skills/core/morph-standards/SKILL.md +0 -52
  192. package/framework/standards/PROVENANCE.json +0 -119
  193. package/src/commands/project/worktree-reap.js +0 -34
  194. package/src/commands/state/handoff.js +0 -65
  195. package/src/commands/validation/mutate.js +0 -263
  196. package/src/commands/validation/scout-check.js +0 -28
  197. package/src/lib/generators/handoff-generator.js +0 -172
  198. package/src/lib/mutation/adapters.js +0 -79
  199. package/src/lib/mutation/commands.js +0 -61
  200. package/src/lib/mutation/dotnet-introspection.js +0 -281
  201. package/src/lib/mutation/manifest.js +0 -144
  202. package/src/lib/mutation/plan.js +0 -44
  203. package/src/lib/mutation/report.js +0 -68
  204. package/src/lib/mutation/runner.js +0 -301
  205. package/src/lib/mutation/schemata.js +0 -60
  206. package/src/lib/mutation/snapshot.js +0 -65
  207. package/src/lib/mutation/subset.js +0 -109
  208. package/src/lib/mutation/trx.js +0 -50
  209. package/src/lib/scout/scout-check.js +0 -293
  210. package/src/lib/validators/traceability-check.js +0 -103
  211. package/src/lib/worktree/agent-reaper.js +0 -247
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "9.7.0",
3
+ "version": "10.0.0",
4
4
  "description": "MORPH-SPEC: NLH (Natural Language Harness) for spec-driven development with Claude Code",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -16,7 +16,9 @@ import {
16
16
  deleteStamp,
17
17
  getStackStatus,
18
18
  isDockerAvailable,
19
+ isHostOnlyStack,
19
20
  lintComposeIsolation,
21
+ resetE2eData,
20
22
  readStamp,
21
23
  resolveComposeFile,
22
24
  resolveSpecCommand,
@@ -34,8 +36,9 @@ import { readHeavyConfig } from '../../../framework/hooks/shared/heavy-config.js
34
36
  const EXIT_USAGE = 2;
35
37
  const EXIT_BUSY = 3;
36
38
 
37
- // No compose file is a usage error here, unlike in the verify node where it is a graded skip.
38
- function resolveContext(featureName, { json = false } = {}) {
39
+ // No compose file and no e2e.hostServices is a usage error here, unlike in the verify node where
40
+ // it is a graded skip. `composeFile` is null for a host-only stack.
41
+ function resolveContext(featureName, { json = false, onMissing } = {}) {
39
42
  const root = resolvePrimaryRoot(process.cwd());
40
43
  const found = findWorktreeForFeature(featureName, root);
41
44
  const cwd = found?.path ?? root;
@@ -43,11 +46,13 @@ function resolveContext(featureName, { json = false } = {}) {
43
46
  const config = readConfig(cwd) ?? readConfig(root);
44
47
  const composeFile = resolveComposeFile(cwd, config);
45
48
 
46
- if (!composeFile) {
49
+ if (!composeFile && !isHostOnlyStack(config, composeFile)) {
47
50
  const message =
48
- `No compose file found in ${cwd} (compose.yaml, docker-compose.yml, …). ` +
49
- 'Set project.e2e.composeFile in .morph/config/config.json if it lives elsewhere.';
50
- if (json) console.log(JSON.stringify({ error: message, tree: cwd }, null, 2));
51
+ `No compose file found in ${cwd} (compose.yaml, docker-compose.yml, …) and no e2e.hostServices. ` +
52
+ 'Set e2e.composeFile in .morph/config/config.json if it lives elsewhere, ' +
53
+ 'or declare the app in e2e.hostServices when it has no dependency to containerize.';
54
+ if (onMissing) onMissing(message, cwd);
55
+ else if (json) console.log(JSON.stringify({ error: message, tree: cwd }, null, 2));
51
56
  else console.error(chalk.red(`\n❌ ${message}\n`));
52
57
  return null;
53
58
  }
@@ -86,7 +91,7 @@ export async function e2eUpCommand(featureName, options = {}) {
86
91
 
87
92
  // Isolation BEFORE the docker check: a compose that hardcodes host ports or container names
88
93
  // collides with a sibling worktree whatever we inject.
89
- const lint = lintComposeIsolation(readComposeText(ctx.cwd, ctx.composeFile));
94
+ const lint = ctx.composeFile ? lintComposeIsolation(readComposeText(ctx.cwd, ctx.composeFile)) : { findings: [] };
90
95
  const isolation = decideIsolation({ findings: lint.findings, insideWorktree: ctx.insideWorktree });
91
96
  if (isolation.status === 'fail') {
92
97
  if (options.json) {
@@ -106,7 +111,7 @@ export async function e2eUpCommand(featureName, options = {}) {
106
111
  }
107
112
 
108
113
  const exec = options._exec ?? defaultExec;
109
- if (!isDockerAvailable(ctx.cwd, exec)) {
114
+ if (ctx.composeFile && !isDockerAvailable(ctx.cwd, exec)) {
110
115
  console.error(chalk.red('\n❌ Docker is not available in this environment.\n'));
111
116
  process.exit(EXIT_USAGE);
112
117
  }
@@ -149,7 +154,7 @@ export async function e2eUpCommand(featureName, options = {}) {
149
154
  tree: ctx.tree,
150
155
  composeFile: ctx.composeFile,
151
156
  status: failed ? 'fail' : 'pass',
152
- reused: result.stack.reused,
157
+ reused: ctx.composeFile ? result.stack.reused : hostServices.reused,
153
158
  reason: result.reason,
154
159
  auth: { status: auth.status, reason: auth.reason },
155
160
  ...(hostServices.status === 'skip' ? {} : { hostServices: hostServices.services }),
@@ -164,7 +169,9 @@ export async function e2eUpCommand(featureName, options = {}) {
164
169
  if (result.output) console.error(result.output);
165
170
  for (const w of result.warnings) console.error(chalk.yellow(`⚠️ ${w}`));
166
171
  } else {
167
- const how = result.stack.reused ? chalk.gray(`(${result.stack.reason})`) : chalk.gray('(built)');
172
+ const how = !ctx.composeFile
173
+ ? chalk.gray(`(${result.stack.reason})`)
174
+ : result.stack.reused ? chalk.gray(`(${result.stack.reason})`) : chalk.gray('(built)');
168
175
  console.log(chalk.green(`\n✓ Stack up — ${ctx.projectName} ${how}`));
169
176
  console.log(chalk.gray(` tree: ${ctx.tree}`));
170
177
  for (const s of hostServices.services) {
@@ -190,18 +197,24 @@ export async function e2eStatusCommand(featureName, options = {}) {
190
197
  if (!ctx) process.exit(EXIT_USAGE);
191
198
 
192
199
  const exec = options._exec ?? defaultExec;
193
- const status = getStackStatus(ctx.cwd, {
194
- composeFile: ctx.composeFile,
195
- projectName: ctx.projectName,
196
- env: ctx.env,
197
- }, exec);
200
+ const hostServices = ctx.gitCommonDir ? hostServicesStatus(ctx.gitCommonDir, ctx.projectName) : [];
201
+ const status = ctx.composeFile
202
+ ? getStackStatus(ctx.cwd, {
203
+ composeFile: ctx.composeFile,
204
+ projectName: ctx.projectName,
205
+ env: ctx.env,
206
+ }, exec)
207
+ : {
208
+ up: hostServices.length > 0 && hostServices.every((h) => h.alive),
209
+ healthy: hostServices.length > 0 && hostServices.every((h) => h.alive && h.health !== false),
210
+ services: [],
211
+ };
198
212
 
199
213
  const stamp = computeSourceStamp(ctx.cwd, exec);
200
214
  const previous = ctx.gitCommonDir ? readStamp(ctx.gitCommonDir, ctx.projectName) : null;
201
215
  const fresh = Boolean(stamp && previous?.stamp === stamp);
202
216
 
203
217
  const spec = resolveSpecCommand(ctx.cwd, ctx.config, ctx.config?.project?.frontendPath);
204
- const hostServices = ctx.gitCommonDir ? hostServicesStatus(ctx.gitCommonDir, ctx.projectName) : [];
205
218
 
206
219
  const payload = {
207
220
  feature: featureName,
@@ -228,7 +241,7 @@ export async function e2eStatusCommand(featureName, options = {}) {
228
241
  console.log('');
229
242
  console.log(chalk.bold(`E2E stack — ${ctx.projectName}`));
230
243
  console.log(chalk.gray(`tree: ${ctx.tree}`));
231
- console.log(chalk.gray(`compose: ${ctx.composeFile}`));
244
+ console.log(chalk.gray(`compose: ${ctx.composeFile ?? 'none (host services only)'}`));
232
245
  console.log(chalk.gray(`url: ${payload.baseUrl}`));
233
246
  console.log('');
234
247
  console.log(` up ${status.up ? chalk.green('yes') : chalk.gray('no')}`);
@@ -257,12 +270,14 @@ export async function e2eDownCommand(featureName, options = {}) {
257
270
  if (!ctx) process.exit(EXIT_USAGE);
258
271
 
259
272
  const hostServices = stopHostServices(ctx.gitCommonDir, ctx.projectName);
260
- const result = tearDownStack(ctx.cwd, {
261
- composeFile: ctx.composeFile,
262
- projectName: ctx.projectName,
263
- env: ctx.env,
264
- volumes: Boolean(options.volumes),
265
- }, options._exec ?? defaultExec);
273
+ const result = ctx.composeFile
274
+ ? tearDownStack(ctx.cwd, {
275
+ composeFile: ctx.composeFile,
276
+ projectName: ctx.projectName,
277
+ env: ctx.env,
278
+ volumes: Boolean(options.volumes),
279
+ }, options._exec ?? defaultExec)
280
+ : { status: 'pass', output: '' };
266
281
  const stampDeleted = deleteStamp(ctx.gitCommonDir, ctx.projectName);
267
282
  const cleanup = afterHeavyRun({ projectPath: ctx.cwd, config: readHeavyConfig(ctx.cwd) });
268
283
 
@@ -288,6 +303,56 @@ export async function e2eDownCommand(featureName, options = {}) {
288
303
  process.exit(0);
289
304
  }
290
305
 
306
+ // Between the verifier's flows: the next flow starts from the seeded state, not from the rows the
307
+ // previous one left. Exit 1 only on fail; skip (nothing configured to reset) is exit 0.
308
+ export async function e2eResetCommand(featureName, options = {}) {
309
+ const emit = (payload) => {
310
+ if (options.json) {
311
+ console.log(JSON.stringify(payload, null, 2));
312
+ } else if (payload.status === 'fail') {
313
+ console.error(chalk.red(`\n✗ ${payload.reason}\n`));
314
+ if (payload.output) console.error(payload.output);
315
+ } else if (payload.status === 'skip') {
316
+ console.log(chalk.gray(`\n○ e2e reset: ${payload.reason}\n`));
317
+ } else {
318
+ const what = payload.reset.mode === 'command'
319
+ ? `e2e.resetCommand (${payload.reset.command})`
320
+ : payload.reset.mode === 'volumes'
321
+ ? `recreated ${payload.reset.services.join(', ')} (volumes ${payload.reset.volumes.join(', ')})`
322
+ : 'no data reset';
323
+ console.log(chalk.green(`\n✓ e2e reset — ${what}`));
324
+ if (payload.auth.reason) console.log(chalk.gray(` auth: ${payload.auth.reason}`));
325
+ console.log('');
326
+ }
327
+ process.exit(payload.status === 'fail' ? 1 : 0);
328
+ };
329
+
330
+ const ctx = resolveContext(featureName, {
331
+ ...options,
332
+ onMissing: (message, tree) => emit({ feature: featureName, tree, status: 'fail', reason: message }),
333
+ });
334
+ if (!ctx) return;
335
+
336
+ const result = resetE2eData(ctx.cwd, {
337
+ config: ctx.config,
338
+ composeFile: ctx.composeFile,
339
+ projectName: ctx.projectName,
340
+ gitCommonDir: ctx.gitCommonDir,
341
+ env: ctx.env,
342
+ }, options._exec ?? defaultExec);
343
+
344
+ emit({
345
+ feature: featureName,
346
+ project: ctx.projectName,
347
+ tree: ctx.tree,
348
+ status: result.status,
349
+ reason: result.reason,
350
+ reset: result.reset,
351
+ auth: result.auth,
352
+ ...(result.status === 'fail' && result.output ? { output: result.output } : {}),
353
+ });
354
+ }
355
+
291
356
  function stoppedAnything({ killed, skipped, warnings }) {
292
357
  return killed.length + skipped.length + warnings.length > 0;
293
358
  }