@sk8metal/michi-cli 0.1.0 → 0.2.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 (47) hide show
  1. package/README.md +1 -0
  2. package/dist/scripts/__tests__/validate-phase.test.js +83 -0
  3. package/dist/scripts/__tests__/validate-phase.test.js.map +1 -1
  4. package/dist/scripts/config/config-schema.d.ts +14 -0
  5. package/dist/scripts/config/config-schema.d.ts.map +1 -1
  6. package/dist/scripts/config/config-schema.js +9 -0
  7. package/dist/scripts/config/config-schema.js.map +1 -1
  8. package/dist/scripts/validate-phase.d.ts.map +1 -1
  9. package/dist/scripts/validate-phase.js +18 -3
  10. package/dist/scripts/validate-phase.js.map +1 -1
  11. package/dist/src/__tests__/integration/setup/claude.test.js +82 -0
  12. package/dist/src/__tests__/integration/setup/claude.test.js.map +1 -1
  13. package/dist/src/cli.d.ts.map +1 -1
  14. package/dist/src/cli.js +1 -0
  15. package/dist/src/cli.js.map +1 -1
  16. package/dist/src/commands/setup-existing.d.ts +1 -0
  17. package/dist/src/commands/setup-existing.d.ts.map +1 -1
  18. package/dist/src/commands/setup-existing.js +33 -0
  19. package/dist/src/commands/setup-existing.js.map +1 -1
  20. package/docs/user-guide/guides/agent-skills-integration.md +217 -0
  21. package/docs/user-guide/guides/customization.md +2 -2
  22. package/docs/user-guide/guides/multi-project.md +2 -2
  23. package/docs/user-guide/guides/phase-automation.md +25 -25
  24. package/docs/user-guide/guides/workflow.md +8 -20
  25. package/docs/user-guide/reference/config.md +2 -2
  26. package/docs/user-guide/reference/tasks-template.md +2 -2
  27. package/docs/user-guide/testing/test-planning-flow.md +1 -1
  28. package/package.json +1 -1
  29. package/scripts/__tests__/validate-phase.test.ts +100 -0
  30. package/scripts/config/config-schema.ts +11 -0
  31. package/scripts/validate-phase.ts +21 -3
  32. package/templates/claude/agents/design-reviewer/AGENT.md +497 -0
  33. package/templates/claude/agents/e2e-first-planner/AGENT.md +410 -0
  34. package/templates/claude/agents/oss-license-checker/AGENT.md +265 -0
  35. package/templates/claude/agents/pr-resolver/AGENT.md +196 -0
  36. package/templates/claude/agents/stable-version-auditor/AGENT.md +279 -0
  37. package/templates/claude/commands/kiro/kiro-spec-impl.md +13 -4
  38. package/templates/claude/commands/kiro/kiro-spec-tasks.md +17 -3
  39. package/templates/claude/commands/michi/design-review.md +66 -0
  40. package/templates/claude/commands/michi/e2e-plan.md +113 -0
  41. package/templates/claude/commands/michi/license-check.md +80 -0
  42. package/templates/claude/commands/michi/pr-resolve.md +153 -0
  43. package/templates/claude/commands/michi/version-audit.md +91 -0
  44. package/templates/claude/skills/design-review/SKILL.md +648 -0
  45. package/templates/claude/skills/e2e-first-planning/SKILL.md +360 -0
  46. package/templates/claude/skills/oss-license/SKILL.md +232 -0
  47. package/templates/claude/skills/stable-version/SKILL.md +252 -0
@@ -5,6 +5,8 @@
5
5
  import { describe, it, expect, beforeEach, vi } from 'vitest';
6
6
  import { existsSync, readFileSync } from 'fs';
7
7
  import { validatePhase } from '../validate-phase.js';
8
+ import { loadConfig } from '../utils/config-loader.js';
9
+ import type { AppConfig } from '../config/config-schema.js';
8
10
 
9
11
  // fsモジュールのモック
