@sk8metal/michi-cli 0.10.1 → 0.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 (104) hide show
  1. package/README.md +77 -847
  2. package/dist/scripts/phase-runner.js +1 -1
  3. package/dist/scripts/phase-runner.js.map +1 -1
  4. package/dist/scripts/utils/multi-repo-validator.d.ts +18 -0
  5. package/dist/scripts/utils/multi-repo-validator.d.ts.map +1 -1
  6. package/dist/scripts/utils/multi-repo-validator.js +42 -0
  7. package/dist/scripts/utils/multi-repo-validator.js.map +1 -1
  8. package/dist/scripts/utils/tasks-format-validator.js +3 -3
  9. package/dist/scripts/utils/tasks-format-validator.js.map +1 -1
  10. package/docs/README.md +20 -83
  11. package/docs/getting-started/configuration.md +379 -0
  12. package/docs/getting-started/installation.md +59 -0
  13. package/docs/getting-started/quick-start.md +76 -0
  14. package/docs/guides/ai-tools.md +311 -0
  15. package/docs/guides/atlassian-integration.md +116 -0
  16. package/docs/guides/claude-code.md +155 -0
  17. package/docs/guides/multi-repo.md +117 -0
  18. package/docs/guides/workflow.md +382 -0
  19. package/docs/reference/ai-commands.md +92 -0
  20. package/docs/reference/cli.md +756 -0
  21. package/docs/reference/environment-variables.md +192 -0
  22. package/docs/troubleshooting.md +543 -0
  23. package/package.json +1 -1
  24. package/scripts/phase-runner.ts +1 -1
  25. package/scripts/utils/__tests__/multi-repo-validator.test.ts +159 -1
  26. package/scripts/utils/multi-repo-validator.ts +50 -0
  27. package/scripts/utils/tasks-format-validator.ts +3 -3
  28. package/templates/claude/agents/e2e-first-planner/AGENT.md +1 -1
  29. package/templates/claude/agents/pr-resolver/AGENT.md +15 -3
  30. package/templates/claude/commands/michi/e2e-plan.md +1 -1
  31. package/templates/claude/commands/michi/spec-design.md +2 -2
  32. package/templates/claude/commands/michi/spec-tasks.md +156 -0
  33. package/templates/claude/commands/michi/test-planning.md +1 -1
  34. package/templates/claude/commands/michi/validate-design.md +3 -3
  35. package/templates/claude/commands/michi-multi-repo/impl-all.md +30 -1
  36. package/templates/claude/commands/michi-multi-repo/propagate-specs.md +14 -1
  37. package/templates/claude/commands/michi-multi-repo/spec-review.md +16 -2
  38. package/templates/claude-agent/agents/repo-spec-executor.md +1 -1
  39. package/templates/claude-agent/commands/michi/spec-tasks.md +117 -0
  40. package/templates/claude-agent/rules/code-size-monitor.md +26 -0
  41. package/templates/claude-agent/rules/code-size-rules.md +32 -0
  42. package/templates/codex/AGENTS.override.md +1 -1
  43. package/templates/codex/rules/README.md +2 -2
  44. package/templates/cursor/commands/michi/spec-tasks.md +117 -0
  45. package/templates/michi/cc-sdd-overrides/settings/rules/design-review-michi.md +1 -1
  46. package/docs/context.md +0 -59
  47. package/docs/michi-development/contributing/development.md +0 -341
  48. package/docs/michi-development/contributing/release.md +0 -365
  49. package/docs/michi-development/design/config-unification.md +0 -733
  50. package/docs/michi-development/design/design-config-current-state.md +0 -330
  51. package/docs/michi-development/design/design-config-implementation.md +0 -628
  52. package/docs/michi-development/design/design-config-migration.md +0 -952
  53. package/docs/michi-development/design/design-config-security.md +0 -771
  54. package/docs/michi-development/design/design-config-solution.md +0 -583
  55. package/docs/michi-development/design/design-config-testing.md +0 -892
  56. package/docs/michi-development/testing/manual-verification-flow.md +0 -871
  57. package/docs/michi-development/testing/manual-verification-other-tools.md +0 -1279
  58. package/docs/michi-development/testing/manual-verification-troubleshooting.md +0 -122
  59. package/docs/michi-development/testing/pre-publish-checklist.md +0 -560
  60. package/docs/michi-development/testing-strategy.md +0 -87
  61. package/docs/plan.md +0 -275
  62. package/docs/user-guide/getting-started/github-token-setup.md +0 -510
  63. package/docs/user-guide/getting-started/new-repository-setup.md +0 -704
  64. package/docs/user-guide/getting-started/quick-start.md +0 -212
  65. package/docs/user-guide/getting-started/setup.md +0 -819
  66. package/docs/user-guide/guides/agent-skills-integration.md +0 -222
  67. package/docs/user-guide/guides/customization.md +0 -537
  68. package/docs/user-guide/guides/internationalization.md +0 -540
  69. package/docs/user-guide/guides/migration-guide.md +0 -138
  70. package/docs/user-guide/guides/multi-project.md +0 -368
  71. package/docs/user-guide/guides/multi-repo-guide.md +0 -1590
  72. package/docs/user-guide/guides/phase-automation.md +0 -419
  73. package/docs/user-guide/guides/workflow.md +0 -574
  74. package/docs/user-guide/hands-on/README.md +0 -142
  75. package/docs/user-guide/hands-on/claude-agent-setup.md +0 -597
  76. package/docs/user-guide/hands-on/claude-setup.md +0 -452
  77. package/docs/user-guide/hands-on/cursor-setup.md +0 -353
  78. package/docs/user-guide/hands-on/troubleshooting.md +0 -964
  79. package/docs/user-guide/hands-on/verification-checklist.md +0 -439
  80. package/docs/user-guide/hands-on/workflow-walkthrough.md +0 -1078
  81. package/docs/user-guide/reference/config.md +0 -589
  82. package/docs/user-guide/reference/multi-repo-api.md +0 -771
  83. package/docs/user-guide/reference/quick-reference.md +0 -297
  84. package/docs/user-guide/reference/security-test-payloads.md +0 -50
  85. package/docs/user-guide/reference/tasks-template.md +0 -550
  86. package/docs/user-guide/release/ci-setup-java.md +0 -114
  87. package/docs/user-guide/release/ci-setup-nodejs.md +0 -94
  88. package/docs/user-guide/release/ci-setup-php.md +0 -102
  89. package/docs/user-guide/release/ci-setup-troubleshooting.md +0 -94
  90. package/docs/user-guide/release/ci-setup.md +0 -188
  91. package/docs/user-guide/release/release-flow.md +0 -476
  92. package/docs/user-guide/templates/test-specs/README.md +0 -173
  93. package/docs/user-guide/templates/test-specs/e2e-test-spec-template.md +0 -553
  94. package/docs/user-guide/templates/test-specs/integration-test-spec-template.md +0 -435
  95. package/docs/user-guide/templates/test-specs/performance-test-spec-template.md +0 -454
  96. package/docs/user-guide/templates/test-specs/security-test-spec-template.md +0 -625
  97. package/docs/user-guide/templates/test-specs/unit-test-spec-template.md +0 -328
  98. package/docs/user-guide/testing/integration-tests.md +0 -312
  99. package/docs/user-guide/testing/tdd-cycle.md +0 -349
  100. package/docs/user-guide/testing/test-execution-flow.md +0 -396
  101. package/docs/user-guide/testing/test-failure-handling.md +0 -521
  102. package/docs/user-guide/testing/test-planning-flow.md +0 -185
  103. package/docs/user-guide/testing-strategy.md +0 -185
  104. package/docs/verification-guide.md +0 -518
