@polymorphism-tech/morph-spec 4.10.9 → 4.11.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 (145) hide show
  1. package/CLAUDE.md +3 -3
  2. package/LICENSE +71 -71
  3. package/README.md +5 -11
  4. package/bin/morph-spec.js +23 -1
  5. package/bin/task-manager.js +5 -5
  6. package/claude-plugin.json +1 -1
  7. package/docs/CHEATSHEET.md +1 -1
  8. package/docs/QUICKSTART.md +2 -8
  9. package/framework/agents/README.md +14 -14
  10. package/framework/agents/architecture/standards-architect.md +159 -159
  11. package/framework/agents/frontend/css-specialist.md +1 -1
  12. package/framework/agents/infrastructure/azure-architect.md +149 -149
  13. package/framework/agents/infrastructure/azure-deploy-specialist.md +4 -4
  14. package/framework/agents/infrastructure/infra-architect.md +48 -48
  15. package/framework/commands/morph-apply.md +18 -18
  16. package/framework/commands/morph-preflight.md +3 -3
  17. package/framework/commands/morph-proposal.md +15 -15
  18. package/framework/commands/morph-status.md +3 -3
  19. package/framework/commands/morph-troubleshoot.md +1 -1
  20. package/framework/hooks/README.md +204 -204
  21. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +2 -2
  22. package/framework/hooks/claude-code/session-start/inject-morph-context.js +1 -1
  23. package/framework/hooks/claude-code/teammate-idle/teammate-idle.js +3 -3
  24. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +2 -2
  25. package/framework/hooks/git/pre-commit/agents.sh +1 -1
  26. package/framework/hooks/shared/phase-utils.js +139 -139
  27. package/framework/rules/csharp-standards.md +13 -13
  28. package/framework/rules/frontend-standards.md +13 -13
  29. package/framework/rules/infrastructure-standards.md +16 -16
  30. package/framework/rules/testing-standards.md +14 -14
  31. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +8 -8
  32. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +3 -3
  33. package/framework/skills/level-0-meta/morph-code-review-nextjs/references/review-example-nextjs.md +254 -254
  34. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
  35. package/framework/skills/level-0-meta/morph-init/SKILL.md +11 -11
  36. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +3 -3
  37. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +1 -1
  38. package/framework/skills/level-0-meta/morph-simulation-checklist/SKILL.md +4 -4
  39. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +25 -25
  40. package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +8 -8
  41. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +7 -7
  42. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +4 -4
  43. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +23 -23
  44. package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +1 -1
  45. package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +38 -0
  46. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +29 -29
  47. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +4 -4
  48. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +9 -9
  49. package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +17 -17
  50. package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +14 -0
  51. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +12 -12
  52. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +16 -16
  53. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +5 -5
  54. package/framework/standards/STANDARDS.json +2338 -2041
  55. package/framework/standards/frontend/nextjs/nextjs-patterns.md +17 -17
  56. package/framework/standards/infrastructure/supabase/supabase-custom-jwt.md +206 -0
  57. package/framework/templates/.idea/morph-templates.xml +92 -0
  58. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  59. package/framework/templates/README.md +814 -814
  60. package/framework/templates/code/dotnet/contracts/Commands.cs +74 -74
  61. package/framework/templates/code/dotnet/contracts/Entities.cs +25 -25
  62. package/framework/templates/code/dotnet/contracts/Queries.cs +74 -74
  63. package/framework/templates/code/dotnet/contracts/README.md +74 -74
  64. package/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -173
  65. package/framework/templates/code/dotnet/frontend/component.razor +239 -239
  66. package/framework/templates/code/dotnet/jobs/agent.cs +163 -163
  67. package/framework/templates/code/dotnet/jobs/job.cs +171 -171
  68. package/framework/templates/code/dotnet/test.cs +239 -239
  69. package/framework/templates/code/sql/rls-policy.sql +57 -57
  70. package/framework/templates/code/sql/supabase-migration.sql +100 -100
  71. package/framework/templates/code/sql/supabase-migration.template.sql +113 -113
  72. package/framework/templates/code/typescript/contracts.ts +168 -168
  73. package/framework/templates/context/CONTEXT.md +181 -181
  74. package/framework/templates/docs/proposal.md +182 -182
  75. package/framework/templates/docs/user-stories.md +34 -34
  76. package/framework/templates/examples/design-system-examples.md +357 -357
  77. package/framework/templates/examples/spec-examples.md +90 -90
  78. package/framework/templates/feature/decisions.md +187 -187
  79. package/framework/templates/feature/recap.md +146 -146
  80. package/framework/templates/feature/tasks.md +199 -199
  81. package/framework/templates/infrastructure/azure/README.md +286 -286
  82. package/framework/templates/infrastructure/azure/deploy-checklist.md +426 -426
  83. package/framework/templates/infrastructure/azure/parameters.dev.json +29 -29
  84. package/framework/templates/infrastructure/azure/parameters.prod.json +29 -29
  85. package/framework/templates/infrastructure/azure/parameters.staging.json +29 -29
  86. package/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -67
  87. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  88. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  89. package/framework/templates/infrastructure/docker/easypanel.template.json +54 -54
  90. package/framework/workflows/README.md +18 -18
  91. package/framework/workflows/docs/enforcement-pipeline.md +1 -1
  92. package/framework/workflows/docs/full-morph.md +2 -2
  93. package/package.json +1 -1
  94. package/src/commands/agents/dispatch-agents.js +17 -0
  95. package/src/commands/agents/index.js +13 -13
  96. package/src/commands/agents/project-metrics.js +74 -0
  97. package/src/commands/project/doctor.js +3 -4
  98. package/src/commands/project/install-plugin-cmd.js +28 -28
  99. package/src/commands/project/setup-infra-cmd.js +12 -12
  100. package/src/commands/project/status.js +8 -1
  101. package/src/commands/scope/escalate.js +5 -3
  102. package/src/commands/standards/context-budget.js +89 -0
  103. package/src/commands/tasks/index.js +4 -4
  104. package/src/commands/templates/index.js +5 -5
  105. package/src/commands/utils/index.js +3 -3
  106. package/src/commands/validation/index.js +4 -4
  107. package/src/commands/validation/validate-feature.js +32 -3
  108. package/src/core/state/phase-state-machine.js +217 -217
  109. package/src/lib/agents/metrics-aggregator.js +56 -0
  110. package/src/lib/generators/design-system-generator.js +298 -298
  111. package/src/lib/generators/index.js +10 -10
  112. package/src/lib/generators/metadata-extractor.js +387 -387
  113. package/src/lib/stack-filter.js +65 -65
  114. package/src/lib/standards/digest-builder.js +57 -3
  115. package/src/lib/standards/index.js +7 -7
  116. package/src/lib/standards/standards-context-injector.js +302 -302
  117. package/src/lib/validators/architecture/architecture-validator.js +387 -387
  118. package/src/lib/validators/architecture/index.js +7 -7
  119. package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +316 -316
  120. package/src/lib/validators/blazor/blazor-state-validator.js +279 -279
  121. package/src/lib/validators/blazor/blazor-validator.js +369 -369
  122. package/src/lib/validators/blazor/index.js +9 -9
  123. package/src/lib/validators/content/content-validator.js +287 -287
  124. package/src/lib/validators/content/index.js +7 -7
  125. package/src/lib/validators/contracts/index.js +7 -7
  126. package/src/lib/validators/css/css-validator.js +352 -352
  127. package/src/lib/validators/css/index.js +7 -7
  128. package/src/lib/validators/design-system/design-system-validator.js +231 -231
  129. package/src/lib/validators/design-system/index.js +7 -7
  130. package/src/lib/validators/nextjs/index.js +6 -6
  131. package/src/lib/validators/nextjs/next-component-validator.js +183 -183
  132. package/src/lib/validators/packages/index.js +7 -7
  133. package/src/lib/validators/packages/package-validator.js +360 -360
  134. package/src/lib/validators/shared/index.js +12 -12
  135. package/src/lib/validators/shared/issue-counter.js +18 -18
  136. package/src/lib/validators/shared/result-formatter.js +124 -124
  137. package/src/lib/validators/ui/index.js +7 -7
  138. package/src/lib/validators/ui/ui-contrast-validator.js +422 -422
  139. package/src/scripts/global-install.js +112 -58
  140. package/src/scripts/install-plugin.js +126 -126
  141. package/src/utils/claude-md-injector.js +90 -90
  142. package/src/utils/file-copier.js +200 -200
  143. package/src/utils/logger.js +32 -32
  144. package/src/utils/skills-installer.js +178 -178
  145. package/src/utils/version-checker.js +169 -175