10
12
  vi.mock('fs', () => ({
@@ -21,6 +23,17 @@ vi.mock('../utils/project-meta.js', () => ({
21
23
  })),
22
24
  }));
23
25
 
26
+ // config-loaderのモック
27
+ vi.mock('../utils/config-loader.js', () => ({
28
+ loadConfig: vi.fn(() => ({
29
+ validation: {
30
+ weekdayNotation: true,
31
+ businessDayCount: true,
32
+ weekendExclusion: true,
33
+ },
34
+ })),
35
+ }));
36
+
24
37
  describe('validatePhase', () => {
25
38
  beforeEach(() => {
26
39
  vi.clearAllMocks();
@@ -162,6 +175,93 @@ describe('validatePhase', () => {
162
175
  '⚠️ tasks.mdに曜日表記(月、火、水...)が含まれていません',
163
176
  );
164
177
  });
178
+
179
+ it('tasksフェーズ: 日本語曜日表記を受け入れる', () => {
180
+ // Arrange
181
+ vi.mocked(existsSync).mockReturnValue(true);
182
+ vi.mocked(readFileSync).mockImplementation((path) => {
183
+ if (String(path).includes('tasks.md')) {
184
+ return 'Day 1(月):\n - タスク1\nDay 2(火):\n - タスク2\n土日休み';
185
+ }
186
+ return JSON.stringify({
187
+ milestones: { design: { completed: true } },
188
+ jira: { epicKey: 'TEST-1', storyKeys: ['TEST-2'] },
189
+ });
190
+ });
191
+ vi.mocked(loadConfig).mockReturnValue({
192
+ validation: {
193
+ weekdayNotation: true,
194
+ businessDayCount: true,
195
+ weekendExclusion: true,
196
+ },
197
+ } as Partial<AppConfig> as AppConfig);
198
+
199
+ // Act
200
+ const result = validatePhase('test-feature', 'tasks');
201
+
202
+ // Assert
203
+ expect(result.warnings).not.toContain(
204
+ '⚠️ tasks.mdに曜日表記(月、火、水...)が含まれていません',
205
+ );
206
+ });
207
+
208
+ it('tasksフェーズ: 英語曜日表記を受け入れる', () => {
209
+ // Arrange
210
+ vi.mocked(existsSync).mockReturnValue(true);
211
+ vi.mocked(readFileSync).mockImplementation((path) => {
212
+ if (String(path).includes('tasks.md')) {
213
+ return 'Day 1 (Mon):\n - Task 1\nDay 2 (Tue):\n - Task 2\nWeekends excluded';
214
+ }
215
+ return JSON.stringify({
216
+ milestones: { design: { completed: true } },
217
+ jira: { epicKey: 'TEST-1', storyKeys: ['TEST-2'] },
218
+ });
219
+ });
220
+ vi.mocked(loadConfig).mockReturnValue({
221
+ validation: {
222
+ weekdayNotation: true,
223
+ businessDayCount: true,
224
+ weekendExclusion: true,
225
+ },
226
+ } as Partial<AppConfig> as AppConfig);
227
+
228
+ // Act
229
+ const result = validatePhase('test-feature', 'tasks');
230
+
231
+ // Assert
232
+ expect(result.warnings).not.toContain(
233
+ '⚠️ tasks.mdに曜日表記(月、火、水...)が含まれていません',
234
+ );
235
+ });
236
+
237
+ it('tasksフェーズ: バリデーション無効化設定を尊重する', () => {
238
+ // Arrange
239
+ vi.mocked(existsSync).mockReturnValue(true);
240
+ vi.mocked(readFileSync).mockImplementation((path) => {
241
+ if (String(path).includes('tasks.md')) {
242
+ return 'タスク一覧(曜日表記なし)'; // 営業日表記がない
243
+ }
244
+ return JSON.stringify({
245
+ milestones: { design: { completed: true } },
246
+ jira: { epicKey: 'TEST-1', storyKeys: ['TEST-2'] },
247
+ });
248
+ });
249
+ vi.mocked(loadConfig).mockReturnValue({
250
+ validation: {
251
+ weekdayNotation: false, // バリデーション無効化
252
+ businessDayCount: true,
253
+ weekendExclusion: true,
254
+ },
255
+ } as Partial<AppConfig> as AppConfig);
256
+
257
+ // Act
258
+ const result = validatePhase('test-feature', 'tasks');
259
+
260
+ // Assert
261
+ expect(result.warnings).not.toContain(
262
+ '⚠️ tasks.mdに曜日表記(月、火、水...)が含まれていません',
263
+ );
264
+ });
165
265
  });
166
266
 
167
267
  describe('エッジケース', () => {
@@ -137,6 +137,15 @@ export const WorkflowConfigSchema = z.object({
137
137
  .optional(),
138
138
  });
139
139
 
140
+ /**
141
+ * バリデーション設定スキーマ
142
+ */
143
+ export const ValidationConfigSchema = z.object({
144
+ weekdayNotation: z.boolean().default(true),
145
+ businessDayCount: z.boolean().default(true),
146
+ weekendExclusion: z.boolean().default(true),
147
+ });
148
+
140
149
  /**
141
150
  * 全体設定スキーマ
142
151
  */
@@ -144,6 +153,7 @@ export const AppConfigSchema = z.object({
144
153
  confluence: ConfluenceConfigSchema.optional(),
145
154
  jira: JiraConfigSchema.optional(),
146
155
  workflow: WorkflowConfigSchema.optional(),
156
+ validation: ValidationConfigSchema.optional(),
147
157
  });
148
158
 
149
159
  /**
@@ -166,4 +176,5 @@ export type JiraStoryPoints = z.infer<typeof JiraStoryPointsSchema>;
166
176
  export type JiraStatusMapping = z.infer<typeof JiraStatusMappingSchema>;
167
177
  export type JiraConfig = z.infer<typeof JiraConfigSchema>;
168
178
  export type WorkflowConfig = z.infer<typeof WorkflowConfigSchema>;
179
+ export type ValidationConfig = z.infer<typeof ValidationConfigSchema>;
169
180
  export type AppConfig = z.infer<typeof AppConfigSchema>;
@@ -6,6 +6,7 @@
6
6
  import { existsSync, readFileSync } from 'fs';
7
7
  import { join } from 'path';
8
8
  import { validateFeatureName } from './utils/feature-name-validator.js';
9
+ import { loadConfig } from './utils/config-loader.js';
9
10
 
10
11
  type Phase =
11
12
  | 'requirements'
@@ -159,11 +160,28 @@ function validateTasks(feature: string): ValidationResult {
159
160
  if (!existsSync(tasksPath)) {
160
161
  errors.push('❌ tasks.md が作成されていません');
161
162
  } else {
162
- // 営業日表記チェック
163
+ // 設定読み込み(バリデーション設定)
164
+ let config;
165
+ try {
166
+ config = loadConfig();
167
+ } catch {
168
+ // 設定ファイルの読み込みエラーは無視(デフォルト設定を使用)
169
+ config = { validation: { weekdayNotation: true } };
170
+ }
171
+
172
+ // 営業日表記チェック(設定で無効化可能)
163
173
  const tasksContent = readFileSync(tasksPath, 'utf-8');
164
- if (!tasksContent.includes('(月)') && !tasksContent.includes('(火)')) {
165
- warnings.push('⚠️ tasks.mdに曜日表記(月、火、水...)が含まれていません');
174
+
175
+ if (config.validation?.weekdayNotation !== false) {
176
+ // 日本語または英語の曜日表記をチェック
177
+ const hasJapaneseWeekday = ['(月)', '(火)'].some(p => tasksContent.includes(p));
178
+ const hasEnglishWeekday = ['(Mon)', '(Tue)'].some(p => tasksContent.includes(p));
179
+
180
+ if (!hasJapaneseWeekday && !hasEnglishWeekday) {
181
+ warnings.push('⚠️ tasks.mdに曜日表記(月、火、水...)が含まれていません');
182
+ }
166
183
  }
184
+
167
185
  if (!tasksContent.includes('Day 1') && !tasksContent.includes('Day1')) {
168
186
  warnings.push('⚠️ tasks.mdに営業日カウント(Day 1, Day 2...)が含まれていません');
169
187
  }
@@ -0,0 +1,497 @@
1
+ ---
2
+ name: design-reviewer
3
+ description: |
4
+ UIデザインを自動レビューする実行エージェント。
5
+ Playwright MCPでアクセシビリティ、レスポンシブ、パフォーマンスを分析。
6
+ CSS、React、Vue、HTML、Tailwindの変更時に PROACTIVELY 使用してください。
7
+ allowed-tools: Bash, Read, Grep, Glob
8
+ ---
9
+
10
+ # Design Reviewer Agent
11
+
12
+ ## 目的
13
+
14
+ WebページのUIデザインを自動的にレビューし、アクセシビリティ、レスポンシブデザイン、UXパターン、パフォーマンスの観点から改善提案を行う。
15
+
16
+ ## 前提条件
17
+
18
+ - **Playwright MCP**: ブラウザ自動化のために必要
19
+ - インストール確認: Claude Codeの設定で `mcp__playwright__*` ツールが利用可能
20
+ - **レビュー対象のURL**: ローカル開発サーバーまたは公開URL
21
+ - **ブラウザ**: Chromium(Playwright MCPが自動管理)
22
+
23
+ ## 参照すべきスキル
24
+
25
+ 実行前に必ず `.claude/skills/design-review/SKILL.md` を確認し、そのガイドラインに従ってデザインレビューを実施してください。
26
+
27
+ ## 実行フロー
28
+
29
+ ### Step 1: レビュー対象の確認
30
+
31
+ ```bash
32
+ # ローカル開発サーバーの確認
33
+ echo "=== Development Server Check ===="
34
+ if lsof -i :3000 > /dev/null 2>&1; then
35
+ echo "✓ Server running on http://localhost:3000"
36
+ elif lsof -i :8080 > /dev/null 2>&1; then
37
+ echo "✓ Server running on http://localhost:8080"
38
+ else
39
+ echo "⚠ No local server detected"
40
+ fi
41
+
42
+ # package.jsonからdevコマンド確認
43
+ if [ -f "package.json" ]; then
44
+ echo "=== Available dev commands ===="
45
+ cat package.json | grep -A 5 '"scripts"'
46
+ fi
47
+ ```
48
+
49
+ **ユーザー確認事項:**
50
+ - レビュー対象のURL(例: `http://localhost:3000`)
51
+ - レビュー対象のページ(例: `/`, `/login`, `/dashboard`)
52
+ - 特定のコンポーネント(例: ヘッダー、フォーム、モーダル)
53
+
54
+ ### Step 2: Playwright MCP でページアクセス
55
+
56
+ #### ページナビゲーション
57
+
58
+ 使用ツール: `mcp__playwright__browser_navigate`
59
+
60
+ ```
61
+ URL: http://localhost:3000
62
+ ```
63
+
64
+ #### ページスナップショット取得
65
+
66
+ 使用ツール: `mcp__playwright__browser_snapshot`
67
+
68
+ このツールは、以下の情報を返します:
69
+ - ページのアクセシビリティツリー
70
+ - インタラクティブ要素のリスト
71
+ - テキストコンテンツ
72
+ - フォーム要素
73
+ - リンク一覧
74
+
75
+ ### Step 3: レスポンシブデザインのチェック
76
+
77
+ #### 各ブレークポイントでの確認
78
+
79
+ 使用ツール: `mcp__playwright__browser_resize`
80
+
81
+ **チェック対象:**
82
+
83
+ 1. **Mobile(375x667)**
84
+ ```
85
+ width: 375
86
+ height: 667
87
+ ```
88
+ - 横スクロールが発生しないか
89
+ - タッチターゲットが44x44px以上か
90
+ - フォントサイズが読みやすいか(最小16px推奨)
91
+
92
+ 2. **Tablet(768x1024)**
93
+ ```
94
+ width: 768
95
+ height: 1024
96
+ ```
97
+ - レイアウトが適切に変化するか
98
+ - 画像が適切にリサイズされるか
99
+
100
+ 3. **Desktop(1280x800)**
101
+ ```
102
+ width: 1280
103
+ height: 800
104
+ ```
105
+ - コンテンツが中央に配置されているか
106
+ - 最大幅が適切か(推奨: 1200-1400px)
107
+
108
+ #### スクリーンショット取得
109
+
110
+ 使用ツール: `mcp__playwright__browser_take_screenshot`
111
+
112
+ ```
113
+ filename: docs/tmp/review-mobile.png
114
+ ```
115
+
116
+ 各ブレークポイントでスクリーンショットを取得し、視覚的な問題を確認。
117
+
118
+ ### Step 4: アクセシビリティ分析
119
+
120
+ #### スナップショットからの分析
121
+
122
+ **チェック項目:**
123
+
124
+ 1. **セマンティックHTML**
125
+ - `<header>`, `<nav>`, `<main>`, `<footer>` が使用されているか
126
+ - 見出し階層が適切か(h1 → h2 → h3)
127
+ - リストが `<ul>`, `<ol>` で構造化されているか
128
+
129
+ 2. **フォームのラベル**
130
+ - すべての `<input>` に対応する `<label>` があるか
131
+ - `aria-label` または `aria-labelledby` が適切に使用されているか
132
+
133
+ 3. **インタラクティブ要素**
134
+ - ボタンが `<button>` または `role="button"` を使用しているか
135
+ - リンクが `<a href="...">` を使用しているか
136
+ - カスタム要素に適切な `role` があるか
137
+
138
+ 4. **ARIA属性**
139
+ - `aria-hidden="true"` が適切に使用されているか
140
+ - `aria-live` がステータスメッセージに使用されているか
141
+ - `aria-modal="true"` がモーダルに使用されているか
142
+
143
+ #### ブラウザのアクセシビリティチェック
144
+
145
+ 使用ツール: `mcp__playwright__browser_evaluate`
146
+
147
+ ```javascript
148
+ // Lighthouse のアクセシビリティチェックを実行
149
+ () => {
150
+ // axe-core を実行(ページに注入されている場合)
151
+ if (typeof axe !== 'undefined') {
152
+ return axe.run().then(results => ({
153
+ violations: results.violations.length,
154
+ passes: results.passes.length,
155
+ incomplete: results.incomplete.length
156
+ }));
157
+ }
158
+
159
+ // 基本的なチェック
160
+ const issues = [];
161
+
162
+ // 画像のalt属性チェック
163
+ document.querySelectorAll('img:not([alt])').forEach(img => {
164
+ issues.push({
165
+ type: 'missing-alt',
166
+ element: img.outerHTML.substring(0, 100)
167
+ });
168
+ });
169
+
170
+ // ボタンのラベルチェック
171
+ document.querySelectorAll('button:empty, button:not([aria-label])').forEach(btn => {
172
+ if (!btn.textContent.trim() && !btn.getAttribute('aria-label')) {
173
+ issues.push({
174
+ type: 'unlabeled-button',
175
+ element: btn.outerHTML.substring(0, 100)
176
+ });
177
+ }
178
+ });
179
+
180
+ return { issues };
181
+ }
182
+ ```
183
+
184
+ ### Step 5: コントラスト比チェック
185
+
186
+ #### テキストとボタンのコントラスト確認
187
+
188
+ 使用ツール: `mcp__playwright__browser_evaluate`
189
+
190
+ ```javascript
191
+ (element) => {
192
+ const style = window.getComputedStyle(element);
193
+ const color = style.color;
194
+ const backgroundColor = style.backgroundColor;
195
+
196
+ // RGB値を抽出
197
+ const parseRGB = (rgbString) => {
198
+ const match = rgbString.match(/\d+/g);
199
+ return match ? match.map(Number) : [255, 255, 255];
200
+ };
201
+
202
+ const [r1, g1, b1] = parseRGB(color);
203
+ const [r2, g2, b2] = parseRGB(backgroundColor);
204
+
205
+ // 相対輝度計算
206
+ const getLuminance = (r, g, b) => {
207
+ const [rs, gs, bs] = [r, g, b].map(c => {
208
+ c = c / 255;
209
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
210
+ });
211
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
212
+ };
213
+
214
+ const l1 = getLuminance(r1, g1, b1);
215
+ const l2 = getLuminance(r2, g2, b2);
216
+
217
+ // コントラスト比計算
218
+ const contrastRatio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
219
+
220
+ return {
221
+ color,
222
+ backgroundColor,
223
+ contrastRatio: contrastRatio.toFixed(2),
224
+ passes_AA: contrastRatio >= 4.5,
225
+ passes_AAA: contrastRatio >= 7
226
+ };
227
+ }
228
+ ```
229
+
230
+ ### Step 6: パフォーマンス分析
231
+
232
+ #### Core Web Vitals の確認
233
+
234
+ 使用ツール: `mcp__playwright__browser_evaluate`
235
+
236
+ ```javascript
237
+ () => {
238
+ return new Promise((resolve) => {
239
+ // Performance Observer で LCP を取得
240
+ const lcpObserver = new PerformanceObserver((list) => {
241
+ const entries = list.getEntries();
242
+ const lastEntry = entries[entries.length - 1];
243
+ lcpObserver.disconnect();
244
+
245
+ // CLS を取得
246
+ let clsValue = 0;
247
+ const clsObserver = new PerformanceObserver((list) => {
248
+ for (const entry of list.getEntries()) {
249
+ if (!entry.hadRecentInput) {
250
+ clsValue += entry.value;
251
+ }
252
+ }
253
+ });
254
+ clsObserver.observe({ type: 'layout-shift', buffered: true });
255
+
256
+ // FID はユーザー操作が必要なので省略
257
+
258
+ setTimeout(() => {
259
+ clsObserver.disconnect();
260
+ resolve({
261
+ lcp: lastEntry.renderTime || lastEntry.loadTime,
262
+ cls: clsValue,
263
+ // その他のメトリクス
264
+ domContentLoaded: performance.timing.domContentLoadedEventEnd - performance.timing.navigationStart,
265
+ loadComplete: performance.timing.loadEventEnd - performance.timing.navigationStart
266
+ });
267
+ }, 3000);
268
+ });
269
+
270
+ lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
271
+ });
272
+ }
273
+ ```
274
+
275
+ #### リソースサイズの確認
276
+
277
+ 使用ツール: `mcp__playwright__browser_network_requests`
278
+
279
+ このツールで以下を確認:
280
+ - 画像サイズが最適化されているか(推奨: WebP形式、100KB以下)
281
+ - JavaScriptバンドルサイズ(推奨: 200KB以下)
282
+ - CSSファイルサイズ(推奨: 50KB以下)
283
+ - 外部リソースの数(推奨: 最小限)
284
+
285
+ ### Step 7: レビューレポート生成
286
+
287
+ #### レポート出力
288
+
289
+ ```bash
290
+ # レポートを docs/tmp/ に出力
291
+ mkdir -p docs/tmp
292
+ cat > docs/tmp/design-review-report.md <<'EOF'
293
+ # デザインレビューレポート
294
+
295
+ ## サマリー
296
+ - レビュー日時: $(date '+%Y-%m-%d %H:%M:%S')
297
+ - レビューURL: http://localhost:3000
298
+ - 総合評価: [自動生成]
299
+
300
+ ## 1. アクセシビリティ(評価: X/10)
301
+
302
+ ### Critical(即時対応)
303
+ [自動生成された重大な問題]
304
+
305
+ ### Warning(対応推奨)
306
+ [自動生成された警告]
307
+
308
+ ### Info(改善提案)
309
+ [自動生成された改善提案]
310
+
311
+ ## 2. レスポンシブデザイン(評価: X/10)
312
+
313
+ ### Mobile (375px)
314
+ - [自動生成されたチェック結果]
315
+
316
+ ### Tablet (768px)
317
+ - [自動生成されたチェック結果]
318
+
319
+ ### Desktop (1280px)
320
+ - [自動生成されたチェック結果]
321
+
322
+ ## 3. UXパターン(評価: X/10)
323
+
324
+ [自動生成されたUX評価]
325
+
326
+ ## 4. パフォーマンス(評価: X/10)
327
+
328
+ ### Core Web Vitals
329
+ - LCP: [X]s
330
+ - CLS: [X]
331
+ - DOM Content Loaded: [X]ms
332
+ - Load Complete: [X]ms
333
+
334
+ ### リソースサイズ
335
+ - 画像: [X]KB
336
+ - JavaScript: [X]KB
337
+ - CSS: [X]KB
338
+
339
+ ## 推奨アクション
340
+
341
+ ### 優先度1(即時対応)
342
+ [自動生成されたアクション]
343
+
344
+ ### 優先度2(1週間以内)
345
+ [自動生成されたアクション]
346
+
347
+ ### 優先度3(任意)
348
+ [自動生成されたアクション]
349
+
350
+ ## スクリーンショット
351
+
352
+ - Mobile: docs/tmp/review-mobile.png
353
+ - Tablet: docs/tmp/review-tablet.png
354
+ - Desktop: docs/tmp/review-desktop.png
355
+ EOF
356
+
357
+ echo "✅ レビューレポートを docs/tmp/design-review-report.md に出力しました"
358
+ ```
359
+
360
+ ## レビュー例
361
+
362
+ ### 例1: ログインフォームのレビュー
363
+
364
+ **URL**: `http://localhost:3000/login`
365
+
366
+ **実行手順:**
367
+ 1. ページナビゲーション: `/login`
368
+ 2. スナップショット取得
369
+ 3. アクセシビリティチェック:
370
+ - ✅ `<label for="email">` が存在
371
+ - ❌ パスワードフィールドに `autocomplete="current-password"` がない
372
+ - ❌ エラーメッセージに `role="alert"` がない
373
+ 4. レスポンシブチェック(375px, 768px, 1280px)
374
+ 5. コントラスト比チェック:
375
+ - ❌ ボタンのコントラスト比が3.2:1(推奨: 4.5:1以上)
376
+
377
+ **レポート出力:**
378
+ ```markdown
379
+ ## アクセシビリティ
380
+
381
+ ### Warning
382
+ - **autocomplete属性不足**: パスワードフィールドに `autocomplete="current-password"` を追加してください
383
+ - **エラーメッセージの通知不足**: `<span role="alert">` を使用してエラーをスクリーンリーダーに通知してください
384
+
385
+ ### Critical
386
+ - **コントラスト不足**: ログインボタンのコントラスト比が3.2:1です。WCAG AA基準(4.5:1)を満たすため、色を調整してください。
387
+ - 現在: `color: #666` on `background: #fff`
388
+ - 推奨: `color: #333` on `background: #fff`(コントラスト比: 12.6:1)
389
+ ```
390
+
391
+ ### 例2: ダッシュボードのレビュー
392
+
393
+ **URL**: `http://localhost:3000/dashboard`
394
+
395
+ **実行手順:**
396
+ 1. ページナビゲーション: `/dashboard`
397
+ 2. パフォーマンス分析:
398
+ - LCP: 2.8s(改善が必要)
399
+ - CLS: 0.15(改善が必要)
400
+ 3. リソース確認:
401
+ - ❌ 画像 `hero.jpg` が2.5MB(推奨: 300KB以下)
402
+ - ❌ JavaScriptバンドルが1.2MB(推奨: 200KB以下)
403
+ 4. レスポンシブチェック:
404
+ - ❌ Mobile (375px) で横スクロール発生
405
+
406
+ **レポート出力:**
407
+ ```markdown
408
+ ## パフォーマンス
409
+
410
+ ### Critical
411
+ - **LCP遅延**: Hero画像 (2.5MB) が最適化されていません
412
+ - 推奨: WebP形式 (300KB) に変換
413
+ - 推奨: `loading="eager"` と `fetchpriority="high"` を設定
414
+
415
+ - **JavaScriptバンドル過大**: 1.2MB のバンドルがパフォーマンスに影響
416
+ - 推奨: Code Splitting を実装
417
+ - 推奨: Tree Shaking を有効化
418
+
419
+ ## レスポンシブデザイン
420
+
421
+ ### Critical
422
+ - **横スクロール発生**: Mobile (375px) で横スクロールが発生しています
423
+ - 原因: `.container { width: 400px }`
424
+ - 推奨: `max-width: 100%` に変更
425
+ ```
426
+
427
+ ## 安全性ルール
428
+
429
+ ### 情報提供のみ
430
+
431
+ - ✅ デザイン問題の検出と報告
432
+ - ✅ 改善提案の提示
433
+ - ✅ レポート生成
434
+ - ❌ **自動コード修正は行わない**
435
+ - ❌ **ユーザー確認なしでのスタイル変更は行わない**
436
+
437
+ ### 必須確認ケース
438
+
439
+ 1. **レビュー実施前**: URLとレビュー対象を確認
440
+ 2. **Critical問題発見時**: 即座にユーザーに報告
441
+ 3. **パフォーマンス問題**: 具体的な改善案を提示
442
+
443
+ ### 禁止事項
444
+
445
+ - ❌ ユーザー確認なしでのCSSファイル変更
446
+ - ❌ ユーザー確認なしでのHTML構造変更
447
+ - ❌ 本番環境での直接テスト(ローカル環境のみ)
448
+
449
+ ### 推奨パターン
450
+
451
+ ```
452
+ AIエージェント:
453
+ 「デザインレビューを実施しました:
454
+
455
+ ## サマリー
456
+ - アクセシビリティ: 7/10
457
+ - レスポンシブ: 6/10
458
+ - UX: 8/10
459
+ - パフォーマンス: 5/10
460
+
461
+ ## Critical(3件)
462
+ 1. コントラスト不足: ボタンが3.2:1(推奨: 4.5:1)
463
+ 2. 横スクロール: Mobile (375px) で発生
464
+ 3. LCP遅延: 2.8s(推奨: 2.5s以下)
465
+
466
+ 詳細レポート: docs/tmp/design-review-report.md
467
+
468
+ 次のアクション:
469
+ A) Critical問題を修正する
470
+ B) 詳細レポートを確認する
471
+ C) 別のページをレビューする
472
+
473
+ どの対応を希望しますか?」
474
+ ```
475
+
476
+ ## Playwright MCPツール活用例
477
+
478
+ ### ツール一覧
479
+
480
+ | ツール | 用途 |
481
+ |--------|------|
482
+ | `browser_navigate` | ページへの移動 |
483
+ | `browser_snapshot` | アクセシビリティツリー取得 |
484
+ | `browser_resize` | ブレークポイント変更 |
485
+ | `browser_take_screenshot` | スクリーンショット取得 |
486
+ | `browser_evaluate` | JavaScript実行 |
487
+ | `browser_network_requests` | ネットワーク分析 |
488
+ | `browser_click` | 要素クリック(インタラクション分析用) |
489
+ | `browser_hover` | ホバー状態確認 |
490
+
491
+ ## 参考資料
492
+
493
+ - [WCAG 2.1 ガイドライン](https://www.w3.org/WAI/WCAG21/quickref/)
494
+ - [Lighthouse](https://developers.google.com/web/tools/lighthouse)
495
+ - [axe DevTools](https://www.deque.com/axe/devtools/)
496
+ - [Web Vitals](https://web.dev/vitals/)
497
+ - [Playwright Documentation](https://playwright.dev/)