@sk8metal/michi-cli 0.2.1 → 0.4.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 (172) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/scripts/config-global.d.ts +10 -0
  3. package/dist/scripts/config-global.d.ts.map +1 -0
  4. package/dist/scripts/config-global.js +111 -0
  5. package/dist/scripts/config-global.js.map +1 -0
  6. package/dist/scripts/confluence-sync.d.ts +22 -4
  7. package/dist/scripts/confluence-sync.d.ts.map +1 -1
  8. package/dist/scripts/confluence-sync.js +22 -12
  9. package/dist/scripts/confluence-sync.js.map +1 -1
  10. package/dist/scripts/jira-sync.d.ts.map +1 -1
  11. package/dist/scripts/jira-sync.js +201 -167
  12. package/dist/scripts/jira-sync.js.map +1 -1
  13. package/dist/scripts/list-projects.js.map +1 -1
  14. package/dist/scripts/multi-project-estimate.js.map +1 -1
  15. package/dist/scripts/phase-runner.d.ts +1 -1
  16. package/dist/scripts/phase-runner.d.ts.map +1 -1
  17. package/dist/scripts/phase-runner.js +295 -522
  18. package/dist/scripts/phase-runner.js.map +1 -1
  19. package/dist/scripts/pre-flight-check.d.ts.map +1 -1
  20. package/dist/scripts/pre-flight-check.js +10 -6
  21. package/dist/scripts/pre-flight-check.js.map +1 -1
  22. package/dist/scripts/resource-dashboard.js.map +1 -1
  23. package/dist/scripts/spec-impl-workflow.js +1 -1
  24. package/dist/scripts/spec-impl-workflow.js.map +1 -1
  25. package/dist/scripts/template/renderer.d.ts +1 -1
  26. package/dist/scripts/template/renderer.d.ts.map +1 -1
  27. package/dist/scripts/test-interactive.d.ts.map +1 -1
  28. package/dist/scripts/test-interactive.js +0 -15
  29. package/dist/scripts/test-interactive.js.map +1 -1
  30. package/dist/scripts/test-new-features.js +6 -3
  31. package/dist/scripts/test-new-features.js.map +1 -1
  32. package/dist/scripts/test-spec-generator.d.ts.map +1 -1
  33. package/dist/scripts/test-spec-generator.js +1 -2
  34. package/dist/scripts/test-spec-generator.js.map +1 -1
  35. package/dist/scripts/utils/config-loader.d.ts +7 -2
  36. package/dist/scripts/utils/config-loader.d.ts.map +1 -1
  37. package/dist/scripts/utils/config-loader.js +79 -8
  38. package/dist/scripts/utils/config-loader.js.map +1 -1
  39. package/dist/scripts/utils/config-sections.d.ts +54 -0
  40. package/dist/scripts/utils/config-sections.d.ts.map +1 -0
  41. package/dist/scripts/utils/config-sections.js +178 -0
  42. package/dist/scripts/utils/config-sections.js.map +1 -0
  43. package/dist/scripts/utils/config-validator.d.ts +4 -0
  44. package/dist/scripts/utils/config-validator.d.ts.map +1 -1
  45. package/dist/scripts/utils/config-validator.js +57 -1
  46. package/dist/scripts/utils/config-validator.js.map +1 -1
  47. package/dist/scripts/utils/confluence-approval.d.ts.map +1 -1
  48. package/dist/scripts/utils/confluence-approval.js +5 -3
  49. package/dist/scripts/utils/confluence-approval.js.map +1 -1
  50. package/dist/scripts/utils/confluence-hierarchy.d.ts.map +1 -1
  51. package/dist/scripts/utils/confluence-hierarchy.js.map +1 -1
  52. package/dist/scripts/utils/interactive-helpers.d.ts +32 -0
  53. package/dist/scripts/utils/interactive-helpers.d.ts.map +1 -0
  54. package/dist/scripts/utils/interactive-helpers.js +92 -0
  55. package/dist/scripts/utils/interactive-helpers.js.map +1 -0
  56. package/dist/scripts/utils/jira-issue-type-fetcher.d.ts.map +1 -1
  57. package/dist/scripts/utils/jira-issue-type-fetcher.js +27 -18
  58. package/dist/scripts/utils/jira-issue-type-fetcher.js.map +1 -1
  59. package/dist/scripts/utils/release-notes-generator.d.ts.map +1 -1
  60. package/dist/scripts/utils/release-notes-generator.js +2 -1
  61. package/dist/scripts/utils/release-notes-generator.js.map +1 -1
  62. package/dist/scripts/utils/spec-updater.d.ts +19 -0
  63. package/dist/scripts/utils/spec-updater.d.ts.map +1 -1
  64. package/dist/scripts/utils/spec-updater.js.map +1 -1
  65. package/dist/scripts/utils/tasks-converter.d.ts.map +1 -1
  66. package/dist/scripts/utils/tasks-converter.js +2 -2
  67. package/dist/scripts/utils/tasks-converter.js.map +1 -1
  68. package/dist/scripts/utils/tasks-format-validator.d.ts.map +1 -1
  69. package/dist/scripts/utils/tasks-format-validator.js +0 -12
  70. package/dist/scripts/utils/tasks-format-validator.js.map +1 -1
  71. package/dist/scripts/utils/test-runner.d.ts.map +1 -1
  72. package/dist/scripts/utils/test-runner.js +3 -2
  73. package/dist/scripts/utils/test-runner.js.map +1 -1
  74. package/dist/scripts/validate-phase.d.ts +1 -1
  75. package/dist/scripts/validate-phase.d.ts.map +1 -1
  76. package/dist/scripts/validate-phase.js +12 -62
  77. package/dist/scripts/validate-phase.js.map +1 -1
  78. package/dist/scripts/workflow-orchestrator.d.ts.map +1 -1
  79. package/dist/scripts/workflow-orchestrator.js +11 -16
  80. package/dist/scripts/workflow-orchestrator.js.map +1 -1
  81. package/dist/src/__tests__/integration/setup/claude.test.js +8 -8
  82. package/dist/src/__tests__/integration/setup/claude.test.js.map +1 -1
  83. package/dist/src/__tests__/integration/setup/init.test.d.ts +5 -0
  84. package/dist/src/__tests__/integration/setup/init.test.d.ts.map +1 -0
  85. package/dist/src/__tests__/integration/setup/init.test.js +352 -0
  86. package/dist/src/__tests__/integration/setup/init.test.js.map +1 -0
  87. package/dist/src/cli.d.ts.map +1 -1
  88. package/dist/src/cli.js +29 -21
  89. package/dist/src/cli.js.map +1 -1
  90. package/dist/src/commands/init.d.ts +28 -0
  91. package/dist/src/commands/init.d.ts.map +1 -0
  92. package/dist/src/commands/init.js +490 -0
  93. package/dist/src/commands/init.js.map +1 -0
  94. package/dist/src/commands/setup-existing.d.ts +1 -1
  95. package/dist/src/commands/setup-existing.d.ts.map +1 -1
  96. package/dist/src/commands/setup-existing.js +49 -3
  97. package/dist/src/commands/setup-existing.js.map +1 -1
  98. package/docs/user-guide/getting-started/new-repository-setup.md +1 -1
  99. package/docs/user-guide/getting-started/setup.md +33 -5
  100. package/docs/user-guide/guides/agent-skills-integration.md +16 -11
  101. package/docs/user-guide/guides/customization.md +64 -11
  102. package/docs/user-guide/guides/workflow.md +35 -21
  103. package/docs/user-guide/hands-on/claude-agent-setup.md +192 -50
  104. package/docs/user-guide/hands-on/claude-setup.md +63 -9
  105. package/docs/user-guide/hands-on/cursor-setup.md +9 -8
  106. package/docs/user-guide/hands-on/verification-checklist.md +4 -3
  107. package/docs/user-guide/hands-on/workflow-walkthrough.md +3 -3
  108. package/docs/user-guide/reference/config.md +30 -5
  109. package/docs/user-guide/reference/quick-reference.md +70 -74
  110. package/docs/user-guide/testing/test-planning-flow.md +4 -0
  111. package/package.json +2 -4
  112. package/scripts/config-global.ts +160 -0
  113. package/scripts/confluence-sync.ts +91 -27
  114. package/scripts/jira-sync.ts +284 -218
  115. package/scripts/list-projects.ts +2 -2
  116. package/scripts/multi-project-estimate.ts +3 -3
  117. package/scripts/phase-runner.ts +391 -594
  118. package/scripts/pre-flight-check.ts +20 -9
  119. package/scripts/pre-publish-check.sh +3 -34
  120. package/scripts/resource-dashboard.ts +4 -4
  121. package/scripts/spec-impl-workflow.ts +1 -1
  122. package/scripts/template/renderer.ts +1 -1
  123. package/scripts/test-interactive.ts +0 -19
  124. package/scripts/test-new-features.ts +10 -7
  125. package/scripts/test-npm-package.sh +3 -34
  126. package/scripts/test-spec-generator.ts +3 -7
  127. package/scripts/utils/config-loader.ts +107 -26
  128. package/scripts/utils/config-sections.ts +316 -0
  129. package/scripts/utils/config-validator.ts +66 -1
  130. package/scripts/utils/confluence-approval.ts +8 -6
  131. package/scripts/utils/confluence-hierarchy.ts +27 -27
  132. package/scripts/utils/interactive-helpers.ts +135 -0
  133. package/scripts/utils/jira-issue-type-fetcher.ts +29 -21
  134. package/scripts/utils/release-notes-generator.ts +3 -2
  135. package/scripts/utils/spec-updater.ts +37 -15
  136. package/scripts/utils/tasks-converter.ts +4 -6
  137. package/scripts/utils/tasks-format-validator.ts +0 -13
  138. package/scripts/utils/test-runner.ts +4 -3
  139. package/scripts/validate-phase.ts +21 -80
  140. package/scripts/workflow-orchestrator.ts +16 -25
  141. package/templates/claude/commands/kiro/kiro-spec-impl.md +4 -0
  142. package/templates/claude/commands/kiro/kiro-spec-tasks.md +3 -1
  143. package/templates/claude/commands/michi/confluence-sync.md +8 -2
  144. package/templates/claude/commands/michi/design-review.md +4 -0
  145. package/templates/claude/commands/michi/e2e-plan.md +4 -0
  146. package/templates/claude/commands/michi/license-check.md +4 -0
  147. package/templates/claude/commands/michi/pr-resolve.md +4 -0
  148. package/templates/claude/commands/michi/project-switch.md +8 -2
  149. package/templates/claude/commands/michi/spec-design.md +78 -0
  150. package/templates/claude/commands/michi/spec-impl.md +716 -0
  151. package/templates/claude/commands/michi/test-planning.md +174 -0
  152. package/templates/claude/commands/michi/validate-design.md +58 -0
  153. package/templates/claude/commands/michi/version-audit.md +4 -0
  154. package/templates/michi/cc-sdd-overrides/README.md +58 -0
  155. package/templates/michi/cc-sdd-overrides/settings/rules/design-review-michi.md +53 -0
  156. package/templates/michi/cc-sdd-overrides/settings/templates/specs/init.json +24 -0
  157. package/templates/michi/cc-sdd-overrides/settings/templates/specs/tasks.md +446 -0
  158. package/dist/scripts/config-interactive.d.ts +0 -10
  159. package/dist/scripts/config-interactive.d.ts.map +0 -1
  160. package/dist/scripts/config-interactive.js +0 -372
  161. package/dist/scripts/config-interactive.js.map +0 -1
  162. package/dist/scripts/setup-existing-project.d.ts +0 -15
  163. package/dist/scripts/setup-existing-project.d.ts.map +0 -1
  164. package/dist/scripts/setup-existing-project.js +0 -455
  165. package/dist/scripts/setup-existing-project.js.map +0 -1
  166. package/dist/scripts/setup-interactive.d.ts +0 -10
  167. package/dist/scripts/setup-interactive.d.ts.map +0 -1
  168. package/dist/scripts/setup-interactive.js +0 -413
  169. package/dist/scripts/setup-interactive.js.map +0 -1
  170. package/scripts/config-interactive.ts +0 -550
  171. package/scripts/setup-existing-project.ts +0 -585
  172. package/scripts/setup-interactive.ts +0 -565