@@ -1,254 +1,254 @@
1
- # Code Review Report — User Management Feature
2
-
3
- > Example of a well-structured Next.js code review output. Filled-in reference — not a template.
4
-
5
- **Scope:** `src/features/users/` + `src/app/(dashboard)/users/page.tsx`
6
- **Date:** 2026-02-23
7
- **Reviewer:** code-review-nextjs skill
8
-
9
- ---
10
-
11
- ## Automated Scan Results
12
-
13
- ```bash
14
- $ node scripts/scan-nextjs.mjs src/features/users/
15
-
16
- CRITICAL (1)
17
- features/users/components/UserList.tsx:1 — React hooks used (useState) without 'use client'
18
-
19
- HIGH/MEDIUM (2)
20
- features/users/components/UserList.tsx — PascalCase filename (should be user-list.tsx)
21
- features/users/components/user-form.tsx — 'use client' directive present but no interactivity detected
22
-
23
- Summary: 8 files scanned | 3 issues (1 critical, 2 high/medium)
24
- ```
25
-
26
- ---
27
-
28
- ## Findings by Severity
29
-
30
- | Severity | Count |
31
- |----------|-------|
32
- | CRITICAL | 2 |
33
- | HIGH | 3 |
34
- | MEDIUM | 2 |
35
- | LOW | 1 |
36
-
37
- ---
38
-
39
- ### [CRITICAL] Missing 'use client' on interactive component
40
-
41
- **File:** `src/features/users/components/UserList.tsx:1`
42
-
43
- **Current code:**
44
- ```tsx
45
- import { useState } from 'react';
46
-
47
- export function UserList() {
48
- const [selected, setSelected] = useState<string | null>(null);
49
- return <div onClick={() => setSelected('test')}>...</div>;
50
- }
51
- ```
52
-
53
- **Suggested fix:**
54
- ```tsx
55
- 'use client';
56
-
57
- import { useState } from 'react';
58
- // ... rest unchanged
59
- ```
60
-
61
- **Why:** React hooks (`useState`) require `'use client'`. Without it, Next.js treats this as a Server Component and the `useState` call fails at runtime.
62
-
63
- ---
64
-
65
- ### [CRITICAL] useEffect for data fetching
66
-
67
- **File:** `src/features/users/components/user-list.tsx:8`
68
-
69
- **Current code:**
70
- ```tsx
71
- 'use client';
72
- import { useEffect, useState } from 'react';
73
-
74
- export function UserList() {
75
- const [users, setUsers] = useState([]);
76
- useEffect(() => {
77
- fetch('/api/users').then(r => r.json()).then(setUsers);
78
- }, []);
79
- return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
80
- }
81
- ```
82
-
83
- **Suggested fix:**
84
- ```tsx
85
- // Option A — Server Component (no 'use client' needed)
86
- // app/(dashboard)/users/page.tsx
87
- async function getUsers() {
88
- const res = await fetch(`${process.env.API_URL}/api/users`, { next: { revalidate: 30 } });
89
- return res.json();
90
- }
91
- export default async function UsersPage() {
92
- const users = await getUsers();
93
- return <UserList initialData={users} />;
94
- }
95
-
96
- // Option B — TanStack Query (when client interactivity needed)
97
- 'use client';
98
- import { useUsers } from '@/features/users/hooks/use-users';
99
- export function UserList() {
100
- const { data: users = [], isLoading } = useUsers();
101
- if (isLoading) return <div>Loading...</div>;
102
- return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
103
- }
104
- ```
105
-
106
- **Why:** `useEffect` + `useState` for fetching: (1) doubles renders, (2) no caching, (3) no SSR, (4) no error/loading states, (5) can't be cancelled. TanStack Query or Server Components solve all five.
107
-
108
- ---
109
-
110
- ### [HIGH] PascalCase file name
111
-
112
- **File:** `src/features/users/components/UserList.tsx`
113
-
114
- **Suggested fix:** Rename to `user-list.tsx`
115
-
116
- **Why:** Linux servers are case-sensitive. `UserList.tsx` and `user-list.tsx` are different files on the server but the same on macOS/Windows, causing import failures in production.
117
-
118
- ---
119
-
120
- ### [HIGH] Default export on non-page component
121
-
122
- **File:** `src/features/users/components/user-card.tsx:3`
123
-
124
- **Current code:**
125
- ```tsx
126
- export default function UserCard({ user }: { user: User }) {
127
- ```
128
-
129
- **Suggested fix:**
130
- ```tsx
131
- export function UserCard({ user }: { user: User }) {
132
- ```
133
-
134
- **Why:** Named exports are refactor-safe — IDEs track renames automatically. Default exports are anonymous in imports (`import X from './user-card'` allows `X` to be anything).
135
-
136
- ---
137
-
138
- ### [HIGH] Type defined manually instead of deriving from Zod schema
139
-
140
- **File:** `src/features/users/types/user.types.ts:1`
141
-
142
- **Current code:**
143
- ```ts
144
- export type User = {
145
- id: string;
146
- name: string;
147
- email: string;
148
- role: 'admin' | 'user';
149
- };
150
- ```
151
-
152
- **Suggested fix:**
153
- ```ts
154
- // user.schemas.ts — single source of truth
155
- export const userSchema = z.object({
156
- id: z.string(),
157
- name: z.string(),
158
- email: z.string().email(),
159
- role: z.enum(['admin', 'user']),
160
- });
161
-
162
- // user.types.ts — derived, never written manually
163
- export type User = z.infer<typeof userSchema>;
164
- ```
165
-
166
- **Why:** Manually written types drift from API responses. `z.infer<>` ensures the TypeScript type is always in sync with the runtime validation.
167
-
168
- ---
169
-
170
- ### [MEDIUM] Deep path import instead of feature index
171
-
172
- **File:** `src/app/(dashboard)/users/page.tsx:2`
173
-
174
- **Current code:**
175
- ```tsx
176
- import { UserList } from '@/features/users/components/user-list';
177
- ```
178
-
179
- **Suggested fix:**
180
- ```tsx
181
- import { UserList } from '@/features/users';
182
- ```
183
-
184
- **Why:** Deep path imports expose internal structure. When `user-list.tsx` moves or is renamed, every consumer breaks. The feature index is the stable public API.
185
-
186
- ---
187
-
188
- ### [MEDIUM] Query key not using factory pattern
189
-
190
- **File:** `src/features/users/hooks/use-users.ts:8`
191
-
192
- **Current code:**
193
- ```ts
194
- return useQuery({
195
- queryKey: ['users'],
196
- ```
197
-
198
- **Suggested fix:**
199
- ```ts
200
- // query-keys.ts
201
- export const userKeys = {
202
- all: ['users'] as const,
203
- lists: () => [...userKeys.all, 'list'] as const,
204
- };
205
-
206
- // use-users.ts
207
- return useQuery({
208
- queryKey: userKeys.lists(),
209
- ```
210
-
211
- **Why:** Hardcoded `['users']` cannot be selectively invalidated. `queryClient.invalidateQueries({ queryKey: userKeys.lists() })` correctly invalidates only list queries, not detail queries with the same prefix.
212
-
213
- ---
214
-
215
- ### [LOW] Test uses fireEvent instead of userEvent
216
-
217
- **File:** `src/features/users/components/user-card.test.tsx:14`
218
-
219
- **Current code:**
220
- ```tsx
221
- fireEvent.click(screen.getByRole('button', { name: /edit/i }));
222
- ```
223
-
224
- **Suggested fix:**
225
- ```tsx
226
- await userEvent.click(screen.getByRole('button', { name: /edit/i }));
227
- ```
228
-
229
- **Why:** `fireEvent.click` dispatches a synthetic event. `userEvent.click` simulates the full browser interaction sequence (pointerdown, mousedown, focus, click, etc.) — closer to real user behaviour.
230
-
231
- ---
232
-
233
- ## Top Priorities
234
-
235
- 1. `UserList.tsx:1` — CRITICAL missing `'use client'` (2 min fix)
236
- 2. `user-list.tsx:8` — CRITICAL useEffect fetch → useQuery (15 min)
237
- 3. `UserList.tsx` — HIGH rename to `user-list.tsx` (2 min)
238
- 4. `user-card.tsx:3` — HIGH named export (2 min)
239
- 5. `user.types.ts:1` — HIGH derive from Zod (10 min)
240
-
241
- ---
242
-
243
- ## Passed Checks ✅
244
-
245
- - `components/ui/` files untouched
246
- - `zodResolver` correctly wired in `user-form.tsx`
247
- - `isPending` used (v5 correct — not `isLoading`)
248
- - `loading.tsx` and `error.tsx` present in `app/(dashboard)/users/`
249
- - Feature has `index.ts` re-exporting public API
250
- - Test file co-located with component
251
-
252
- ---
253
-
254
- *MORPH-SPEC by Polymorphism Tech*
1
+ # Code Review Report — User Management Feature
2
+
3
+ > Example of a well-structured Next.js code review output. Filled-in reference — not a template.
4
+
5
+ **Scope:** `src/features/users/` + `src/app/(dashboard)/users/page.tsx`
6
+ **Date:** 2026-02-23
7
+ **Reviewer:** code-review-nextjs skill
8
+
9
+ ---
10
+
11
+ ## Automated Scan Results
12
+
13
+ ```bash
14
+ $ node scripts/scan-nextjs.mjs src/features/users/
15
+
16
+ CRITICAL (1)
17
+ features/users/components/UserList.tsx:1 — React hooks used (useState) without 'use client'
18
+
19
+ HIGH/MEDIUM (2)
20
+ features/users/components/UserList.tsx — PascalCase filename (should be user-list.tsx)
21
+ features/users/components/user-form.tsx — 'use client' directive present but no interactivity detected
22
+
23
+ Summary: 8 files scanned | 3 issues (1 critical, 2 high/medium)
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Findings by Severity
29
+
30
+ | Severity | Count |
31
+ |----------|-------|
32
+ | CRITICAL | 2 |
33
+ | HIGH | 3 |
34
+ | MEDIUM | 2 |
35
+ | LOW | 1 |
36
+
37
+ ---
38
+
39
+ ### [CRITICAL] Missing 'use client' on interactive component
40
+
41
+ **File:** `src/features/users/components/UserList.tsx:1`
42
+
43
+ **Current code:**
44
+ ```tsx
45
+ import { useState } from 'react';
46
+
47
+ export function UserList() {
48
+ const [selected, setSelected] = useState<string | null>(null);
49
+ return <div onClick={() => setSelected('test')}>...</div>;
50
+ }
51
+ ```
52
+
53
+ **Suggested fix:**
54
+ ```tsx
55
+ 'use client';
56
+
57
+ import { useState } from 'react';
58
+ // ... rest unchanged
59
+ ```
60
+
61
+ **Why:** React hooks (`useState`) require `'use client'`. Without it, Next.js treats this as a Server Component and the `useState` call fails at runtime.
62
+
63
+ ---
64
+
65
+ ### [CRITICAL] useEffect for data fetching
66
+
67
+ **File:** `src/features/users/components/user-list.tsx:8`
68
+
69
+ **Current code:**
70
+ ```tsx
71
+ 'use client';
72
+ import { useEffect, useState } from 'react';
73
+
74
+ export function UserList() {
75
+ const [users, setUsers] = useState([]);
76
+ useEffect(() => {
77
+ fetch('/api/users').then(r => r.json()).then(setUsers);
78
+ }, []);
79
+ return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
80
+ }
81
+ ```
82
+
83
+ **Suggested fix:**
84
+ ```tsx
85
+ // Option A — Server Component (no 'use client' needed)
86
+ // app/(dashboard)/users/page.tsx
87
+ async function getUsers() {
88
+ const res = await fetch(`${process.env.API_URL}/api/users`, { next: { revalidate: 30 } });
89
+ return res.json();
90
+ }
91
+ export default async function UsersPage() {
92
+ const users = await getUsers();
93
+ return <UserList initialData={users} />;
94
+ }
95
+
96
+ // Option B — TanStack Query (when client interactivity needed)
97
+ 'use client';
98
+ import { useUsers } from '@/features/users/hooks/use-users';
99
+ export function UserList() {
100
+ const { data: users = [], isLoading } = useUsers();
101
+ if (isLoading) return <div>Loading...</div>;
102
+ return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
103
+ }
104
+ ```
105
+
106
+ **Why:** `useEffect` + `useState` for fetching: (1) doubles renders, (2) no caching, (3) no SSR, (4) no error/loading states, (5) can't be cancelled. TanStack Query or Server Components solve all five.
107
+
108
+ ---
109
+
110
+ ### [HIGH] PascalCase file name
111
+
112
+ **File:** `src/features/users/components/UserList.tsx`
113
+
114
+ **Suggested fix:** Rename to `user-list.tsx`
115
+
116
+ **Why:** Linux servers are case-sensitive. `UserList.tsx` and `user-list.tsx` are different files on the server but the same on macOS/Windows, causing import failures in production.
117
+
118
+ ---
119
+
120
+ ### [HIGH] Default export on non-page component
121
+
122
+ **File:** `src/features/users/components/user-card.tsx:3`
123
+
124
+ **Current code:**
125
+ ```tsx
126
+ export default function UserCard({ user }: { user: User }) {
127
+ ```
128
+
129
+ **Suggested fix:**
130
+ ```tsx
131
+ export function UserCard({ user }: { user: User }) {
132
+ ```
133
+
134
+ **Why:** Named exports are refactor-safe — IDEs track renames automatically. Default exports are anonymous in imports (`import X from './user-card'` allows `X` to be anything).
135
+
136
+ ---
137
+
138
+ ### [HIGH] Type defined manually instead of deriving from Zod schema
139
+
140
+ **File:** `src/features/users/types/user.types.ts:1`
141
+
142
+ **Current code:**
143
+ ```ts
144
+ export type User = {
145
+ id: string;
146
+ name: string;
147
+ email: string;
148
+ role: 'admin' | 'user';
149
+ };
150
+ ```
151
+
152
+ **Suggested fix:**
153
+ ```ts
154
+ // user.schemas.ts — single source of truth
155
+ export const userSchema = z.object({
156
+ id: z.string(),
157
+ name: z.string(),
158
+ email: z.string().email(),
159
+ role: z.enum(['admin', 'user']),
160
+ });
161
+
162
+ // user.types.ts — derived, never written manually
163
+ export type User = z.infer<typeof userSchema>;
164
+ ```
165
+
166
+ **Why:** Manually written types drift from API responses. `z.infer<>` ensures the TypeScript type is always in sync with the runtime validation.
167
+
168
+ ---
169
+
170
+ ### [MEDIUM] Deep path import instead of feature index
171
+
172
+ **File:** `src/app/(dashboard)/users/page.tsx:2`
173
+
174
+ **Current code:**
175
+ ```tsx
176
+ import { UserList } from '@/features/users/components/user-list';
177
+ ```
178
+
179
+ **Suggested fix:**
180
+ ```tsx
181
+ import { UserList } from '@/features/users';
182
+ ```
183
+
184
+ **Why:** Deep path imports expose internal structure. When `user-list.tsx` moves or is renamed, every consumer breaks. The feature index is the stable public API.
185
+
186
+ ---
187
+
188
+ ### [MEDIUM] Query key not using factory pattern
189
+
190
+ **File:** `src/features/users/hooks/use-users.ts:8`
191
+
192
+ **Current code:**
193
+ ```ts
194
+ return useQuery({
195
+ queryKey: ['users'],
196
+ ```
197
+
198
+ **Suggested fix:**
199
+ ```ts
200
+ // query-keys.ts
201
+ export const userKeys = {
202
+ all: ['users'] as const,
203
+ lists: () => [...userKeys.all, 'list'] as const,
204
+ };
205
+
206
+ // use-users.ts
207
+ return useQuery({
208
+ queryKey: userKeys.lists(),
209
+ ```
210
+
211
+ **Why:** Hardcoded `['users']` cannot be selectively invalidated. `queryClient.invalidateQueries({ queryKey: userKeys.lists() })` correctly invalidates only list queries, not detail queries with the same prefix.
212
+
213
+ ---
214
+
215
+ ### [LOW] Test uses fireEvent instead of userEvent
216
+
217
+ **File:** `src/features/users/components/user-card.test.tsx:14`
218
+
219
+ **Current code:**
220
+ ```tsx
221
+ fireEvent.click(screen.getByRole('button', { name: /edit/i }));
222
+ ```
223
+
224
+ **Suggested fix:**
225
+ ```tsx
226
+ await userEvent.click(screen.getByRole('button', { name: /edit/i }));
227
+ ```
228
+
229
+ **Why:** `fireEvent.click` dispatches a synthetic event. `userEvent.click` simulates the full browser interaction sequence (pointerdown, mousedown, focus, click, etc.) — closer to real user behaviour.
230
+
231
+ ---
232
+
233
+ ## Top Priorities
234
+
235
+ 1. `UserList.tsx:1` — CRITICAL missing `'use client'` (2 min fix)
236
+ 2. `user-list.tsx:8` — CRITICAL useEffect fetch → useQuery (15 min)
237
+ 3. `UserList.tsx` — HIGH rename to `user-list.tsx` (2 min)
238
+ 4. `user-card.tsx:3` — HIGH named export (2 min)
239
+ 5. `user.types.ts:1` — HIGH derive from Zod (10 min)
240
+
241
+ ---
242
+
243
+ ## Passed Checks ✅
244
+
245
+ - `components/ui/` files untouched
246
+ - `zodResolver` correctly wired in `user-form.tsx`
247
+ - `isPending` used (v5 correct — not `isLoading`)
248
+ - `loading.tsx` and `error.tsx` present in `app/(dashboard)/users/`
249
+ - Feature has `index.ts` re-exporting public API
250
+ - Test file co-located with component
251
+
252
+ ---
253
+
254
+ *MORPH-SPEC by Polymorphism Tech*
@@ -57,7 +57,7 @@ Store `stack`, `frontendPath`, `startCommand` and the detected context — all s
57
57
  ## Step 1 — Design Outputs Validation (if context includes design validation)
58
58
 
59
59
  ```bash
60
- npx morph-spec validate-feature $ARGUMENTS
60
+ morph-spec validate-feature $ARGUMENTS
61
61
  ```
62
62
 
63
63
  Verify existence and quality of the 4 mandatory outputs in `.morph/features/$ARGUMENTS/2-ui/`:
@@ -25,10 +25,10 @@ Before running any `morph-spec` command, detect how to invoke the CLI:
25
25
 
26
26
  ```bash
27
27
  # Try local first (project dependency), then global
28
- npx morph-spec --version
28
+ morph-spec --version
29
29
  ```
30
30
 
31
- - If `npx morph-spec --version` succeeds → use `npx morph-spec` as the CLI prefix for all commands.
31
+ - If `morph-spec --version` succeeds → use `morph-spec` as the CLI prefix for all commands.
32
32
  - If it fails → try `morph-spec --version` (global install). If that works → use `morph-spec`.
33
33
  - If both fail → **STOP** and show:
34
34
  ```
@@ -36,7 +36,7 @@ npx morph-spec --version
36
36
  npm install @polymorphism-tech/morph-spec
37
37
  ```
38
38
 
39
- Use the resolved CLI prefix (e.g. `npx morph-spec`) for ALL bash commands in the following steps.
39
+ Use the resolved CLI prefix (e.g. `morph-spec`) for ALL bash commands in the following steps.
40
40
 
41
41
  ---
42
42
 
@@ -78,19 +78,19 @@ Check if `.morph/` exists in the current directory.
78
78
 
79
79
  **If MISSING:**
80
80
  ```bash
81
- npx morph-spec setup-infra
81
+ morph-spec setup-infra
82
82
  ```
83
83
  Output confirms: `✓ MORPH-SPEC infrastructure installed.`
84
84
 
85
85
  **If EXISTS and argument is `refresh`:**
86
86
  Re-run setup-infra to update framework files, then continue with context/config refresh:
87
87
  ```bash
88
- npx morph-spec setup-infra
88
+ morph-spec setup-infra
89
89
  ```
90
90
 
91
91
  **If EXISTS and no argument:**
92
92
  Ask: *"MORPH already initialized. Refresh context and config? (y/n)"*
93
- If `y` → re-run `npx morph-spec setup-infra` then continue.
93
+ If `y` → re-run `morph-spec setup-infra` then continue.
94
94
  If `n` → STOP.
95
95
 
96
96
  ---
@@ -359,7 +359,7 @@ And inform the user:
359
359
  To create a new VSA project:
360
360
  dotnet new install https://github.com/polymorphism-tech/Morph_Template_VerticalSliceArchitecture
361
361
  dotnet new vsa -n MyProject
362
- cd MyProject && npx morph-spec init
362
+ cd MyProject && morph-spec init
363
363
  ```
364
364
 
365
365
  ---
@@ -374,7 +374,7 @@ For each detected integration with an available MCP:
374
374
  ```json
375
375
  "supabase": { "type": "http", "url": "https://mcp.supabase.com/mcp" }
376
376
  ```
377
- - NO → show snippet + `npx morph-spec mcp setup supabase`
377
+ - NO → show snippet + `morph-spec mcp setup supabase`
378
378
 
379
379
  **GitHub:**
380
380
  > *"Configure GitHub MCP? Requires Docker + a `GITHUB_PERSONAL_ACCESS_TOKEN`."*
@@ -386,7 +386,7 @@ For each detected integration with an available MCP:
386
386
  "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "<token>" }
387
387
  }
388
388
  ```
389
- - NO → show snippet + `npx morph-spec mcp setup github`
389
+ - NO → show snippet + `morph-spec mcp setup github`
390
390
 
391
391
  **Vercel detected** (vercel.json exists OR stack is nextjs):
392
392
  > *"Configure Vercel MCP? Uses OAuth — no credentials needed."*
@@ -394,7 +394,7 @@ For each detected integration with an available MCP:
394
394
  ```json
395
395
  "vercel": { "type": "http", "url": "https://mcp.vercel.com" }
396
396
  ```
397
- - NO → show snippet + `npx morph-spec mcp setup vercel`
397
+ - NO → show snippet + `morph-spec mcp setup vercel`
398
398
 
399
399
  Only offer Docker, Azure if explicitly detected in `.env.example`.
400
400
 
@@ -462,7 +462,7 @@ Use `AskUserQuestion` with header `"{MCP} failed"` and these options:
462
462
  After all configuration is complete, run the health check to verify everything is properly installed:
463
463
 
464
464
  ```bash
465
- npx morph-spec doctor
465
+ morph-spec doctor
466
466
  ```
467
467
 
468
468
  This validates: config.json integrity, agents.json presence, hooks installation, skills distribution, required command files, and state.json schema version. Fix any reported issues before proceeding.
@@ -95,7 +95,7 @@ Do not proceed while tests are failing. Fix failures and re-run before continuin
95
95
  ## Step 4 — Framework Validation
96
96
 
97
97
  ```bash
98
- npx morph-spec validate-feature $ARGUMENTS
98
+ morph-spec validate-feature $ARGUMENTS
99
99
  ```
100
100
 
101
101
  **🚫 BLOCK if it fails.**
@@ -251,10 +251,10 @@ Wait for both. **🚫 BLOCK if either returns unresolved CRITICAL.**
251
251
 
252
252
  ```bash
253
253
  # Save post-review checkpoint
254
- npx morph-spec checkpoint-save $ARGUMENTS --note "post-implementation review"
254
+ morph-spec checkpoint-save $ARGUMENTS --note "post-implementation review"
255
255
 
256
256
  # Generate final recap
257
- npx morph-spec generate recap $ARGUMENTS
257
+ morph-spec generate recap $ARGUMENTS
258
258
  ```
259
259
 
260
260
  ---
@@ -152,7 +152,7 @@ All outputs go in `.morph/features/{feature-name}/5-implement/`:
152
152
 
153
153
  After completion, mark the output:
154
154
  ```bash
155
- npx morph-spec state mark-output {feature-name} recap
155
+ morph-spec state mark-output {feature-name} recap
156
156
  ```
157
157
 
158
158
  **Does NOT generate:** proposal.md, spec.md, contracts.cs, tasks.md
@@ -60,13 +60,13 @@ When implementing simulation as a morph-spec task:
60
60
 
61
61
  ```bash
62
62
  # Track the simulation setup task
63
- npx morph-spec task start {feature} {task-id}
63
+ morph-spec task start {feature} {task-id}
64
64
 
65
65
  # After implementation, validate the feature
66
- npx morph-spec validate-feature {feature}
66
+ morph-spec validate-feature {feature}
67
67
 
68
68
  # Complete the task (triggers Tier-4 validators)
69
- npx morph-spec task done {feature} {task-id}
69
+ morph-spec task done {feature} {task-id}
70
70
  ```
71
71
 
72
72
  Reference the project's service lifetime patterns:
@@ -80,7 +80,7 @@ grep -r "AddSingleton\|AddScoped\|AddTransient" src/ --include="*.cs" -l
80
80
  - [ ] Validate DI: `dotnet build && dotnet run` + health check
81
81
  - [ ] Test full flow end-to-end (not just unit tests)
82
82
  - [ ] Verify simulation logs — confirm mocks are being called
83
- - [ ] Run `npx morph-spec validate-feature {feature}` to check architecture compliance
83
+ - [ ] Run `morph-spec validate-feature {feature}` to check architecture compliance
84
84
 
85
85
  ## Common Errors
86
86