@@ -1,628 +0,0 @@
1
- # Michi 設定統合設計書 - 実装詳細
2
-
3
- **バージョン**: 1.0
4
- **作成日**: 2025-01-11
5
- **ステータス**: Draft
6
- **親ドキュメント**: [config-unification.md](./config-unification.md)
7
-
8
- ---
9
-
10
- ## 6. 実装詳細
11
-
12
- ### 6.1 ConfigLoader クラス設計
13
-
14
- ConfigLoaderは、複数の設定ファイルを読み込み、優先順位に従ってマージし、型安全なアクセスを提供するクラスです。
15
-
16
- **ファイルパス:** `scripts/utils/config-loader-v2.ts`
17
-
18
- **責務:**
19
- 1. 複数の設定ファイルを読み込み
20
- 2. 優先順位に従ってマージ
21
- 3. バリデーション
22
- 4. 型安全なアクセス提供
23
- 5. キャッシュによるパフォーマンス向上
24
-
25
- **クラス定義:**
26
-
27
- ```typescript
28
- import { z } from 'zod';
29
- import { existsSync, readFileSync } from 'fs';
30
- import { join } from 'path';
31
- import * as dotenv from 'dotenv';
32
-
33
- /**
34
- * 設定の読み込み元
35
- */
36
- type ConfigSource =
37
- | 'global-env' // ~/.michi/global.env
38
- | 'global-config' // ~/.michi/config.json
39
- | 'project-meta' // .kiro/project.json
40
- | 'project-config' // .michi/config.json
41
- | 'project-env'; // .env
42
-
43
- /**
44
- * 読み込まれた設定(ソース情報付き)
45
- */
46
- interface ConfigWithSource<T> {
47
- value: T;
48
- source: ConfigSource;
49
- }
50
-
51
- /**
52
- * 統合設定
53
- */
54
- interface MergedConfig {
55
- // Atlassian認証
56
- atlassian: {
57
- url: string;
58
- email: string;
59
- apiToken: string;
60
- };
61
-
62
- // GitHub設定
63
- github: {
64
- org: string; // 組織名(グローバル設定から)
65
- token: string; // アクセストークン(グローバル設定から)
66
- repository: string; // フルURL(project.jsonから)
67
- repositoryShort: string; // "org/repo" 形式(自動抽出)
68
- repositoryOrg: string; // リポジトリの組織名(自動抽出)
69
- repositoryName: string; // リポジトリ名(自動抽出)
70
- };
71
-
72
- // Confluenceスペース
73
- confluence: {
74
- spaces: {
75
- prd: string;
76
- qa: string;
77
- release: string;
78
- };
79
- // 設定
80
- pageCreationGranularity: string;
81
- pageTitleFormat?: string;
82
- hierarchy?: unknown;
83
- };
84
-
85
- // JIRA設定
86
- jira: {
87
- issueTypes: {
88
- story: string;
89
- subtask: string;
90
- };
91
- projectKeys: string; // プロジェクト固有
92
- createEpic: boolean;
93
- storyCreationGranularity: string;
94
- selectedPhases?: string[];
95
- storyPoints: string;
96
- };
97
-
98
- // ワークフロー設定
99
- workflow: {
100
- enabledPhases: string[];
101
- approvalGates?: {
102
- requirements?: string[];
103
- design?: string[];
104
- release?: string[];
105
- };
106
- };
107
-
108
- // プロジェクトメタデータ
109
- project: {
110
- id: string;
111
- name: string;
112
- language: string;
113
- jiraProjectKey: string;
114
- confluenceLabels: string[];
115
- status: string;
116
- team: string[];
117
- stakeholders: string[];
118
- repository: string;
119
- description: string;
120
- };
121
- }
122
-
123
- /**
124
- * 読み込みオプション
125
- */
126
- interface LoadOptions {
127
- projectRoot?: string; // プロジェクトルート(デフォルト: process.cwd())
128
- skipValidation?: boolean; // バリデーションをスキップ
129
- useCache?: boolean; // キャッシュを使用(デフォルト: true)
130
- }
131
-
132
- /**
133
- * 設定ローダー
134
- */
135
- export class ConfigLoader {
136
- private cache: MergedConfig | null = null;
137
- private cacheTimestamp: number = 0;
138
- private cacheTTL: number = 60000; // 1分
139
-
140
- /**
141
- * 設定を読み込んでマージ
142
- */
143
- async load(options?: LoadOptions): Promise<MergedConfig> {
144
- // キャッシュチェック
145
- if (this.cache && options?.useCache !== false) {
146
- const now = Date.now();
147
- if (now - this.cacheTimestamp < this.cacheTTL) {
148
- return this.cache;
149
- }
150
- }
151
-
152
- const projectRoot = options?.projectRoot || process.cwd();
153
-
154
- // パフォーマンス計測開始
155
- const start = performance.now();
156
-
157
- // 並列読み込み
158
- const [globalEnv, globalConfig, projectMeta, projectConfig, projectEnv] =
159
- await Promise.all([
160
- this.loadGlobalEnv(),
161
- this.loadGlobalConfig(),
162
- this.loadProjectMeta(projectRoot),
163
- this.loadProjectConfig(projectRoot),
164
- this.loadProjectEnv(projectRoot),
165
- ]);
166
-
167
- // マージ
168
- const merged = this.merge([
169
- globalEnv,
170
- globalConfig,
171
- projectMeta,
172
- projectConfig,
173
- projectEnv,
174
- ]);
175
-
176
- // リポジトリURLのパース(project.jsonから取得)
177
- if (merged.project?.repository) {
178
- const parsed = this.parseGitHubRepository(merged.project.repository);
179
- merged.github = {
180
- ...merged.github,
181
- repository: parsed.url,
182
- repositoryShort: parsed.shortForm,
183
- repositoryOrg: parsed.org,
184
- repositoryName: parsed.repo,
185
- };
186
- }
187
-
188
- // バリデーション
189
- if (!options?.skipValidation) {
190
- this.validate(merged);
191
- }
192
-
193
- // キャッシュ更新
194
- this.cache = merged;
195
- this.cacheTimestamp = Date.now();
196
-
197
- // パフォーマンス計測終了
198
- const elapsed = performance.now() - start;
199
- if (elapsed > 100) {
200
- console.warn(`⚠️ 設定の読み込みに ${elapsed.toFixed(2)}ms かかりました(目標: <100ms)`);
201
- }
202
-
203
- return merged;
204
- }
205
-
206
- /**
207
- * 設定をリロード(キャッシュをクリア)
208
- */
209
- reload(): void {
210
- this.cache = null;
211
- this.cacheTimestamp = 0;
212
- }
213
-
214
- /**
215
- * 特定の設定値を取得
216
- */
217
- get<T>(path: string): T | undefined {
218
- if (!this.cache) {
219
- throw new Error('Configuration not loaded. Call load() first.');
220
- }
221
-
222
- // ドットパスで設定値を取得
223
- return this.getValueByPath(this.cache, path);
224
- }
225
-
226
- /**
227
- * 設定値の設定元を取得
228
- */
229
- getSource(path: string): ConfigSource | undefined {
230
- // TODO: 実装
231
- // 各設定値がどのファイルから来たかを追跡する
232
- return undefined;
233
- }
234
-
235
- /**
236
- * グローバル.envを読み込み
237
- */
238
- private async loadGlobalEnv(): Promise<Partial<MergedConfig>> {
239
- const globalEnvPath = this.getGlobalEnvPath();
240
- if (!existsSync(globalEnvPath)) {
241
- return {};
242
- }
243
-
244
- const parsed = dotenv.parse(readFileSync(globalEnvPath, 'utf-8'));
245
-
246
- return {
247
- atlassian: {
248
- url: parsed.ATLASSIAN_URL || '',
249
- email: parsed.ATLASSIAN_EMAIL || '',
250
- apiToken: parsed.ATLASSIAN_API_TOKEN || '',
251
- },
252
- github: {
253
- org: parsed.GITHUB_ORG || '',
254
- token: parsed.GITHUB_TOKEN || '',
255
- // repository関連はproject.jsonから取得
256
- repository: '',
257
- repositoryShort: '',
258
- repositoryOrg: '',
259
- repositoryName: '',
260
- },
261
- confluence: {
262
- spaces: {
263
- prd: parsed.CONFLUENCE_PRD_SPACE || 'PRD',
264
- qa: parsed.CONFLUENCE_QA_SPACE || 'QA',
265
- release: parsed.CONFLUENCE_RELEASE_SPACE || 'RELEASE',
266
- },
267
- },
268
- jira: {
269
- issueTypes: {
270
- story: parsed.JIRA_ISSUE_TYPE_STORY || '',
271
- subtask: parsed.JIRA_ISSUE_TYPE_SUBTASK || '',
272
- },
273
- projectKeys: '', // プロジェクト固有
274
- },
275
- };
276
- }
277
-
278
- /**
279
- * グローバル設定を読み込み
280
- */
281
- private async loadGlobalConfig(): Promise<Partial<MergedConfig>> {
282
- const globalConfigPath = this.getGlobalConfigPath();
283
- if (!existsSync(globalConfigPath)) {
284
- return {};
285
- }
286
-
287
- const content = readFileSync(globalConfigPath, 'utf-8');
288
- const config = JSON.parse(content);
289
-
290
- // TODO: 変換処理
291
- return config;
292
- }
293
-
294
- /**
295
- * プロジェクトメタデータを読み込み
296
- */
297
- private async loadProjectMeta(projectRoot: string): Promise<Partial<MergedConfig>> {
298
- const projectMetaPath = join(projectRoot, '.kiro/project.json');
299
- if (!existsSync(projectMetaPath)) {
300
- return {};
301
- }
302
-
303
- const content = readFileSync(projectMetaPath, 'utf-8');
304
- const meta = JSON.parse(content);
305
-
306
- return {
307
- project: meta,
308
- };
309
- }
310
-
311
- /**
312
- * プロジェクト設定を読み込み
313
- */
314
- private async loadProjectConfig(projectRoot: string): Promise<Partial<MergedConfig>> {
315
- const projectConfigPath = join(projectRoot, '.michi/config.json');
316
- if (!existsSync(projectConfigPath)) {
317
- return {};
318
- }
319
-
320
- const content = readFileSync(projectConfigPath, 'utf-8');
321
- const config = JSON.parse(content);
322
-
323
- // TODO: 変換処理
324
- return config;
325
- }
326
-
327
- /**
328
- * プロジェクト.envを読み込み
329
- */
330
- private async loadProjectEnv(projectRoot: string): Promise<Partial<MergedConfig>> {
331
- const projectEnvPath = join(projectRoot, '.env');
332
- if (!existsSync(projectEnvPath)) {
333
- return {};
334
- }
335
-
336
- const parsed = dotenv.parse(readFileSync(projectEnvPath, 'utf-8'));
337
-
338
- return {
339
- jira: {
340
- projectKeys: parsed.JIRA_PROJECT_KEYS || '',
341
- },
342
- // GITHUB_REPO は削除(project.jsonのrepositoryから取得)
343
- };
344
- }
345
-
346
- /**
347
- * マージ処理
348
- */
349
- private merge(configs: Partial<MergedConfig>[]): MergedConfig {
350
- // deep merge with priority
351
- return this.deepMerge({}, ...configs) as MergedConfig;
352
- }
353
-
354
- /**
355
- * ディープマージ
356
- */
357
- private deepMerge(target: any, ...sources: any[]): any {
358
- for (const source of sources) {
359
- if (!source) continue;
360
-
361
- for (const key in source) {
362
- const targetValue = target[key];
363
- const sourceValue = source[key];
364
-
365
- if (this.isObject(sourceValue) && this.isObject(targetValue)) {
366
- target[key] = this.deepMerge(targetValue, sourceValue);
367
- } else if (sourceValue !== undefined && sourceValue !== '') {
368
- target[key] = sourceValue;
369
- }
370
- }
371
- }
372
-
373
- return target;
374
- }
375
-
376
- /**
377
- * オブジェクトチェック
378
- */
379
- private isObject(value: any): boolean {
380
- return value !== null && typeof value === 'object' && !Array.isArray(value);
381
- }
382
-
383
- /**
384
- * バリデーション
385
- */
386
- private validate(config: MergedConfig): void {
387
- try {
388
- MergedConfigSchema.parse(config);
389
- } catch (error) {
390
- if (error instanceof z.ZodError) {
391
- throw new ConfigValidationError(
392
- 'Configuration validation failed',
393
- error.issues
394
- );
395
- }
396
- throw error;
397
- }
398
- }
399
-
400
- /**
401
- * パスで値を取得
402
- */
403
- private getValueByPath(obj: any, path: string): any {
404
- const keys = path.split('.');
405
- let current = obj;
406
-
407
- for (const key of keys) {
408
- if (current === undefined || current === null) {
409
- return undefined;
410
- }
411
- current = current[key];
412
- }
413
-
414
- return current;
415
- }
416
-
417
- /**
418
- * グローバル.envのパスを取得
419
- *
420
- * 注: 後方互換性のため、旧形式(global.env)も確認する
421
- */
422
- private getGlobalEnvPath(): string {
423
- const homeDir = process.env.HOME || process.env.USERPROFILE;
424
- if (!homeDir) {
425
- throw new Error('Could not determine home directory');
426
- }
427
-
428
- const newPath = join(homeDir, '.michi', '.env');
429
- const oldPath = join(homeDir, '.michi', 'global.env');
430
-
431
- // 旧形式が存在し、新形式が存在しない場合は警告
432
- if (existsSync(oldPath) && !existsSync(newPath)) {
433
- console.warn('⚠️ 古い設定ファイルが見つかりました: ~/.michi/global.env');
434
- console.warn(' ~/.michi/.env に移行してください');
435
- console.warn(' コマンド: michi migrate config');
436
- return oldPath; // 後方互換性のため旧パスを返す
437
- }
438
-
439
- return newPath;
440
- }
441
-
442
- /**
443
- * グローバル設定のパスを取得
444
- */
445
- private getGlobalConfigPath(): string {
446
- const homeDir = process.env.HOME || process.env.USERPROFILE;
447
- if (!homeDir) {
448
- throw new Error('Could not determine home directory');
449
- }
450
- return join(homeDir, '.michi', 'config.json');
451
- }
452
-
453
- /**
454
- * GitHubリポジトリURLをパース
455
- *
456
- * @param repoUrl - GitHub リポジトリURL(HTTPS または SSH)
457
- * @returns パースされたリポジトリ情報
458
- * @throws {ConfigValidationError} 無効なURLの場合
459
- */
460
- private parseGitHubRepository(repoUrl: string): {
461
- url: string;
462
- org: string;
463
- repo: string;
464
- shortForm: string;
465
- } {
466
- // HTTPSとSSH両方のURLをサポート
467
- const httpsMatch = repoUrl.match(/github\.com\/([^/]+)\/([^/]+?)(\.git)?$/);
468
- const sshMatch = repoUrl.match(/github\.com:([^/]+)\/([^/]+?)(\.git)?$/);
469
- const match = httpsMatch || sshMatch;
470
-
471
- if (!match) {
472
- throw new ConfigValidationError(
473
- 'REPOSITORY_URL_INVALID',
474
- `Invalid GitHub repository URL: ${repoUrl}`,
475
- []
476
- );
477
- }
478
-
479
- const org = match[1];
480
- const repo = match[2];
481
-
482
- return {
483
- url: repoUrl,
484
- org,
485
- repo,
486
- shortForm: `${org}/${repo}`,
487
- };
488
- }
489
- }
490
-
491
- /**
492
- * シングルトンインスタンス
493
- */
494
- export const configLoader = new ConfigLoader();
495
-
496
- /**
497
- * ヘルパー関数(後方互換性のため)
498
- */
499
- export async function loadConfig(options?: LoadOptions): Promise<MergedConfig> {
500
- return configLoader.load(options);
501
- }
502
- ```
503
-
504
- ### 6.2 Zodスキーマ定義
505
-
506
- ```typescript
507
- // scripts/utils/config-schema.ts
508
-
509
- import { z } from 'zod';
510
-
511
- /**
512
- * MergedConfig のZodスキーマ
513
- */
514
- export const MergedConfigSchema = z.object({
515
- atlassian: z.object({
516
- url: z.string().url(),
517
- email: z.string().email(),
518
- apiToken: z.string().min(1),
519
- }),
520
-
521
- github: z.object({
522
- org: z.string().min(1),
523
- token: z.string().min(1),
524
- repository: z.string().url(),
525
- repositoryShort: z.string().min(1),
526
- repositoryOrg: z.string().min(1),
527
- repositoryName: z.string().min(1),
528
- }),
529
-
530
- confluence: z.object({
531
- spaces: z.object({
532
- prd: z.string().min(1),
533
- qa: z.string().min(1),
534
- release: z.string().min(1),
535
- }),
536
- pageCreationGranularity: z.enum(['single', 'by-section', 'by-hierarchy', 'manual']),
537
- pageTitleFormat: z.string().optional(),
538
- hierarchy: z.any().optional(),
539
- }),
540
-
541
- jira: z.object({
542
- issueTypes: z.object({
543
- story: z.string().min(1),
544
- subtask: z.string().min(1),
545
- }),
546
- projectKeys: z.string().min(1),
547
- createEpic: z.boolean(),
548
- storyCreationGranularity: z.enum(['all', 'by-phase', 'selected-phases']),
549
- selectedPhases: z.array(z.string()).optional(),
550
- storyPoints: z.enum(['auto', 'manual', 'disabled']),
551
- }),
552
-
553
- workflow: z.object({
554
- enabledPhases: z.array(z.string()).min(1),
555
- approvalGates: z.object({
556
- requirements: z.array(z.string()).optional(),
557
- design: z.array(z.string()).optional(),
558
- release: z.array(z.string()).optional(),
559
- }).optional(),
560
- }),
561
-
562
- project: z.object({
563
- id: z.string().min(1),
564
- name: z.string().min(1),
565
- language: z.enum(['ja', 'en']),
566
- jiraProjectKey: z.string().regex(/^[A-Z]{2,10}$/),
567
- confluenceLabels: z.array(z.string()),
568
- status: z.string(),
569
- team: z.array(z.string()),
570
- stakeholders: z.array(z.string()),
571
- repository: z.string().url(),
572
- description: z.string(),
573
- }),
574
- });
575
-
576
- export type MergedConfig = z.infer<typeof MergedConfigSchema>;
577
- ```
578
-
579
- ### 6.3 エラークラス定義
580
-
581
- ```typescript
582
- // scripts/utils/config-errors.ts
583
-
584
- import { z } from 'zod';
585
-
586
- /**
587
- * 設定関連のエラー基底クラス
588
- */
589
- export class ConfigError extends Error {
590
- constructor(message: string, public code: string) {
591
- super(message);
592
- this.name = 'ConfigError';
593
- }
594
- }
595
-
596
- /**
597
- * バリデーションエラー
598
- */
599
- export class ConfigValidationError extends ConfigError {
600
- constructor(message: string, public details: z.ZodIssue[]) {
601
- super(message, 'CONFIG_VALIDATION_ERROR');
602
- this.name = 'ConfigValidationError';
603
- }
604
- }
605
-
606
- /**
607
- * 必須設定が見つからない
608
- */
609
- export class ConfigNotFoundError extends ConfigError {
610
- constructor(message: string, public missingKeys: string[]) {
611
- super(message, 'CONFIG_NOT_FOUND');
612
- this.name = 'ConfigNotFoundError';
613
- }
614
- }
615
-
616
- /**
617
- * マイグレーションエラー
618
- */
619
- export class MigrationError extends ConfigError {
620
- constructor(message: string, public phase: string) {
621
- super(message, 'MIGRATION_ERROR');
622
- this.name = 'MigrationError';
623
- }
624
- }
625
- ```
626
-
627
- ---
628
-