@sk8metal/michi-cli 0.3.0 → 0.5.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.
- package/CHANGELOG.md +83 -0
- package/dist/scripts/__tests__/spec-impl-workflow.test.js +4 -2
- package/dist/scripts/__tests__/spec-impl-workflow.test.js.map +1 -1
- package/dist/scripts/config/config-schema.d.ts +52 -0
- package/dist/scripts/config/config-schema.d.ts.map +1 -1
- package/dist/scripts/config/config-schema.js +25 -0
- package/dist/scripts/config/config-schema.js.map +1 -1
- package/dist/scripts/config-global.d.ts +10 -0
- package/dist/scripts/config-global.d.ts.map +1 -0
- package/dist/scripts/config-global.js +111 -0
- package/dist/scripts/config-global.js.map +1 -0
- package/dist/scripts/confluence-sync.d.ts +22 -4
- package/dist/scripts/confluence-sync.d.ts.map +1 -1
- package/dist/scripts/confluence-sync.js +22 -12
- package/dist/scripts/confluence-sync.js.map +1 -1
- package/dist/scripts/jira-sync.d.ts.map +1 -1
- package/dist/scripts/jira-sync.js +201 -167
- package/dist/scripts/jira-sync.js.map +1 -1
- package/dist/scripts/list-projects.js.map +1 -1
- package/dist/scripts/multi-project-estimate.js.map +1 -1
- package/dist/scripts/phase-runner.d.ts +1 -1
- package/dist/scripts/phase-runner.d.ts.map +1 -1
- package/dist/scripts/phase-runner.js +295 -522
- package/dist/scripts/phase-runner.js.map +1 -1
- package/dist/scripts/pr-automation.d.ts.map +1 -1
- package/dist/scripts/pr-automation.js +11 -3
- package/dist/scripts/pr-automation.js.map +1 -1
- package/dist/scripts/pre-flight-check.d.ts.map +1 -1
- package/dist/scripts/pre-flight-check.js +10 -6
- package/dist/scripts/pre-flight-check.js.map +1 -1
- package/dist/scripts/resource-dashboard.js.map +1 -1
- package/dist/scripts/spec-impl-workflow.d.ts.map +1 -1
- package/dist/scripts/spec-impl-workflow.js +23 -7
- package/dist/scripts/spec-impl-workflow.js.map +1 -1
- package/dist/scripts/template/renderer.d.ts +1 -1
- package/dist/scripts/template/renderer.d.ts.map +1 -1
- package/dist/scripts/test-interactive.d.ts.map +1 -1
- package/dist/scripts/test-interactive.js +0 -15
- package/dist/scripts/test-interactive.js.map +1 -1
- package/dist/scripts/test-new-features.js +6 -3
- package/dist/scripts/test-new-features.js.map +1 -1
- package/dist/scripts/test-spec-generator.d.ts.map +1 -1
- package/dist/scripts/test-spec-generator.js +1 -2
- package/dist/scripts/test-spec-generator.js.map +1 -1
- package/dist/scripts/utils/__tests__/config-loader.test.js +114 -1
- package/dist/scripts/utils/__tests__/config-loader.test.js.map +1 -1
- package/dist/scripts/utils/__tests__/config-validator.test.js +2 -0
- package/dist/scripts/utils/__tests__/config-validator.test.js.map +1 -1
- package/dist/scripts/utils/__tests__/env-config.test.js +0 -2
- package/dist/scripts/utils/__tests__/env-config.test.js.map +1 -1
- package/dist/scripts/utils/__tests__/project-meta.test.d.ts +6 -0
- package/dist/scripts/utils/__tests__/project-meta.test.d.ts.map +1 -0
- package/dist/scripts/utils/__tests__/project-meta.test.js +154 -0
- package/dist/scripts/utils/__tests__/project-meta.test.js.map +1 -0
- package/dist/scripts/utils/__tests__/security-validator.test.d.ts +6 -0
- package/dist/scripts/utils/__tests__/security-validator.test.d.ts.map +1 -0
- package/dist/scripts/utils/__tests__/security-validator.test.js +219 -0
- package/dist/scripts/utils/__tests__/security-validator.test.js.map +1 -0
- package/dist/scripts/utils/config-loader.d.ts +14 -3
- package/dist/scripts/utils/config-loader.d.ts.map +1 -1
- package/dist/scripts/utils/config-loader.js +284 -46
- package/dist/scripts/utils/config-loader.js.map +1 -1
- package/dist/scripts/utils/config-sections.d.ts +54 -0
- package/dist/scripts/utils/config-sections.d.ts.map +1 -0
- package/dist/scripts/utils/config-sections.js +178 -0
- package/dist/scripts/utils/config-sections.js.map +1 -0
- package/dist/scripts/utils/config-validator.d.ts +4 -0
- package/dist/scripts/utils/config-validator.d.ts.map +1 -1
- package/dist/scripts/utils/config-validator.js +57 -1
- package/dist/scripts/utils/config-validator.js.map +1 -1
- package/dist/scripts/utils/confluence-approval.d.ts.map +1 -1
- package/dist/scripts/utils/confluence-approval.js +5 -3
- package/dist/scripts/utils/confluence-approval.js.map +1 -1
- package/dist/scripts/utils/confluence-hierarchy.d.ts.map +1 -1
- package/dist/scripts/utils/confluence-hierarchy.js.map +1 -1
- package/dist/scripts/utils/env-config.d.ts +1 -1
- package/dist/scripts/utils/env-config.d.ts.map +1 -1
- package/dist/scripts/utils/env-config.js +2 -14
- package/dist/scripts/utils/env-config.js.map +1 -1
- package/dist/scripts/utils/interactive-helpers.d.ts +32 -0
- package/dist/scripts/utils/interactive-helpers.d.ts.map +1 -0
- package/dist/scripts/utils/interactive-helpers.js +92 -0
- package/dist/scripts/utils/interactive-helpers.js.map +1 -0
- package/dist/scripts/utils/jira-issue-type-fetcher.d.ts.map +1 -1
- package/dist/scripts/utils/jira-issue-type-fetcher.js +27 -18
- package/dist/scripts/utils/jira-issue-type-fetcher.js.map +1 -1
- package/dist/scripts/utils/project-meta.d.ts +9 -0
- package/dist/scripts/utils/project-meta.d.ts.map +1 -1
- package/dist/scripts/utils/project-meta.js +22 -0
- package/dist/scripts/utils/project-meta.js.map +1 -1
- package/dist/scripts/utils/release-notes-generator.d.ts.map +1 -1
- package/dist/scripts/utils/release-notes-generator.js +2 -1
- package/dist/scripts/utils/release-notes-generator.js.map +1 -1
- package/dist/scripts/utils/security-validator.d.ts +55 -0
- package/dist/scripts/utils/security-validator.d.ts.map +1 -0
- package/dist/scripts/utils/security-validator.js +232 -0
- package/dist/scripts/utils/security-validator.js.map +1 -0
- package/dist/scripts/utils/spec-updater.d.ts +19 -0
- package/dist/scripts/utils/spec-updater.d.ts.map +1 -1
- package/dist/scripts/utils/spec-updater.js.map +1 -1
- package/dist/scripts/utils/tasks-converter.d.ts.map +1 -1
- package/dist/scripts/utils/tasks-converter.js +2 -2
- package/dist/scripts/utils/tasks-converter.js.map +1 -1
- package/dist/scripts/utils/tasks-format-validator.d.ts.map +1 -1
- package/dist/scripts/utils/tasks-format-validator.js +0 -12
- package/dist/scripts/utils/tasks-format-validator.js.map +1 -1
- package/dist/scripts/utils/test-runner.d.ts.map +1 -1
- package/dist/scripts/utils/test-runner.js +3 -2
- package/dist/scripts/utils/test-runner.js.map +1 -1
- package/dist/scripts/validate-phase.d.ts +1 -1
- package/dist/scripts/validate-phase.d.ts.map +1 -1
- package/dist/scripts/validate-phase.js +12 -62
- package/dist/scripts/validate-phase.js.map +1 -1
- package/dist/scripts/workflow-orchestrator.d.ts.map +1 -1
- package/dist/scripts/workflow-orchestrator.js +11 -16
- package/dist/scripts/workflow-orchestrator.js.map +1 -1
- package/dist/src/__tests__/integration/setup/init.test.d.ts +5 -0
- package/dist/src/__tests__/integration/setup/init.test.d.ts.map +1 -0
- package/dist/src/__tests__/integration/setup/init.test.js +352 -0
- package/dist/src/__tests__/integration/setup/init.test.js.map +1 -0
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +67 -21
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/__tests__/init.test.d.ts +5 -0
- package/dist/src/commands/__tests__/init.test.d.ts.map +1 -0
- package/dist/src/commands/__tests__/init.test.js +255 -0
- package/dist/src/commands/__tests__/init.test.js.map +1 -0
- package/dist/src/commands/__tests__/migrate.test.d.ts +5 -0
- package/dist/src/commands/__tests__/migrate.test.d.ts.map +1 -0
- package/dist/src/commands/__tests__/migrate.test.js +216 -0
- package/dist/src/commands/__tests__/migrate.test.js.map +1 -0
- package/dist/src/commands/config-validate.d.ts +9 -0
- package/dist/src/commands/config-validate.d.ts.map +1 -0
- package/dist/src/commands/config-validate.js +90 -0
- package/dist/src/commands/config-validate.js.map +1 -0
- package/dist/src/commands/init.d.ts +29 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +513 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/migrate.d.ts +25 -0
- package/dist/src/commands/migrate.d.ts.map +1 -0
- package/dist/src/commands/migrate.js +341 -0
- package/dist/src/commands/migrate.js.map +1 -0
- package/dist/src/commands/setup-existing.d.ts.map +1 -1
- package/dist/src/commands/setup-existing.js +0 -1
- package/dist/src/commands/setup-existing.js.map +1 -1
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +32 -8
- package/dist/vitest.config.js.map +1 -1
- package/docs/michi-development/design/config-unification.md +4789 -0
- package/docs/user-guide/getting-started/github-token-setup.md +2 -1
- package/docs/user-guide/getting-started/new-repository-setup.md +1 -1
- package/docs/user-guide/getting-started/quick-start.md +1 -1
- package/docs/user-guide/getting-started/setup.md +35 -14
- package/docs/user-guide/guides/customization.md +64 -11
- package/docs/user-guide/guides/workflow.md +35 -21
- package/docs/user-guide/hands-on/claude-agent-setup.md +2 -2
- package/docs/user-guide/hands-on/claude-setup.md +2 -2
- package/docs/user-guide/hands-on/cursor-setup.md +2 -2
- package/docs/user-guide/hands-on/workflow-walkthrough.md +4 -1
- package/docs/user-guide/reference/config.md +30 -5
- package/docs/user-guide/reference/quick-reference.md +68 -74
- package/docs/user-guide/testing/test-planning-flow.md +4 -0
- package/env.example +1 -1
- package/package.json +3 -5
- package/scripts/__tests__/spec-impl-workflow.test.ts +5 -2
- package/scripts/config/config-schema.ts +40 -0
- package/scripts/config-global.ts +160 -0
- package/scripts/confluence-sync.ts +91 -27
- package/scripts/jira-sync.ts +284 -218
- package/scripts/list-projects.ts +2 -2
- package/scripts/multi-project-estimate.ts +3 -3
- package/scripts/phase-runner.ts +391 -594
- package/scripts/pr-automation.ts +15 -5
- package/scripts/pre-flight-check.ts +20 -9
- package/scripts/pre-publish-check.sh +3 -34
- package/scripts/resource-dashboard.ts +4 -4
- package/scripts/spec-impl-workflow.ts +23 -7
- package/scripts/template/renderer.ts +1 -1
- package/scripts/test-interactive.ts +0 -19
- package/scripts/test-new-features.ts +10 -7
- package/scripts/test-npm-package.sh +3 -34
- package/scripts/test-spec-generator.ts +3 -7
- package/scripts/utils/__tests__/config-loader.test.ts +149 -0
- package/scripts/utils/__tests__/config-validator.test.ts +2 -0
- package/scripts/utils/__tests__/env-config.test.ts +0 -2
- package/scripts/utils/__tests__/project-meta.test.ts +192 -0
- package/scripts/utils/__tests__/security-validator.test.ts +272 -0
- package/scripts/utils/config-loader.ts +328 -68
- package/scripts/utils/config-sections.ts +316 -0
- package/scripts/utils/config-validator.ts +66 -1
- package/scripts/utils/confluence-approval.ts +8 -6
- package/scripts/utils/confluence-hierarchy.ts +27 -27
- package/scripts/utils/env-config.ts +2 -14
- package/scripts/utils/interactive-helpers.ts +135 -0
- package/scripts/utils/jira-issue-type-fetcher.ts +29 -21
- package/scripts/utils/project-meta.ts +27 -0
- package/scripts/utils/release-notes-generator.ts +3 -2
- package/scripts/utils/security-validator.ts +286 -0
- package/scripts/utils/spec-updater.ts +37 -15
- package/scripts/utils/tasks-converter.ts +4 -6
- package/scripts/utils/tasks-format-validator.ts +0 -13
- package/scripts/utils/test-runner.ts +4 -3
- package/scripts/validate-phase.ts +21 -80
- package/scripts/workflow-orchestrator.ts +16 -25
- package/templates/claude/commands/kiro/kiro-spec-impl.md +5 -1
- package/templates/claude/commands/kiro/kiro-spec-tasks.md +3 -1
- package/templates/claude/commands/michi/confluence-sync.md +8 -2
- package/templates/claude/commands/michi/design-review.md +4 -0
- package/templates/claude/commands/michi/e2e-plan.md +4 -0
- package/templates/claude/commands/michi/license-check.md +4 -0
- package/templates/claude/commands/michi/pr-resolve.md +4 -0
- package/templates/claude/commands/michi/project-switch.md +8 -2
- package/templates/claude/commands/michi/spec-design.md +78 -0
- package/templates/claude/commands/michi/spec-impl.md +716 -0
- package/templates/claude/commands/michi/test-planning.md +174 -0
- package/templates/claude/commands/michi/validate-design.md +58 -0
- package/templates/claude/commands/michi/version-audit.md +4 -0
- package/templates/claude-agent/commands/kiro/kiro-spec-impl.md +1 -1
- package/templates/cursor/commands/kiro/kiro-spec-impl.md +1 -1
- package/templates/michi/cc-sdd-overrides/README.md +8 -0
- package/templates/michi/cc-sdd-overrides/settings/rules/design-review-michi.md +53 -0
- package/dist/scripts/config-interactive.d.ts +0 -10
- package/dist/scripts/config-interactive.d.ts.map +0 -1
- package/dist/scripts/config-interactive.js +0 -372
- package/dist/scripts/config-interactive.js.map +0 -1
- package/dist/scripts/setup-existing-project.d.ts +0 -15
- package/dist/scripts/setup-existing-project.d.ts.map +0 -1
- package/dist/scripts/setup-existing-project.js +0 -455
- package/dist/scripts/setup-existing-project.js.map +0 -1
- package/dist/scripts/setup-interactive.d.ts +0 -10
- package/dist/scripts/setup-interactive.d.ts.map +0 -1
- package/dist/scripts/setup-interactive.js +0 -413
- package/dist/scripts/setup-interactive.js.map +0 -1
- package/scripts/config-interactive.ts +0 -550
- package/scripts/setup-existing-project.ts +0 -585
- package/scripts/setup-interactive.ts +0 -565
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* フェーズランナー
|
|
3
3
|
* 各フェーズを実行し、Confluence/JIRA作成を確実に実行
|
|
4
4
|
*/
|
|
5
|
-
import { existsSync, writeFileSync, readFileSync
|
|
5
|
+
import { existsSync, writeFileSync, readFileSync } from 'fs';
|
|
6
6
|
import { join, relative } from 'path';
|
|
7
7
|
import { syncToConfluence } from './confluence-sync.js';
|
|
8
8
|
import { syncTasksToJIRA } from './jira-sync.js';
|
|
@@ -43,8 +43,9 @@ async function runRequirementsPhase(feature) {
|
|
|
43
43
|
console.log('✅ Confluenceページ作成成功');
|
|
44
44
|
}
|
|
45
45
|
catch (error) {
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
47
|
+
errors.push(`Confluenceページ作成失敗: ${message}`);
|
|
48
|
+
console.error('❌ Confluenceページ作成失敗:', message);
|
|
48
49
|
}
|
|
49
50
|
// Step 3: バリデーション
|
|
50
51
|
console.log('\n🔍 バリデーション実行中...');
|
|
@@ -107,8 +108,9 @@ async function runDesignPhase(feature) {
|
|
|
107
108
|
console.log('✅ Confluenceページ作成成功');
|
|
108
109
|
}
|
|
109
110
|
catch (error) {
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
112
|
+
errors.push(`Confluenceページ作成失敗: ${message}`);
|
|
113
|
+
console.error('❌ Confluenceページ作成失敗:', message);
|
|
112
114
|
}
|
|
113
115
|
// Step 3: バリデーション
|
|
114
116
|
console.log('\n🔍 バリデーション実行中...');
|
|
@@ -141,126 +143,100 @@ async function runDesignPhase(feature) {
|
|
|
141
143
|
};
|
|
142
144
|
}
|
|
143
145
|
/**
|
|
144
|
-
*
|
|
146
|
+
* タスク分割フェーズの前提条件をチェック
|
|
145
147
|
*/
|
|
146
|
-
async function
|
|
147
|
-
console.log('\n📝 Phase: Tasks(タスク分割)');
|
|
148
|
-
console.log('='.repeat(60));
|
|
148
|
+
async function checkTasksPrerequisites(feature) {
|
|
149
149
|
const errors = [];
|
|
150
|
-
|
|
151
|
-
// Step 0: プリフライトチェック
|
|
150
|
+
// プリフライトチェック
|
|
152
151
|
console.log('\n🔍 プリフライトチェック...');
|
|
153
152
|
const preFlightResult = await runPreFlightCheck('jira');
|
|
154
153
|
if (!preFlightResult.valid) {
|
|
155
154
|
console.log('\n❌ プリフライトチェック失敗:');
|
|
156
155
|
preFlightResult.errors.forEach((e) => console.log(` ${e}`));
|
|
157
|
-
return {
|
|
158
|
-
phase: 'tasks',
|
|
159
|
-
success: false,
|
|
160
|
-
confluenceCreated: false,
|
|
161
|
-
jiraCreated: false,
|
|
162
|
-
validationPassed: false,
|
|
163
|
-
errors: preFlightResult.errors,
|
|
164
|
-
};
|
|
156
|
+
return { valid: false, errors: preFlightResult.errors };
|
|
165
157
|
}
|
|
166
158
|
console.log('✅ プリフライトチェック成功');
|
|
167
|
-
//
|
|
159
|
+
// tasks.md存在確認
|
|
168
160
|
const tasksPath = join(process.cwd(), '.kiro', 'specs', feature, 'tasks.md');
|
|
169
161
|
if (!existsSync(tasksPath)) {
|
|
170
162
|
errors.push('tasks.mdが存在しません。先に/kiro:spec-tasks を実行してください');
|
|
171
|
-
return {
|
|
172
|
-
phase: 'tasks',
|
|
173
|
-
success: false,
|
|
174
|
-
confluenceCreated: false,
|
|
175
|
-
jiraCreated: false,
|
|
176
|
-
validationPassed: false,
|
|
177
|
-
errors,
|
|
178
|
-
};
|
|
163
|
+
return { valid: false, errors };
|
|
179
164
|
}
|
|
180
165
|
console.log('✅ tasks.md 存在確認');
|
|
181
|
-
|
|
166
|
+
return { valid: true, errors: [] };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* AI-DLC形式を検出して変換を提案
|
|
170
|
+
*/
|
|
171
|
+
async function detectAndConvertAIDLCFormat(feature, tasksPath) {
|
|
172
|
+
const errors = [];
|
|
182
173
|
console.log('\n🔍 tasks.mdフォーマット検証中...');
|
|
183
174
|
const { isAIDLCFormat } = await import('./utils/aidlc-parser.js');
|
|
184
175
|
const tasksContent = readFileSync(tasksPath, 'utf-8');
|
|
185
|
-
if (isAIDLCFormat(tasksContent)) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
success: false,
|
|
238
|
-
confluenceCreated: false,
|
|
239
|
-
jiraCreated: false,
|
|
240
|
-
validationPassed: false,
|
|
241
|
-
errors,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// Step 1.6: tasks.mdフォーマット検証
|
|
176
|
+
if (!isAIDLCFormat(tasksContent)) {
|
|
177
|
+
return { success: true, errors: [] };
|
|
178
|
+
}
|
|
179
|
+
console.log('\n⚠️ AI-DLC形式が検出されました');
|
|
180
|
+
console.log(' tasks.mdはMichiワークフロー形式ではなくAI-DLC形式です。');
|
|
181
|
+
console.log('');
|
|
182
|
+
console.log('🔄 変換オプション:');
|
|
183
|
+
console.log(` michi tasks:convert ${feature} --dry-run # プレビュー`);
|
|
184
|
+
console.log(` michi tasks:convert ${feature} --backup # バックアップ付きで変換`);
|
|
185
|
+
console.log(` michi tasks:convert ${feature} # 直接変換`);
|
|
186
|
+
console.log('');
|
|
187
|
+
// 対話的に変換を提案
|
|
188
|
+
const shouldConvert = await inquirer.prompt([
|
|
189
|
+
{
|
|
190
|
+
type: 'confirm',
|
|
191
|
+
name: 'convert',
|
|
192
|
+
message: 'AI-DLC形式をMichiワークフロー形式に変換しますか?',
|
|
193
|
+
default: true,
|
|
194
|
+
},
|
|
195
|
+
]);
|
|
196
|
+
if (!shouldConvert.convert) {
|
|
197
|
+
console.log('\n⏭️ 変換をスキップしました');
|
|
198
|
+
console.log(' AI-DLC形式のままではJIRA連携が正常に動作しない可能性があります。');
|
|
199
|
+
errors.push('tasks.mdがAI-DLC形式のため、フォーマット検証をスキップしました');
|
|
200
|
+
return { success: false, errors };
|
|
201
|
+
}
|
|
202
|
+
console.log('\n🔄 AI-DLC形式をMichiワークフロー形式に変換中...');
|
|
203
|
+
const { convertTasksFile } = await import('./utils/tasks-converter.js');
|
|
204
|
+
const result = convertTasksFile(tasksPath, undefined, {
|
|
205
|
+
backup: true,
|
|
206
|
+
language: 'ja',
|
|
207
|
+
projectName: feature,
|
|
208
|
+
});
|
|
209
|
+
if (result.success) {
|
|
210
|
+
console.log('✅ 変換成功!');
|
|
211
|
+
console.log(` 元ファイル: ${result.backupPath}`);
|
|
212
|
+
console.log(` 変換後: ${tasksPath}`);
|
|
213
|
+
console.log(` 統計: ${result.stats.originalTasks}タスク → ${result.stats.convertedStories}ストーリー`);
|
|
214
|
+
return { success: true, errors: [] };
|
|
215
|
+
}
|
|
216
|
+
errors.push('AI-DLC形式の変換に失敗しました');
|
|
217
|
+
result.warnings.forEach((w) => errors.push(w));
|
|
218
|
+
console.error('❌ 変換失敗');
|
|
219
|
+
return { success: false, errors };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* tasks.mdのフォーマット検証とJIRA同期
|
|
223
|
+
*/
|
|
224
|
+
async function validateTasksFormatAndSyncJIRA(feature, tasksPath) {
|
|
225
|
+
const errors = [];
|
|
226
|
+
let jiraCreated = false;
|
|
227
|
+
// フォーマット検証
|
|
246
228
|
const { validateTasksFormat } = await import('./utils/tasks-format-validator.js');
|
|
247
229
|
try {
|
|
248
230
|
validateTasksFormat(tasksPath);
|
|
249
231
|
console.log('✅ tasks.mdフォーマット検証成功');
|
|
250
232
|
}
|
|
251
233
|
catch (error) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
success: false,
|
|
257
|
-
confluenceCreated: false,
|
|
258
|
-
jiraCreated: false,
|
|
259
|
-
validationPassed: false,
|
|
260
|
-
errors,
|
|
261
|
-
};
|
|
234
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
235
|
+
errors.push(`フォーマット検証失敗: ${message}`);
|
|
236
|
+
console.error('❌ フォーマット検証失敗:', message);
|
|
237
|
+
return { jiraCreated: false, errors };
|
|
262
238
|
}
|
|
263
|
-
//
|
|
239
|
+
// JIRA Epic/Story作成
|
|
264
240
|
console.log('\n📤 JIRA Epic/Story作成中...');
|
|
265
241
|
try {
|
|
266
242
|
await syncTasksToJIRA(feature);
|
|
@@ -268,14 +244,16 @@ async function runTasksPhase(feature) {
|
|
|
268
244
|
console.log('✅ JIRA Epic/Story作成成功');
|
|
269
245
|
}
|
|
270
246
|
catch (error) {
|
|
271
|
-
|
|
272
|
-
|
|
247
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
248
|
+
errors.push(`JIRA作成失敗: ${message}`);
|
|
249
|
+
console.error('❌ JIRA作成失敗:', message);
|
|
273
250
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
251
|
+
return { jiraCreated, errors };
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* タスク分割フェーズのサマリーを表示
|
|
255
|
+
*/
|
|
256
|
+
function displayTasksPhaseSummary(jiraCreated, validation) {
|
|
279
257
|
console.log('\n' + '='.repeat(60));
|
|
280
258
|
console.log('📊 タスク分割フェーズ完了チェック:');
|
|
281
259
|
console.log(' ✅ tasks.md: 作成済み');
|
|
@@ -286,254 +264,34 @@ async function runTasksPhase(feature) {
|
|
|
286
264
|
console.log('📢 開発チームに実装開始を通知してください');
|
|
287
265
|
console.log('🚀 次のステップ: /kiro:spec-impl <feature>');
|
|
288
266
|
}
|
|
289
|
-
return {
|
|
290
|
-
phase: 'tasks',
|
|
291
|
-
success: validation.valid && jiraCreated,
|
|
292
|
-
confluenceCreated: false,
|
|
293
|
-
jiraCreated,
|
|
294
|
-
validationPassed: validation.valid,
|
|
295
|
-
errors,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* テストタイプ選択フェーズを実行(Phase 0.3)
|
|
300
|
-
* 対話的にテストタイプを選択
|
|
301
|
-
*/
|
|
302
|
-
async function runTestTypeSelectionPhase(feature) {
|
|
303
|
-
console.log('\n🧪 Phase 0.3: Test Type Selection(テストタイプ選択)');
|
|
304
|
-
console.log('='.repeat(60));
|
|
305
|
-
const errors = [];
|
|
306
|
-
const specDir = join(process.cwd(), '.kiro', 'specs', feature);
|
|
307
|
-
const selectionPath = join(specDir, 'test-type-selection.json');
|
|
308
|
-
// 既存の選択を読み込む(存在する場合)
|
|
309
|
-
let existingSelection = null;
|
|
310
|
-
if (existsSync(selectionPath)) {
|
|
311
|
-
try {
|
|
312
|
-
existingSelection = JSON.parse(readFileSync(selectionPath, 'utf-8'));
|
|
313
|
-
console.log('\n📋 既存の選択が見つかりました:');
|
|
314
|
-
console.log(` 選択済みテストタイプ: ${existingSelection.selectedTypes?.join(', ') || 'なし'}`);
|
|
315
|
-
}
|
|
316
|
-
catch {
|
|
317
|
-
console.warn('⚠️ 既存の選択ファイルの読み込みに失敗しました');
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
console.log('\n📚 プロジェクト要件に応じてテストタイプを選択してください\n');
|
|
321
|
-
// 対話的な質問
|
|
322
|
-
const answers = await inquirer.prompt([
|
|
323
|
-
{
|
|
324
|
-
type: 'checkbox',
|
|
325
|
-
name: 'testTypes',
|
|
326
|
-
message: '実施するテストタイプを選択してください(スペースキーで選択/解除、Enterで確定):',
|
|
327
|
-
choices: [
|
|
328
|
-
{
|
|
329
|
-
name: '単体テスト (Unit Tests) - 必須 [Phase A]',
|
|
330
|
-
value: 'unit',
|
|
331
|
-
checked: true, // 必須のためデフォルトで選択
|
|
332
|
-
disabled: true, // 必須のため変更不可
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
name: 'Lint実行 - 必須 [Phase A]',
|
|
336
|
-
value: 'lint',
|
|
337
|
-
checked: true,
|
|
338
|
-
disabled: true,
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
name: 'ビルド実行 - 必須 [Phase A]',
|
|
342
|
-
value: 'build',
|
|
343
|
-
checked: true,
|
|
344
|
-
disabled: true,
|
|
345
|
-
},
|
|
346
|
-
new inquirer.Separator('--- 推奨テスト ---'),
|
|
347
|
-
{
|
|
348
|
-
name: '統合テスト (Integration Tests) - 推奨 [Phase 3/B]',
|
|
349
|
-
value: 'integration',
|
|
350
|
-
checked: existingSelection?.selectedTypes?.includes('integration') || false,
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
name: 'E2Eテスト (End-to-End Tests) - 推奨 [Phase 3/B]',
|
|
354
|
-
value: 'e2e',
|
|
355
|
-
checked: existingSelection?.selectedTypes?.includes('e2e') || false,
|
|
356
|
-
},
|
|
357
|
-
new inquirer.Separator('--- 任意テスト ---'),
|
|
358
|
-
{
|
|
359
|
-
name: '性能テスト (Performance Tests) - 任意 [Phase B]',
|
|
360
|
-
value: 'performance',
|
|
361
|
-
checked: existingSelection?.selectedTypes?.includes('performance') || false,
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
name: 'セキュリティテスト (Security Tests) - 任意 [Phase B]',
|
|
365
|
-
value: 'security',
|
|
366
|
-
checked: existingSelection?.selectedTypes?.includes('security') || false,
|
|
367
|
-
},
|
|
368
|
-
],
|
|
369
|
-
validate: () => {
|
|
370
|
-
// disabled項目は自動的に含まれるため、バリデーションは常に成功
|
|
371
|
-
return true;
|
|
372
|
-
},
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
type: 'confirm',
|
|
376
|
-
name: 'confirm',
|
|
377
|
-
message: (answers) => {
|
|
378
|
-
// 必須テストを自動的に追加
|
|
379
|
-
const required = ['unit', 'lint', 'build'];
|
|
380
|
-
const selected = [...new Set([...required, ...answers.testTypes])];
|
|
381
|
-
const optional = selected.filter((t) => !required.includes(t));
|
|
382
|
-
if (optional.length === 0) {
|
|
383
|
-
return '必須テストのみが選択されています。この選択で進めますか?';
|
|
384
|
-
}
|
|
385
|
-
return `選択したテストタイプ: ${selected.join(', ')}\nこの選択で進めますか?`;
|
|
386
|
-
},
|
|
387
|
-
default: true,
|
|
388
|
-
},
|
|
389
|
-
]);
|
|
390
|
-
// 必須テストを自動的に追加(disabled項目はanswers.testTypesに含まれないため)
|
|
391
|
-
const requiredTests = ['unit', 'lint', 'build'];
|
|
392
|
-
answers.testTypes = [...new Set([...requiredTests, ...answers.testTypes])];
|
|
393
|
-
if (!answers.confirm) {
|
|
394
|
-
console.log('\n❌ 選択がキャンセルされました');
|
|
395
|
-
return {
|
|
396
|
-
phase: 'test-type-selection',
|
|
397
|
-
success: false,
|
|
398
|
-
confluenceCreated: false,
|
|
399
|
-
jiraCreated: false,
|
|
400
|
-
validationPassed: false,
|
|
401
|
-
errors: ['ユーザーが選択をキャンセルしました'],
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
// 選択結果を保存
|
|
405
|
-
const selection = {
|
|
406
|
-
feature,
|
|
407
|
-
selectedTypes: answers.testTypes,
|
|
408
|
-
selectedAt: new Date().toISOString(),
|
|
409
|
-
testTypes: {
|
|
410
|
-
unit: {
|
|
411
|
-
enabled: true,
|
|
412
|
-
required: true,
|
|
413
|
-
phase: 'A',
|
|
414
|
-
description: '単体テスト',
|
|
415
|
-
},
|
|
416
|
-
lint: {
|
|
417
|
-
enabled: true,
|
|
418
|
-
required: true,
|
|
419
|
-
phase: 'A',
|
|
420
|
-
description: 'Lint実行',
|
|
421
|
-
},
|
|
422
|
-
build: {
|
|
423
|
-
enabled: true,
|
|
424
|
-
required: true,
|
|
425
|
-
phase: 'A',
|
|
426
|
-
description: 'ビルド実行',
|
|
427
|
-
},
|
|
428
|
-
integration: {
|
|
429
|
-
enabled: answers.testTypes.includes('integration'),
|
|
430
|
-
required: false,
|
|
431
|
-
phase: 'B',
|
|
432
|
-
description: '統合テスト',
|
|
433
|
-
},
|
|
434
|
-
e2e: {
|
|
435
|
-
enabled: answers.testTypes.includes('e2e'),
|
|
436
|
-
required: false,
|
|
437
|
-
phase: 'B',
|
|
438
|
-
description: 'E2Eテスト',
|
|
439
|
-
},
|
|
440
|
-
performance: {
|
|
441
|
-
enabled: answers.testTypes.includes('performance'),
|
|
442
|
-
required: false,
|
|
443
|
-
phase: 'B',
|
|
444
|
-
description: '性能テスト',
|
|
445
|
-
},
|
|
446
|
-
security: {
|
|
447
|
-
enabled: answers.testTypes.includes('security'),
|
|
448
|
-
required: false,
|
|
449
|
-
phase: 'B',
|
|
450
|
-
description: 'セキュリティテスト',
|
|
451
|
-
},
|
|
452
|
-
},
|
|
453
|
-
};
|
|
454
|
-
// ディレクトリが存在しない場合は作成
|
|
455
|
-
if (!existsSync(specDir)) {
|
|
456
|
-
mkdirSync(specDir, { recursive: true });
|
|
457
|
-
}
|
|
458
|
-
// 選択結果を保存
|
|
459
|
-
writeFileSync(selectionPath, JSON.stringify(selection, null, 2), 'utf-8');
|
|
460
|
-
console.log(`\n✅ テストタイプ選択を保存しました: ${selectionPath}`);
|
|
461
|
-
// spec.jsonを更新
|
|
462
|
-
try {
|
|
463
|
-
const specPath = join(specDir, 'spec.json');
|
|
464
|
-
if (existsSync(specPath)) {
|
|
465
|
-
const spec = JSON.parse(readFileSync(specPath, 'utf-8'));
|
|
466
|
-
spec.testTypeSelection = {
|
|
467
|
-
completed: true,
|
|
468
|
-
selectedTypes: answers.testTypes,
|
|
469
|
-
selectedAt: selection.selectedAt,
|
|
470
|
-
};
|
|
471
|
-
spec.lastUpdated = new Date().toISOString();
|
|
472
|
-
writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
|
|
473
|
-
console.log('✅ spec.jsonを更新しました');
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
catch (error) {
|
|
477
|
-
errors.push(`spec.json更新失敗: ${error.message}`);
|
|
478
|
-
console.warn(`⚠️ spec.json更新失敗: ${error.message}`);
|
|
479
|
-
}
|
|
480
|
-
// 選択結果のサマリーを表示
|
|
481
|
-
console.log('\n' + '='.repeat(60));
|
|
482
|
-
console.log('📊 選択結果サマリー:');
|
|
483
|
-
console.log(` 必須テスト: ${['unit', 'lint', 'build'].join(', ')}`);
|
|
484
|
-
const optional = answers.testTypes.filter((t) => !['unit', 'lint', 'build'].includes(t));
|
|
485
|
-
if (optional.length > 0) {
|
|
486
|
-
console.log(` 追加テスト: ${optional.join(', ')}`);
|
|
487
|
-
}
|
|
488
|
-
else {
|
|
489
|
-
console.log(' 追加テスト: なし');
|
|
490
|
-
}
|
|
491
|
-
console.log('\n📖 次のステップ:');
|
|
492
|
-
console.log(' 1. Phase 0.4: テスト仕様書作成へ進む');
|
|
493
|
-
console.log(' michi phase:run ' + feature + ' test-spec');
|
|
494
|
-
console.log(' 2. 詳細ガイド: docs/user-guide/testing/test-planning-flow.md');
|
|
495
|
-
console.log('\n' + '='.repeat(60));
|
|
496
|
-
console.log('✅ Phase 0.3: テストタイプ選択が完了しました');
|
|
497
|
-
return {
|
|
498
|
-
phase: 'test-type-selection',
|
|
499
|
-
success: true,
|
|
500
|
-
confluenceCreated: false,
|
|
501
|
-
jiraCreated: false,
|
|
502
|
-
validationPassed: true,
|
|
503
|
-
errors,
|
|
504
|
-
};
|
|
505
267
|
}
|
|
506
268
|
/**
|
|
507
|
-
*
|
|
508
|
-
* 自動生成: test-type-selectionから選択されたテストタイプの仕様書を生成
|
|
269
|
+
* タスク分割フェーズを実行
|
|
509
270
|
*/
|
|
510
|
-
async function
|
|
511
|
-
console.log('\n📝 Phase
|
|
271
|
+
async function runTasksPhase(feature) {
|
|
272
|
+
console.log('\n📝 Phase: Tasks(タスク分割)');
|
|
512
273
|
console.log('='.repeat(60));
|
|
513
274
|
const errors = [];
|
|
514
|
-
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
275
|
+
let jiraCreated = false;
|
|
276
|
+
const tasksPath = join(process.cwd(), '.kiro', 'specs', feature, 'tasks.md');
|
|
277
|
+
// 前提条件チェック
|
|
278
|
+
const prereqCheck = await checkTasksPrerequisites(feature);
|
|
279
|
+
if (!prereqCheck.valid) {
|
|
518
280
|
return {
|
|
519
|
-
phase: '
|
|
281
|
+
phase: 'tasks',
|
|
520
282
|
success: false,
|
|
521
283
|
confluenceCreated: false,
|
|
522
284
|
jiraCreated: false,
|
|
523
285
|
validationPassed: false,
|
|
524
|
-
errors,
|
|
286
|
+
errors: prereqCheck.errors,
|
|
525
287
|
};
|
|
526
288
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
testTypes = selection.selectedTypes || [];
|
|
532
|
-
}
|
|
533
|
-
catch (error) {
|
|
534
|
-
errors.push(`test-type-selection.jsonの読み込みまたはパースに失敗しました: ${error instanceof Error ? error.message : String(error)}`);
|
|
289
|
+
// AI-DLC形式検出と変換
|
|
290
|
+
const convertResult = await detectAndConvertAIDLCFormat(feature, tasksPath);
|
|
291
|
+
if (!convertResult.success) {
|
|
292
|
+
errors.push(...convertResult.errors);
|
|
535
293
|
return {
|
|
536
|
-
phase: '
|
|
294
|
+
phase: 'tasks',
|
|
537
295
|
success: false,
|
|
538
296
|
confluenceCreated: false,
|
|
539
297
|
jiraCreated: false,
|
|
@@ -541,82 +299,29 @@ async function runTestSpecPhase(feature) {
|
|
|
541
299
|
errors,
|
|
542
300
|
};
|
|
543
301
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
console.log(` ⏭️ ${testType}: スキップ(CI設定で対応)`);
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
try {
|
|
558
|
-
await generateTestSpec(feature, testType);
|
|
559
|
-
console.log(` ✅ ${testType}テスト仕様書: ${testType}-test-spec.md`);
|
|
560
|
-
generatedSpecs.push(testType);
|
|
561
|
-
}
|
|
562
|
-
catch (error) {
|
|
563
|
-
errors.push(`${testType}テスト仕様書生成失敗: ${error.message}`);
|
|
564
|
-
console.error(` ❌ ${testType}テスト仕様書生成失敗: ${error.message}`);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
// Step 3: spec.json更新
|
|
568
|
-
const specPath = join(process.cwd(), '.kiro', 'specs', feature, 'spec.json');
|
|
569
|
-
if (existsSync(specPath)) {
|
|
570
|
-
try {
|
|
571
|
-
const spec = JSON.parse(readFileSync(specPath, 'utf-8'));
|
|
572
|
-
spec.testSpecification = {
|
|
573
|
-
completed: true,
|
|
574
|
-
generatedAt: new Date().toISOString(),
|
|
575
|
-
testTypes: testTypes,
|
|
576
|
-
generatedSpecs: generatedSpecs,
|
|
577
|
-
};
|
|
578
|
-
spec.lastUpdated = new Date().toISOString();
|
|
579
|
-
writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
|
|
580
|
-
console.log('\n✅ spec.jsonを更新しました');
|
|
581
|
-
}
|
|
582
|
-
catch (error) {
|
|
583
|
-
errors.push(`spec.json更新失敗: ${error.message}`);
|
|
584
|
-
console.warn(`⚠️ spec.json更新失敗: ${error.message}`);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
// Step 4: サマリー表示
|
|
588
|
-
console.log('\n' + '='.repeat(60));
|
|
589
|
-
console.log('📊 テスト仕様書作成完了:');
|
|
590
|
-
console.log(` 生成されたファイル: ${generatedSpecs.length}件`);
|
|
591
|
-
console.log(` 保存先: .kiro/specs/${feature}/test-specs/`);
|
|
592
|
-
if (generatedSpecs.length > 0) {
|
|
593
|
-
console.log('\n📄 生成されたファイル:');
|
|
594
|
-
generatedSpecs.forEach((type) => {
|
|
595
|
-
console.log(` - ${type}-test-spec.md`);
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
console.log('\n📖 次のステップ:');
|
|
599
|
-
console.log(' 1. Phase 0.5: タスク分割へ進む');
|
|
600
|
-
console.log(` michi phase:run ${feature} tasks`);
|
|
601
|
-
console.log('\n' + '='.repeat(60));
|
|
602
|
-
console.log('✅ Phase 0.4: テスト仕様書作成が完了しました');
|
|
302
|
+
// フォーマット検証とJIRA同期
|
|
303
|
+
const syncResult = await validateTasksFormatAndSyncJIRA(feature, tasksPath);
|
|
304
|
+
jiraCreated = syncResult.jiraCreated;
|
|
305
|
+
errors.push(...syncResult.errors);
|
|
306
|
+
// バリデーション
|
|
307
|
+
console.log('\n🔍 バリデーション実行中...');
|
|
308
|
+
const validation = validatePhase(feature, 'tasks');
|
|
309
|
+
errors.push(...validation.errors);
|
|
310
|
+
// サマリー表示
|
|
311
|
+
displayTasksPhaseSummary(jiraCreated, validation);
|
|
603
312
|
return {
|
|
604
|
-
phase: '
|
|
605
|
-
success:
|
|
313
|
+
phase: 'tasks',
|
|
314
|
+
success: validation.valid && jiraCreated,
|
|
606
315
|
confluenceCreated: false,
|
|
607
|
-
jiraCreated
|
|
608
|
-
validationPassed:
|
|
316
|
+
jiraCreated,
|
|
317
|
+
validationPassed: validation.valid,
|
|
609
318
|
errors,
|
|
610
319
|
};
|
|
611
320
|
}
|
|
612
321
|
/**
|
|
613
|
-
*
|
|
614
|
-
* 対話的に環境を構築し、必要な設定ファイルを生成
|
|
322
|
+
* プロジェクト検出と言語/Docker要件を分析
|
|
615
323
|
*/
|
|
616
|
-
async function
|
|
617
|
-
console.log('\n⚙️ Phase 1: Environment Setup(環境構築)');
|
|
618
|
-
console.log('='.repeat(60));
|
|
619
|
-
const errors = [];
|
|
324
|
+
async function detectAndAnalyzeProject(feature) {
|
|
620
325
|
// Step 1: プロジェクト検出
|
|
621
326
|
const { detectProject } = await import('./utils/project-detector.js');
|
|
622
327
|
const detected = detectProject();
|
|
@@ -647,7 +352,12 @@ async function runEnvironmentSetupPhase(feature) {
|
|
|
647
352
|
console.log(` 推奨サービス: ${dockerAnalysis.suggestedServices.join(', ')}`);
|
|
648
353
|
}
|
|
649
354
|
}
|
|
650
|
-
|
|
355
|
+
return { detected, languageAnalysis, dockerAnalysis };
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* 環境構築の対話的質問を収集
|
|
359
|
+
*/
|
|
360
|
+
async function collectEnvironmentAnswers(detected, languageAnalysis, dockerAnalysis) {
|
|
651
361
|
console.log('\n📚 環境構築を対話的に設定します\n');
|
|
652
362
|
const languageMap = {
|
|
653
363
|
nodejs: 'Node.js/TypeScript',
|
|
@@ -705,23 +415,30 @@ async function runEnvironmentSetupPhase(feature) {
|
|
|
705
415
|
]);
|
|
706
416
|
// Docker Composeの推奨サービスを保存
|
|
707
417
|
answers.suggestedServices = dockerAnalysis.suggestedServices;
|
|
708
|
-
|
|
418
|
+
return answers;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* 環境構築の設定ファイルを生成
|
|
422
|
+
*/
|
|
423
|
+
async function generateEnvironmentConfigs(feature, answers, errors) {
|
|
709
424
|
console.log('\n🤖 設定ファイルを生成中...');
|
|
710
425
|
try {
|
|
711
426
|
const { generateCIConfig } = await import('./utils/ci-generator.js');
|
|
712
427
|
await generateCIConfig(feature, answers);
|
|
713
428
|
}
|
|
714
429
|
catch (error) {
|
|
715
|
-
|
|
716
|
-
|
|
430
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
431
|
+
errors.push(`CI/CD設定生成失敗: ${message}`);
|
|
432
|
+
console.error(` ❌ CI/CD設定生成失敗: ${message}`);
|
|
717
433
|
}
|
|
718
434
|
try {
|
|
719
435
|
const { generateTestConfig } = await import('./utils/test-config-generator.js');
|
|
720
436
|
await generateTestConfig(feature, answers);
|
|
721
437
|
}
|
|
722
438
|
catch (error) {
|
|
723
|
-
|
|
724
|
-
|
|
439
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
440
|
+
errors.push(`テスト設定生成失敗: ${message}`);
|
|
441
|
+
console.error(` ❌ テスト設定生成失敗: ${message}`);
|
|
725
442
|
}
|
|
726
443
|
if (answers.needsDocker) {
|
|
727
444
|
try {
|
|
@@ -729,78 +446,94 @@ async function runEnvironmentSetupPhase(feature) {
|
|
|
729
446
|
await generateDockerCompose(feature, answers.suggestedServices || []);
|
|
730
447
|
}
|
|
731
448
|
catch (error) {
|
|
732
|
-
|
|
733
|
-
|
|
449
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
450
|
+
errors.push(`Docker Compose生成失敗: ${message}`);
|
|
451
|
+
console.error(` ❌ Docker Compose生成失敗: ${message}`);
|
|
734
452
|
}
|
|
735
453
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
console.warn(' 💡 プロジェクト初期化後に手動でインストールしてください');
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
// Step 5: spec.json更新
|
|
783
|
-
const specPath = join(process.cwd(), '.kiro', 'specs', feature, 'spec.json');
|
|
784
|
-
if (existsSync(specPath)) {
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* 依存関係を自動インストール
|
|
457
|
+
*/
|
|
458
|
+
async function installDependencies(answers, detected) {
|
|
459
|
+
if (!answers.installDeps) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
console.log('\n📦 依存関係をインストール中...');
|
|
463
|
+
const { execSync } = await import('child_process');
|
|
464
|
+
// 言語別のビルドファイル存在確認
|
|
465
|
+
const buildFileChecks = {
|
|
466
|
+
'Node.js/TypeScript': 'package.json',
|
|
467
|
+
Java: 'build.gradle',
|
|
468
|
+
PHP: 'composer.json',
|
|
469
|
+
Python: 'requirements.txt',
|
|
470
|
+
Go: 'go.mod',
|
|
471
|
+
Rust: 'Cargo.toml',
|
|
472
|
+
};
|
|
473
|
+
const buildFile = buildFileChecks[answers.language];
|
|
474
|
+
if (!buildFile || !existsSync(buildFile)) {
|
|
475
|
+
console.log(` ℹ️ ${buildFile || 'ビルドファイル'}が見つかりません(スキップ)`);
|
|
476
|
+
console.log(' 💡 実際のプロジェクトでは、先にプロジェクトを初期化してください');
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
const commands = {
|
|
480
|
+
'Node.js/TypeScript': detected.packageManager === 'pnpm'
|
|
481
|
+
? 'pnpm install'
|
|
482
|
+
: detected.packageManager === 'yarn'
|
|
483
|
+
? 'yarn install'
|
|
484
|
+
: 'npm install',
|
|
485
|
+
Java: existsSync('./gradlew')
|
|
486
|
+
? './gradlew build --no-daemon'
|
|
487
|
+
: 'gradle build',
|
|
488
|
+
PHP: 'composer install',
|
|
489
|
+
Python: 'pip install -r requirements.txt',
|
|
490
|
+
Go: 'go mod download',
|
|
491
|
+
Rust: 'cargo fetch',
|
|
492
|
+
};
|
|
493
|
+
const command = commands[answers.language];
|
|
494
|
+
if (command) {
|
|
785
495
|
try {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
completed: true,
|
|
789
|
-
language: answers.language,
|
|
790
|
-
ciTool: answers.ciTool,
|
|
791
|
-
dockerCompose: answers.needsDocker,
|
|
792
|
-
completedAt: new Date().toISOString(),
|
|
793
|
-
};
|
|
794
|
-
spec.lastUpdated = new Date().toISOString();
|
|
795
|
-
writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
|
|
796
|
-
console.log('\n✅ spec.jsonを更新しました');
|
|
496
|
+
execSync(command, { stdio: 'inherit', cwd: process.cwd() });
|
|
497
|
+
console.log(' ✅ 依存関係のインストール完了');
|
|
797
498
|
}
|
|
798
499
|
catch (error) {
|
|
799
|
-
|
|
800
|
-
console.warn(
|
|
500
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
501
|
+
console.warn(` ⚠️ 依存関係インストール失敗: ${message}`);
|
|
502
|
+
console.warn(' 💡 プロジェクト初期化後に手動でインストールしてください');
|
|
801
503
|
}
|
|
802
504
|
}
|
|
803
|
-
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* spec.jsonを更新
|
|
508
|
+
*/
|
|
509
|
+
async function updateEnvironmentSpecJson(feature, answers, errors) {
|
|
510
|
+
const specPath = join(process.cwd(), '.kiro', 'specs', feature, 'spec.json');
|
|
511
|
+
if (!existsSync(specPath)) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
const spec = JSON.parse(readFileSync(specPath, 'utf-8'));
|
|
516
|
+
spec.environmentSetup = {
|
|
517
|
+
completed: true,
|
|
518
|
+
language: answers.language,
|
|
519
|
+
ciTool: answers.ciTool,
|
|
520
|
+
dockerCompose: answers.needsDocker,
|
|
521
|
+
completedAt: new Date().toISOString(),
|
|
522
|
+
};
|
|
523
|
+
spec.lastUpdated = new Date().toISOString();
|
|
524
|
+
writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
|
|
525
|
+
console.log('\n✅ spec.jsonを更新しました');
|
|
526
|
+
}
|
|
527
|
+
catch (error) {
|
|
528
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
529
|
+
errors.push(`spec.json更新失敗: ${message}`);
|
|
530
|
+
console.warn(`⚠️ spec.json更新失敗: ${message}`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* 環境構築のサマリーを表示
|
|
535
|
+
*/
|
|
536
|
+
function displayEnvironmentSummary(feature, answers) {
|
|
804
537
|
console.log('\n' + '='.repeat(60));
|
|
805
538
|
console.log('📊 環境構築完了:');
|
|
806
539
|
console.log(` 言語: ${answers.language}`);
|
|
@@ -811,6 +544,27 @@ async function runEnvironmentSetupPhase(feature) {
|
|
|
811
544
|
console.log(` /kiro:spec-impl ${feature}`);
|
|
812
545
|
console.log('\n' + '='.repeat(60));
|
|
813
546
|
console.log('✅ Phase 1: 環境構築が完了しました');
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* 環境構築フェーズを実行(Phase 1)
|
|
550
|
+
* 対話的に環境を構築し、必要な設定ファイルを生成
|
|
551
|
+
*/
|
|
552
|
+
async function runEnvironmentSetupPhase(feature) {
|
|
553
|
+
console.log('\n⚙️ Phase 1: Environment Setup(環境構築)');
|
|
554
|
+
console.log('='.repeat(60));
|
|
555
|
+
const errors = [];
|
|
556
|
+
// プロジェクト検出と分析
|
|
557
|
+
const { detected, languageAnalysis, dockerAnalysis } = await detectAndAnalyzeProject(feature);
|
|
558
|
+
// 対話的質問の収集
|
|
559
|
+
const answers = await collectEnvironmentAnswers(detected, languageAnalysis, dockerAnalysis);
|
|
560
|
+
// 設定ファイル生成
|
|
561
|
+
await generateEnvironmentConfigs(feature, answers, errors);
|
|
562
|
+
// 依存関係インストール
|
|
563
|
+
await installDependencies(answers, detected);
|
|
564
|
+
// spec.json更新
|
|
565
|
+
await updateEnvironmentSpecJson(feature, answers, errors);
|
|
566
|
+
// サマリー表示
|
|
567
|
+
displayEnvironmentSummary(feature, answers);
|
|
814
568
|
return {
|
|
815
569
|
phase: 'environment-setup',
|
|
816
570
|
success: errors.length === 0,
|
|
@@ -860,15 +614,9 @@ async function runPhaseAPhase(feature) {
|
|
|
860
614
|
};
|
|
861
615
|
}
|
|
862
616
|
/**
|
|
863
|
-
*
|
|
864
|
-
* テスト実行ファイルを自動生成し、手動テストチェックリストを表示
|
|
617
|
+
* Phase B対象のテストタイプを読み込み
|
|
865
618
|
*/
|
|
866
|
-
|
|
867
|
-
console.log('\n🔍 Phase B: リリース準備テスト(Release Tests)');
|
|
868
|
-
console.log('='.repeat(60));
|
|
869
|
-
const errors = [];
|
|
870
|
-
const generatedFiles = [];
|
|
871
|
-
// Step 1: テストタイプ選択の読み込み
|
|
619
|
+
function loadPhaseBTestTypes(feature) {
|
|
872
620
|
const selectionPath = join(process.cwd(), '.kiro', 'specs', feature, 'test-type-selection.json');
|
|
873
621
|
let selectedTypes = [];
|
|
874
622
|
if (existsSync(selectionPath)) {
|
|
@@ -893,32 +641,49 @@ async function runPhaseBPhase(feature) {
|
|
|
893
641
|
'security',
|
|
894
642
|
];
|
|
895
643
|
}
|
|
896
|
-
//
|
|
644
|
+
// Phase B対象のテストタイプを抽出(Phase Aのテストを除外)
|
|
897
645
|
const phaseBTypes = selectedTypes.filter((t) => !['unit', 'lint', 'build'].includes(t));
|
|
898
646
|
if (phaseBTypes.length > 0) {
|
|
899
647
|
console.log(`\n📝 Phase B対象テスト: ${phaseBTypes.join(', ')}`);
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
648
|
+
}
|
|
649
|
+
return phaseBTypes;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Phase Bのテスト実行ファイルを生成
|
|
653
|
+
*/
|
|
654
|
+
async function generatePhaseBTestFiles(feature, phaseBTypes) {
|
|
655
|
+
const generatedFiles = [];
|
|
656
|
+
const errors = [];
|
|
657
|
+
if (phaseBTypes.length === 0) {
|
|
658
|
+
return { generatedFiles, errors };
|
|
659
|
+
}
|
|
660
|
+
console.log('\n🤖 テスト実行ファイルを自動生成中...');
|
|
661
|
+
const { generateTestExecution } = await import('./test-execution-generator.js');
|
|
662
|
+
for (const testType of phaseBTypes) {
|
|
663
|
+
try {
|
|
664
|
+
const result = await generateTestExecution(feature, testType);
|
|
665
|
+
if (result.success) {
|
|
666
|
+
console.log(` ✅ ${result.testType}: ${result.files.length}ファイル生成`);
|
|
667
|
+
generatedFiles.push(...result.files);
|
|
914
668
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
669
|
+
else {
|
|
670
|
+
console.error(` ❌ ${result.testType}: ${result.error}`);
|
|
671
|
+
errors.push(`${result.testType}テスト生成失敗: ${result.error}`);
|
|
918
672
|
}
|
|
919
673
|
}
|
|
674
|
+
catch (error) {
|
|
675
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
676
|
+
errors.push(`${testType}テスト生成失敗: ${message}`);
|
|
677
|
+
console.error(`❌ ${testType}テスト生成失敗:`, message);
|
|
678
|
+
}
|
|
920
679
|
}
|
|
921
|
-
|
|
680
|
+
return { generatedFiles, errors };
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Phase Bのチェックリストとサマリーを表示
|
|
684
|
+
*/
|
|
685
|
+
function displayPhaseBChecklist(feature, phaseBTypes, generatedFiles, errors) {
|
|
686
|
+
// 生成されたファイルのサマリー
|
|
922
687
|
const testExecutionDir = join(process.cwd(), '.kiro', 'specs', feature, 'test-execution');
|
|
923
688
|
if (generatedFiles.length > 0) {
|
|
924
689
|
console.log('\n📄 生成されたファイル:');
|
|
@@ -927,7 +692,7 @@ async function runPhaseBPhase(feature) {
|
|
|
927
692
|
console.log(` - ${relativePath}`);
|
|
928
693
|
});
|
|
929
694
|
}
|
|
930
|
-
//
|
|
695
|
+
// チェックリスト表示
|
|
931
696
|
console.log('\n' + '='.repeat(60));
|
|
932
697
|
console.log('📋 リリース準備テストチェックリスト:\n');
|
|
933
698
|
if (phaseBTypes.includes('performance')) {
|
|
@@ -968,9 +733,23 @@ async function runPhaseBPhase(feature) {
|
|
|
968
733
|
errors.forEach((err) => console.log(` - ${err}`));
|
|
969
734
|
console.log('📢 エラーを修正してから再実行してください');
|
|
970
735
|
}
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* リリース準備テストフェーズを実行(Phase B)
|
|
739
|
+
* テスト実行ファイルを自動生成し、手動テストチェックリストを表示
|
|
740
|
+
*/
|
|
741
|
+
async function runPhaseBPhase(feature) {
|
|
742
|
+
console.log('\n🔍 Phase B: リリース準備テスト(Release Tests)');
|
|
743
|
+
console.log('='.repeat(60));
|
|
744
|
+
// Phase B対象のテストタイプを読み込み
|
|
745
|
+
const phaseBTypes = loadPhaseBTestTypes(feature);
|
|
746
|
+
// テスト実行ファイルを生成
|
|
747
|
+
const { generatedFiles, errors } = await generatePhaseBTestFiles(feature, phaseBTypes);
|
|
748
|
+
// チェックリストとサマリーを表示
|
|
749
|
+
displayPhaseBChecklist(feature, phaseBTypes, generatedFiles, errors);
|
|
971
750
|
return {
|
|
972
751
|
phase: 'phase-b',
|
|
973
|
-
success,
|
|
752
|
+
success: errors.length === 0,
|
|
974
753
|
confluenceCreated: false,
|
|
975
754
|
jiraCreated: false,
|
|
976
755
|
validationPassed: true,
|
|
@@ -988,10 +767,6 @@ export async function runPhase(feature, phase) {
|
|
|
988
767
|
return await runRequirementsPhase(feature);
|
|
989
768
|
case 'design':
|
|
990
769
|
return await runDesignPhase(feature);
|
|
991
|
-
case 'test-type-selection':
|
|
992
|
-
return await runTestTypeSelectionPhase(feature);
|
|
993
|
-
case 'test-spec':
|
|
994
|
-
return await runTestSpecPhase(feature);
|
|
995
770
|
case 'tasks':
|
|
996
771
|
return await runTasksPhase(feature);
|
|
997
772
|
case 'environment-setup':
|
|
@@ -1013,20 +788,17 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
1013
788
|
console.error('\nAvailable Phases:');
|
|
1014
789
|
console.error(' requirements - Phase 0.1: 要件定義');
|
|
1015
790
|
console.error(' design - Phase 0.2: 設計');
|
|
1016
|
-
console.error(' test-type-selection- Phase 0.3: テストタイプ選択(任意)');
|
|
1017
|
-
console.error(' test-spec - Phase 0.4: テスト仕様書作成(任意)');
|
|
1018
791
|
console.error(' tasks - Phase 0.5-0.6: タスク分割・JIRA同期');
|
|
1019
792
|
console.error(' environment-setup - Phase 1: 環境構築(任意)');
|
|
1020
793
|
console.error(' phase-a - Phase A: PR前自動テスト(任意)');
|
|
1021
794
|
console.error(' phase-b - Phase B: リリース準備テスト(任意)');
|
|
795
|
+
console.error('\nNote: For test planning (Phase 0.3-0.4), use /michi:test-planning AI command');
|
|
1022
796
|
process.exit(1);
|
|
1023
797
|
}
|
|
1024
798
|
const [feature, phase] = args;
|
|
1025
799
|
const validPhases = [
|
|
1026
800
|
'requirements',
|
|
1027
801
|
'design',
|
|
1028
|
-
'test-type-selection',
|
|
1029
|
-
'test-spec',
|
|
1030
802
|
'tasks',
|
|
1031
803
|
'environment-setup',
|
|
1032
804
|
'phase-a',
|
|
@@ -1034,7 +806,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
1034
806
|
];
|
|
1035
807
|
if (!validPhases.includes(phase)) {
|
|
1036
808
|
console.error(`Invalid phase: ${phase}`);
|
|
1037
|
-
console.error('Must be one of: requirements, design,
|
|
809
|
+
console.error('Must be one of: requirements, design, tasks, environment-setup, phase-a, phase-b');
|
|
1038
810
|
process.exit(1);
|
|
1039
811
|
}
|
|
1040
812
|
runPhase(feature, phase)
|
|
@@ -1049,7 +821,8 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
1049
821
|
}
|
|
1050
822
|
})
|
|
1051
823
|
.catch((error) => {
|
|
1052
|
-
|
|
824
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
825
|
+
console.error(`\n❌ フェーズ実行エラー: ${message}`);
|
|
1053
826
|
process.exit(1);
|
|
1054
827
|
});
|
|
1055
828
|
}
|