@@ -1,550 +0,0 @@
1
- /**
2
- * 対話式設定ツール
3
- * .michi/config.json を対話的に作成・更新
4
- */
5
-
6
- import { readFileSync, writeFileSync, existsSync } from 'fs';
7
- import * as readline from 'readline';
8
- import { loadProjectMeta } from './utils/project-meta.js';
9
- import { validateProjectConfig } from './utils/config-validator.js';
10
-
11
- /**
12
- * readlineインターフェースを作成
13
- */
14
- function createInterface(): readline.Interface {
15
- return readline.createInterface({
16
- input: process.stdin,
17
- output: process.stdout,
18
- });
19
- }
20
-
21
- /**
22
- * 質問を表示して回答を取得
23
- */
24
- function question(rl: readline.Interface, query: string): Promise<string> {
25
- return new Promise((resolve) => {
26
- rl.question(query, (answer) => {
27
- resolve(answer.trim());
28
- });
29
- });
30
- }
31
-
32
- /**
33
- * 選択肢から選択
34
- */
35
- async function select(
36
- rl: readline.Interface,
37
- prompt: string,
38
- choices: Array<{ value: string; label: string; description?: string }>,
39
- defaultValue?: string,
40
- maxRetries: number = 3,
41
- ): Promise<string> {
42
- console.log(`\n${prompt}`);
43
- choices.forEach((choice, index) => {
44
- const defaultMark = defaultValue === choice.value ? ' (デフォルト)' : '';
45
- const desc = choice.description ? ` - ${choice.description}` : '';
46
- console.log(` ${index + 1}. ${choice.label}${desc}${defaultMark}`);
47
- });
48
-
49
- const answer = await question(
50
- rl,
51
- `\n選択してください [1-${choices.length}]: `,
52
- );
53
-
54
- if (!answer && defaultValue) {
55
- return defaultValue;
56
- }
57
-
58
- const index = parseInt(answer, 10) - 1;
59
- if (index >= 0 && index < choices.length) {
60
- return choices[index].value;
61
- }
62
-
63
- if (defaultValue) {
64
- return defaultValue;
65
- }
66
-
67
- // 無効な入力の場合は再試行(最大試行回数まで)
68
- if (maxRetries > 0) {
69
- console.log(
70
- `⚠️ 無効な選択です。もう一度入力してください(残り試行回数: ${maxRetries})。`,
71
- );
72
- return select(rl, prompt, choices, defaultValue, maxRetries - 1);
73
- }
74
-
75
- // 最大試行回数に達した場合はデフォルト値または最初の選択肢を返す
76
- console.log(
77
- `⚠️ 最大試行回数に達しました。デフォルト値を使用します: ${defaultValue || choices[0].value}`,
78
- );
79
- return defaultValue || choices[0].value;
80
- }
81
-
82
- /**
83
- * Yes/No質問
84
- */
85
- async function confirm(
86
- rl: readline.Interface,
87
- prompt: string,
88
- defaultValue: boolean = true,
89
- ): Promise<boolean> {
90
- const defaultText = defaultValue ? '[Y/n]' : '[y/N]';
91
- const answer = await question(rl, `${prompt} ${defaultText}: `);
92
-
93
- if (!answer) {
94
- return defaultValue;
95
- }
96
-
97
- return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
98
- }
99
-
100
- /**
101
- * 複数選択
102
- */
103
- async function multiSelect(
104
- rl: readline.Interface,
105
- prompt: string,
106
- choices: Array<{ value: string; label: string }>,
107
- defaults: string[] = [],
108
- ): Promise<string[]> {
109
- console.log(`\n${prompt}`);
110
- choices.forEach((choice, index) => {
111
- const checked = defaults.includes(choice.value) ? '[x]' : '[ ]';
112
- console.log(` ${checked} ${index + 1}. ${choice.label}`);
113
- });
114
-
115
- const answer = await question(
116
- rl,
117
- '\n選択してください(カンマ区切り、例: 1,2,3): ',
118
- );
119
-
120
- if (!answer && defaults.length > 0) {
121
- return defaults;
122
- }
123
-
124
- if (!answer) {
125
- return [];
126
- }
127
-
128
- const indices = answer
129
- .split(',')
130
- .map((s) => parseInt(s.trim(), 10) - 1)
131
- .filter((i) => i >= 0 && i < choices.length);
132
- return indices.map((i) => choices[i].value);
133
- }
134
-
135
- /**
136
- * Confluence設定を対話的に取得
137
- */
138
- async function getConfluenceConfig(
139
- rl: readline.Interface,
140
- _projectMeta: any,
141
- ): Promise<any> {
142
- console.log('\n📄 Confluence設定');
143
- console.log('='.repeat(60));
144
-
145
- const granularityChoices = [
146
- {
147
- value: 'single',
148
- label: 'single(1ドキュメント = 1ページ)',
149
- description: 'デフォルト・現在の動作',
150
- },
151
- {
152
- value: 'by-section',
153
- label: 'by-section(セクションごとにページ分割)',
154
- description: '## セクションごとにページを作成',
155
- },
156
- {
157
- value: 'by-hierarchy',
158
- label: 'by-hierarchy(階層構造)',
159
- description: '親ページ + 子ページの階層構造',
160
- },
161
- {
162
- value: 'manual',
163
- label: 'manual(手動指定)',
164
- description: '設定ファイルで明示的に指定',
165
- },
166
- ];
167
-
168
- const granularity = await select(
169
- rl,
170
- 'ページ作成粒度を選択してください:',
171
- granularityChoices,
172
- 'single',
173
- );
174
-
175
- const config: any = {
176
- pageCreationGranularity: granularity,
177
- };
178
-
179
- // タイトル形式のカスタマイズ
180
- const customTitle = await confirm(
181
- rl,
182
- 'ページタイトル形式をカスタマイズしますか?',
183
- false,
184
- );
185
-
186
- if (customTitle) {
187
- const titleFormat = await question(
188
- rl,
189
- 'タイトル形式を入力してください(例: {projectName} - {featureName}): ',
190
- );
191
- if (titleFormat) {
192
- config.pageTitleFormat = titleFormat;
193
- }
194
- }
195
-
196
- // 階層構造設定
197
- if (granularity === 'by-hierarchy' || granularity === 'manual') {
198
- config.hierarchy = {};
199
-
200
- if (granularity === 'by-hierarchy') {
201
- const modeChoices = [
202
- {
203
- value: 'simple',
204
- label: 'simple(親ページ + ドキュメントタイプ子ページ)',
205
- description: '2階層構造',
206
- },
207
- {
208
- value: 'nested',
209
- label:
210
- 'nested(親ページ → ドキュメントタイプ親 → セクション子ページ)',
211
- description: '3階層構造',
212
- },
213
- ];
214
-
215
- const mode = await select(
216
- rl,
217
- '階層構造のモードを選択してください:',
218
- modeChoices,
219
- 'simple',
220
- );
221
-
222
- config.hierarchy.mode = mode;
223
- }
224
-
225
- const parentTitle = await question(
226
- rl,
227
- '親ページのタイトル形式を入力してください(例: [{projectName}] {featureName}): ',
228
- );
229
-
230
- if (parentTitle) {
231
- config.hierarchy.parentPageTitle = parentTitle;
232
- } else {
233
- config.hierarchy.parentPageTitle = '[{projectName}] {featureName}';
234
- }
235
-
236
- if (granularity === 'manual') {
237
- console.log(
238
- '\n⚠️ manualモードでは、設定ファイルを手動で編集する必要があります。',
239
- );
240
- console.log(
241
- ' hierarchy.structure に各ドキュメントタイプのページ構造を定義してください。',
242
- );
243
- }
244
- }
245
-
246
- return config;
247
- }
248
-
249
- /**
250
- * JIRA設定を対話的に取得
251
- */
252
- async function getJiraConfig(rl: readline.Interface): Promise<any> {
253
- console.log('\n📋 JIRA設定');
254
- console.log('='.repeat(60));
255
-
256
- const createEpic = await confirm(rl, 'Epicを作成しますか?', true);
257
-
258
- const granularityChoices = [
259
- {
260
- value: 'all',
261
- label: 'all(全Storyを作成)',
262
- description: 'デフォルト',
263
- },
264
- {
265
- value: 'by-phase',
266
- label: 'by-phase(フェーズごとに作成)',
267
- description: 'フェーズごとに個別に作成',
268
- },
269
- {
270
- value: 'selected-phases',
271
- label: 'selected-phases(指定フェーズのみ)',
272
- description: '選択したフェーズのみ作成',
273
- },
274
- ];
275
-
276
- const granularity = await select(
277
- rl,
278
- 'Story作成粒度を選択してください:',
279
- granularityChoices,
280
- 'all',
281
- );
282
-
283
- const config: any = {
284
- createEpic,
285
- storyCreationGranularity: granularity,
286
- };
287
-
288
- if (granularity === 'selected-phases') {
289
- const phaseChoices = [
290
- // 新ワークフロー構造
291
- { value: 'spec-init', label: 'Phase 0.0: プロジェクト初期化' },
292
- { value: 'requirements', label: 'Phase 0.1: 要件定義(Requirements)' },
293
- { value: 'design', label: 'Phase 0.2: 設計(Design)' },
294
- { value: 'test-type-selection', label: 'Phase 0.3: テストタイプ選択' },
295
- { value: 'test-spec', label: 'Phase 0.4: テスト仕様書作成' },
296
- { value: 'spec-tasks', label: 'Phase 0.5: タスク分割' },
297
- { value: 'environment-setup', label: 'Phase 1: 環境構築' },
298
- { value: 'implementation', label: 'Phase 2: TDD実装(Implementation)' },
299
- { value: 'phase-a', label: 'Phase A: PR前自動テスト' },
300
- { value: 'testing', label: 'Phase 3: 追加QA(Testing)' },
301
- { value: 'phase-b', label: 'Phase B: リリース準備テスト' },
302
- { value: 'release-prep', label: 'Phase 4: リリース準備(Release Preparation)' },
303
- { value: 'release', label: 'Phase 5: リリース(Release)' },
304
- ];
305
-
306
- const selectedPhases = await multiSelect(
307
- rl,
308
- '作成するフェーズを選択してください:',
309
- phaseChoices,
310
- ['implementation', 'testing'],
311
- );
312
-
313
- config.selectedPhases = selectedPhases;
314
- }
315
-
316
- const storyPointsChoices = [
317
- { value: 'auto', label: 'auto(自動抽出)', description: 'デフォルト' },
318
- { value: 'manual', label: 'manual(手動設定)' },
319
- { value: 'disabled', label: 'disabled(設定しない)' },
320
- ];
321
-
322
- const storyPoints = await select(
323
- rl,
324
- 'Story Points設定を選択してください:',
325
- storyPointsChoices,
326
- 'auto',
327
- );
328
-
329
- config.storyPoints = storyPoints;
330
-
331
- return config;
332
- }
333
-
334
- /**
335
- * ワークフロー設定を対話的に取得
336
- */
337
- async function getWorkflowConfig(rl: readline.Interface): Promise<any> {
338
- console.log('\n⚙️ ワークフロー設定');
339
- console.log('='.repeat(60));
340
-
341
- const phaseChoices = [
342
- { value: 'requirements', label: '要件定義(Requirements)' },
343
- { value: 'design', label: '設計(Design)' },
344
- { value: 'tasks', label: 'タスク分割(Tasks)' },
345
- ];
346
-
347
- const enabledPhases = await multiSelect(
348
- rl,
349
- '有効化するフェーズを選択してください:',
350
- phaseChoices,
351
- ['requirements', 'design', 'tasks'],
352
- );
353
-
354
- const config: any = {
355
- enabledPhases,
356
- };
357
-
358
- const customApprovalGates = await confirm(
359
- rl,
360
- '承認ゲートをカスタマイズしますか?',
361
- false,
362
- );
363
-
364
- if (customApprovalGates) {
365
- config.approvalGates = {};
366
-
367
- if (enabledPhases.includes('requirements')) {
368
- const approvers = await question(
369
- rl,
370
- '要件定義フェーズの承認者(カンマ区切り、例: pm,director): ',
371
- );
372
- if (approvers) {
373
- config.approvalGates.requirements = approvers
374
- .split(',')
375
- .map((s) => s.trim());
376
- }
377
- }
378
-
379
- if (enabledPhases.includes('design')) {
380
- const approvers = await question(
381
- rl,
382
- '設計フェーズの承認者(カンマ区切り、例: architect,director): ',
383
- );
384
- if (approvers) {
385
- config.approvalGates.design = approvers.split(',').map((s) => s.trim());
386
- }
387
- }
388
-
389
- const releaseApprovers = await question(
390
- rl,
391
- 'リリースフェーズの承認者(カンマ区切り、例: sm,director): ',
392
- );
393
- if (releaseApprovers) {
394
- config.approvalGates.release = releaseApprovers
395
- .split(',')
396
- .map((s) => s.trim());
397
- }
398
- }
399
-
400
- return config;
401
- }
402
-
403
- /**
404
- * メイン処理
405
- */
406
- async function main(): Promise<void> {
407
- const rl = createInterface();
408
-
409
- try {
410
- console.log('🎨 Michi カスタマイズ設定ツール');
411
- console.log('='.repeat(60));
412
- console.log('このツールで .michi/config.json を作成・更新できます。\n');
413
-
414
- // プロジェクトメタデータを読み込み
415
- let projectMeta;
416
- try {
417
- projectMeta = loadProjectMeta();
418
- console.log(
419
- `📦 プロジェクト: ${projectMeta.projectName} (${projectMeta.projectId})\n`,
420
- );
421
- } catch {
422
- console.error('❌ プロジェクトメタデータが見つかりません。');
423
- console.error(' .kiro/project.json が存在するか確認してください。');
424
- process.exit(1);
425
- }
426
-
427
- // 既存の設定ファイルを確認
428
- const { getConfigPath } = await import('./utils/config-loader.js');
429
- const configPath = getConfigPath();
430
- let existingConfig: any = null;
431
-
432
- if (existsSync(configPath)) {
433
- console.log('⚠️ 既存の設定ファイルが見つかりました。');
434
- const overwrite = await confirm(rl, '上書きしますか?', false);
435
-
436
- if (!overwrite) {
437
- console.log('中止しました。');
438
- process.exit(0);
439
- }
440
-
441
- try {
442
- const content = readFileSync(configPath, 'utf-8');
443
- existingConfig = JSON.parse(content);
444
- console.log('既存の設定を読み込みました。\n');
445
- } catch {
446
- console.log(
447
- '既存の設定ファイルの読み込みに失敗しました。新規作成します。\n',
448
- );
449
- }
450
- }
451
-
452
- // 設定を対話的に取得
453
- const config: any = existingConfig || {};
454
-
455
- // Confluence設定
456
- const configureConfluence = await confirm(
457
- rl,
458
- 'Confluence設定をカスタマイズしますか?',
459
- false,
460
- );
461
- if (configureConfluence) {
462
- config.confluence = await getConfluenceConfig(rl, projectMeta);
463
- }
464
-
465
- // JIRA設定
466
- const configureJira = await confirm(
467
- rl,
468
- 'JIRA設定をカスタマイズしますか?',
469
- false,
470
- );
471
- if (configureJira) {
472
- config.jira = await getJiraConfig(rl);
473
- }
474
-
475
- // ワークフロー設定
476
- const configureWorkflow = await confirm(
477
- rl,
478
- 'ワークフロー設定をカスタマイズしますか?',
479
- false,
480
- );
481
- if (configureWorkflow) {
482
- config.workflow = await getWorkflowConfig(rl);
483
- }
484
-
485
- // 設定の確認
486
- console.log('\n📋 設定内容の確認');
487
- console.log('='.repeat(60));
488
- console.log(JSON.stringify(config, null, 2));
489
- console.log('');
490
-
491
- const confirmSave = await confirm(rl, 'この設定を保存しますか?', true);
492
-
493
- if (!confirmSave) {
494
- console.log('保存をキャンセルしました。');
495
- process.exit(0);
496
- }
497
-
498
- // 設定ファイルを保存
499
- writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
500
- console.log(`\n✅ 設定ファイルを保存しました: ${configPath}`);
501
-
502
- // バリデーション
503
- console.log('\n🔍 設定ファイルのバリデーション...');
504
- const validation = validateProjectConfig();
505
-
506
- if (validation.info.length > 0) {
507
- console.log('ℹ️ Info:');
508
- validation.info.forEach((msg) => console.log(` - ${msg}`));
509
- }
510
-
511
- if (validation.warnings.length > 0) {
512
- console.log('⚠️ Warnings:');
513
- validation.warnings.forEach((warning) => console.log(` - ${warning}`));
514
- }
515
-
516
- if (validation.errors.length > 0) {
517
- console.error('❌ Validation errors:');
518
- validation.errors.forEach((error) => console.error(` - ${error}`));
519
- console.error(
520
- '\n設定ファイルにエラーがあります。手動で修正してください。',
521
- );
522
- process.exit(1);
523
- }
524
-
525
- if (validation.valid) {
526
- console.log('✅ 設定ファイルは有効です。');
527
- }
528
-
529
- console.log('\n🎉 設定が完了しました!');
530
- console.log(' 次回のConfluence/JIRA同期時に、この設定が適用されます。');
531
- } catch (error) {
532
- console.error(
533
- '❌ エラーが発生しました:',
534
- error instanceof Error ? error.message : error,
535
- );
536
- process.exit(1);
537
- } finally {
538
- rl.close();
539
- }
540
- }
541
-
542
- // CLI実行
543
- if (import.meta.url === `file://${process.argv[1]}`) {
544
- main().catch((error) => {
545
- console.error('❌ 予期しないエラー:', error);
546
- process.exit(1);
547
- });
548
- }
549
-
550
- export { main as configInteractive };