@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.
- package/CHANGELOG.md +65 -0
- 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/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.js +1 -1
- 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/config-loader.d.ts +7 -2
- package/dist/scripts/utils/config-loader.d.ts.map +1 -1
- package/dist/scripts/utils/config-loader.js +79 -8
- 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/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/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/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/claude.test.js +8 -8
- package/dist/src/__tests__/integration/setup/claude.test.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 +29 -21
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/init.d.ts +28 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +490 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/setup-existing.d.ts +1 -1
- package/dist/src/commands/setup-existing.d.ts.map +1 -1
- package/dist/src/commands/setup-existing.js +49 -3
- package/dist/src/commands/setup-existing.js.map +1 -1
- package/docs/user-guide/getting-started/new-repository-setup.md +1 -1
- package/docs/user-guide/getting-started/setup.md +33 -5
- package/docs/user-guide/guides/agent-skills-integration.md +16 -11
- 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 +192 -50
- package/docs/user-guide/hands-on/claude-setup.md +63 -9
- package/docs/user-guide/hands-on/cursor-setup.md +9 -8
- package/docs/user-guide/hands-on/verification-checklist.md +4 -3
- package/docs/user-guide/hands-on/workflow-walkthrough.md +3 -3
- package/docs/user-guide/reference/config.md +30 -5
- package/docs/user-guide/reference/quick-reference.md +70 -74
- package/docs/user-guide/testing/test-planning-flow.md +4 -0
- package/package.json +2 -4
- 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/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 +1 -1
- 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/config-loader.ts +107 -26
- 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/interactive-helpers.ts +135 -0
- package/scripts/utils/jira-issue-type-fetcher.ts +29 -21
- package/scripts/utils/release-notes-generator.ts +3 -2
- 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 +4 -0
- 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/michi/cc-sdd-overrides/README.md +58 -0
- package/templates/michi/cc-sdd-overrides/settings/rules/design-review-michi.md +53 -0
- package/templates/michi/cc-sdd-overrides/settings/templates/specs/init.json +24 -0
- package/templates/michi/cc-sdd-overrides/settings/templates/specs/tasks.md +446 -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
|
@@ -16,6 +16,13 @@ interface PreFlightResult {
|
|
|
16
16
|
warnings: string[];
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
interface ProjectMeta {
|
|
20
|
+
projectId?: string;
|
|
21
|
+
projectName?: string;
|
|
22
|
+
jiraProjectKey?: string;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
/**
|
|
20
27
|
* .env設定をチェック
|
|
21
28
|
*/
|
|
@@ -78,7 +85,7 @@ function checkProjectJson(): { errors: string[], warnings: string[] } {
|
|
|
78
85
|
return { errors, warnings };
|
|
79
86
|
}
|
|
80
87
|
|
|
81
|
-
let projectMeta:
|
|
88
|
+
let projectMeta: ProjectMeta;
|
|
82
89
|
try {
|
|
83
90
|
projectMeta = JSON.parse(readFileSync(projectJsonPath, 'utf-8'));
|
|
84
91
|
} catch {
|
|
@@ -125,16 +132,18 @@ async function checkConfluenceSpace(spaceKey: string): Promise<{ errors: string[
|
|
|
125
132
|
if (response.data) {
|
|
126
133
|
console.log(` ✅ Confluenceスペース確認: ${spaceKey} (${response.data.name})`);
|
|
127
134
|
}
|
|
128
|
-
} catch (error:
|
|
129
|
-
|
|
135
|
+
} catch (error: unknown) {
|
|
136
|
+
const isAxiosError = axios.isAxiosError(error);
|
|
137
|
+
if (isAxiosError && error.response?.status === 404) {
|
|
130
138
|
errors.push(`❌ Confluenceスペースが存在しません: ${spaceKey}`);
|
|
131
139
|
errors.push(` → Confluenceで新しいスペースを作成: ${url}/wiki/spaces`);
|
|
132
140
|
errors.push(' → または、.envのCONFLUENCE_PRD_SPACEを修正してください');
|
|
133
|
-
} else if (error.response?.status === 401) {
|
|
141
|
+
} else if (isAxiosError && error.response?.status === 401) {
|
|
134
142
|
errors.push('❌ Confluence認証エラー(.envの認証情報を確認)');
|
|
135
143
|
errors.push(` → API Token管理: ${url.replace('atlassian.net', 'atlassian.net/manage/profile/security/api-tokens')}`);
|
|
136
144
|
} else {
|
|
137
|
-
|
|
145
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
146
|
+
warnings.push(`⚠️ Confluenceスペースチェック失敗: ${message}`);
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
149
|
|
|
@@ -169,18 +178,20 @@ async function checkJiraProject(projectKey: string): Promise<{ errors: string[],
|
|
|
169
178
|
if (response.data) {
|
|
170
179
|
console.log(` ✅ JIRAプロジェクト確認: ${projectKey} (${response.data.name})`);
|
|
171
180
|
}
|
|
172
|
-
} catch (error:
|
|
173
|
-
|
|
181
|
+
} catch (error: unknown) {
|
|
182
|
+
const isAxiosError = axios.isAxiosError(error);
|
|
183
|
+
if (isAxiosError && error.response?.status === 404) {
|
|
174
184
|
errors.push(`❌ JIRAプロジェクトが存在しません: ${projectKey}`);
|
|
175
185
|
errors.push(` → JIRAプロジェクト作成: ${url}/jira/projects/create`);
|
|
176
186
|
errors.push(` → プロジェクト一覧: ${url}/jira/settings/projects`);
|
|
177
187
|
errors.push(' → または、.kiro/project.jsonのjiraProjectKeyを修正してください');
|
|
178
188
|
errors.push(` 現在の設定: "${projectKey}" → 実際に存在するキーに変更`);
|
|
179
|
-
} else if (error.response?.status === 401) {
|
|
189
|
+
} else if (isAxiosError && error.response?.status === 401) {
|
|
180
190
|
errors.push('❌ JIRA認証エラー(.envの認証情報を確認)');
|
|
181
191
|
errors.push(' → API Token管理: https://id.atlassian.com/manage-profile/security/api-tokens');
|
|
182
192
|
} else {
|
|
183
|
-
|
|
193
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
194
|
+
warnings.push(`⚠️ JIRAプロジェクトチェック失敗: ${message}`);
|
|
184
195
|
}
|
|
185
196
|
}
|
|
186
197
|
|
|
@@ -142,23 +142,8 @@ echo_success "Test feature initialized"
|
|
|
142
142
|
# ========================================
|
|
143
143
|
echo_step "Testing New Phases (0.3-0.4, 1, A, B)"
|
|
144
144
|
|
|
145
|
-
# Phase 0.3:
|
|
146
|
-
|
|
147
|
-
if npm run phase:run "${TEST_FEATURE}" test-type-selection > /dev/null 2>&1; then
|
|
148
|
-
echo_success "Phase 0.3 succeeded"
|
|
149
|
-
else
|
|
150
|
-
echo_error "Phase 0.3 failed"
|
|
151
|
-
exit 1
|
|
152
|
-
fi
|
|
153
|
-
|
|
154
|
-
# Phase 0.4: テスト仕様書作成
|
|
155
|
-
echo_info "Testing Phase 0.4: test-spec"
|
|
156
|
-
if npm run phase:run "${TEST_FEATURE}" test-spec > /dev/null 2>&1; then
|
|
157
|
-
echo_success "Phase 0.4 succeeded"
|
|
158
|
-
else
|
|
159
|
-
echo_error "Phase 0.4 failed"
|
|
160
|
-
exit 1
|
|
161
|
-
fi
|
|
145
|
+
# Phase 0.3-0.4: Test planning is now handled by AI command /michi:test-planning
|
|
146
|
+
# (CLI commands removed)
|
|
162
147
|
|
|
163
148
|
# Phase 1: 環境構築
|
|
164
149
|
echo_info "Testing Phase 1: environment-setup"
|
|
@@ -192,23 +177,7 @@ fi
|
|
|
192
177
|
# ========================================
|
|
193
178
|
echo_step "Testing Phase Validations"
|
|
194
179
|
|
|
195
|
-
# Phase 0.3
|
|
196
|
-
echo_info "Validating Phase 0.3"
|
|
197
|
-
if npm run validate:phase "${TEST_FEATURE}" test-type-selection > /dev/null 2>&1; then
|
|
198
|
-
echo_success "Phase 0.3 validation passed"
|
|
199
|
-
else
|
|
200
|
-
echo_error "Phase 0.3 validation failed"
|
|
201
|
-
exit 1
|
|
202
|
-
fi
|
|
203
|
-
|
|
204
|
-
# Phase 0.4
|
|
205
|
-
echo_info "Validating Phase 0.4"
|
|
206
|
-
if npm run validate:phase "${TEST_FEATURE}" test-spec > /dev/null 2>&1; then
|
|
207
|
-
echo_success "Phase 0.4 validation passed"
|
|
208
|
-
else
|
|
209
|
-
echo_error "Phase 0.4 validation failed"
|
|
210
|
-
exit 1
|
|
211
|
-
fi
|
|
180
|
+
# Phase 0.3-0.4: Validation removed (test planning is now handled by AI command)
|
|
212
181
|
|
|
213
182
|
# Phase 1
|
|
214
183
|
echo_info "Validating Phase 1"
|
|
@@ -70,7 +70,7 @@ async function createResourceDashboard(): Promise<void> {
|
|
|
70
70
|
const { data } = await octokit.repos.getContent({
|
|
71
71
|
owner: org,
|
|
72
72
|
repo: repo.name,
|
|
73
|
-
path: `projects/${(projectEntry as
|
|
73
|
+
path: `projects/${(projectEntry as { name: string }).name}/.kiro/project.json`
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
if ('content' in data) {
|
|
@@ -154,16 +154,16 @@ async function createResourceDashboard(): Promise<void> {
|
|
|
154
154
|
existingPage.id,
|
|
155
155
|
pageTitle,
|
|
156
156
|
dashboardContent,
|
|
157
|
-
existingPage.version
|
|
157
|
+
existingPage.version!.number
|
|
158
158
|
);
|
|
159
159
|
const baseUrl = process.env.ATLASSIAN_URL || '';
|
|
160
|
-
pageUrl = `${baseUrl}/wiki${updated._links
|
|
160
|
+
pageUrl = `${baseUrl}/wiki${updated._links!.webui}`;
|
|
161
161
|
console.log(`✅ Dashboard page updated: ${pageUrl}`);
|
|
162
162
|
} else {
|
|
163
163
|
// 新規ページを作成
|
|
164
164
|
const created = await client.createPage(spaceKey, pageTitle, dashboardContent, ['dashboard', 'resource-management']);
|
|
165
165
|
const baseUrl = process.env.ATLASSIAN_URL || '';
|
|
166
|
-
pageUrl = `${baseUrl}/wiki${created._links
|
|
166
|
+
pageUrl = `${baseUrl}/wiki${created._links!.webui}`;
|
|
167
167
|
console.log(`✅ Dashboard page created: ${pageUrl}`);
|
|
168
168
|
}
|
|
169
169
|
} catch (error) {
|
|
@@ -299,7 +299,7 @@ ${jiraLink}
|
|
|
299
299
|
// 2. Epic と Story を「レビュー待ち」に遷移
|
|
300
300
|
try {
|
|
301
301
|
await transitionEpicAndStory(jiraInfo, statusMapping.readyForReview);
|
|
302
|
-
} catch (
|
|
302
|
+
} catch (_error) {
|
|
303
303
|
console.error(
|
|
304
304
|
`⚠️ JIRA ステータス更新に失敗しましたが、PR は作成されています: ${prUrl}`,
|
|
305
305
|
);
|
|
@@ -120,20 +120,6 @@ function question(rl: readline.Interface, query: string): Promise<string> {
|
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
/**
|
|
124
|
-
* Yes/No質問
|
|
125
|
-
*/
|
|
126
|
-
async function confirm(rl: readline.Interface, prompt: string, defaultValue: boolean = true): Promise<boolean> {
|
|
127
|
-
const defaultText = defaultValue ? '[Y/n]' : '[y/N]';
|
|
128
|
-
const answer = await question(rl, `${prompt} ${defaultText}: `);
|
|
129
|
-
|
|
130
|
-
if (!answer) {
|
|
131
|
-
return defaultValue;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
|
|
135
|
-
}
|
|
136
|
-
|
|
137
123
|
/**
|
|
138
124
|
* 選択肢を表示
|
|
139
125
|
*/
|
|
@@ -676,11 +662,6 @@ async function main(): Promise<number> {
|
|
|
676
662
|
console.log('Phase Bテスト(手動回帰、負荷、セキュリティ)を対話的に作成します。\n');
|
|
677
663
|
|
|
678
664
|
// テストタイプを選択
|
|
679
|
-
const testTypeChoices = TEST_TYPES.map(t => ({
|
|
680
|
-
value: t.value,
|
|
681
|
-
label: `${t.label} - ${t.description}`
|
|
682
|
-
}));
|
|
683
|
-
|
|
684
665
|
console.log('テストタイプを選択してください:');
|
|
685
666
|
TEST_TYPES.forEach((t, index) => {
|
|
686
667
|
console.log(` ${index + 1}. ${t.label}`);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { executeTests, generateTestReport } from './utils/test-runner.js';
|
|
6
|
-
import {
|
|
6
|
+
import { getCommits, generateReleaseNotes, formatReleaseNotes } from './utils/release-notes-generator.js';
|
|
7
7
|
import { getApprovalStatus } from './utils/confluence-approval.js';
|
|
8
8
|
|
|
9
9
|
async function testTestRunner() {
|
|
@@ -32,8 +32,9 @@ async function testTestRunner() {
|
|
|
32
32
|
console.log(report.substring(0, 500) + '...');
|
|
33
33
|
|
|
34
34
|
return true;
|
|
35
|
-
} catch (error:
|
|
36
|
-
|
|
35
|
+
} catch (error: unknown) {
|
|
36
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
37
|
+
console.error('❌ テストランナーエラー:', message);
|
|
37
38
|
return false;
|
|
38
39
|
}
|
|
39
40
|
}
|
|
@@ -74,8 +75,9 @@ async function testReleaseNotesGenerator() {
|
|
|
74
75
|
console.log('⚠️ コミットが見つかりませんでした');
|
|
75
76
|
return false;
|
|
76
77
|
}
|
|
77
|
-
} catch (error:
|
|
78
|
-
|
|
78
|
+
} catch (error: unknown) {
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
console.error('❌ リリースノート生成エラー:', message);
|
|
79
81
|
return false;
|
|
80
82
|
}
|
|
81
83
|
}
|
|
@@ -123,8 +125,9 @@ async function testConfluenceApproval() {
|
|
|
123
125
|
console.log(` 承認者: ${status.approvers.join(', ') || 'なし'}`);
|
|
124
126
|
|
|
125
127
|
return true;
|
|
126
|
-
} catch (error:
|
|
127
|
-
|
|
128
|
+
} catch (error: unknown) {
|
|
129
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
130
|
+
console.error('❌ Confluence承認状態確認エラー:', message);
|
|
128
131
|
return false;
|
|
129
132
|
}
|
|
130
133
|
}
|
|
@@ -208,23 +208,8 @@ fi
|
|
|
208
208
|
|
|
209
209
|
echo_info "Testing phase:run commands..."
|
|
210
210
|
|
|
211
|
-
# Phase 0.3: test-
|
|
212
|
-
|
|
213
|
-
if "$MICHI_CMD" phase:run test-feature test-type-selection > /dev/null 2>&1; then
|
|
214
|
-
echo_success "phase:run test-type-selection succeeded"
|
|
215
|
-
else
|
|
216
|
-
echo_error "phase:run test-type-selection failed"
|
|
217
|
-
exit 1
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
# Phase 0.4: test-spec
|
|
221
|
-
echo_info "Testing phase:run test-spec"
|
|
222
|
-
if "$MICHI_CMD" phase:run test-feature test-spec > /dev/null 2>&1; then
|
|
223
|
-
echo_success "phase:run test-spec succeeded"
|
|
224
|
-
else
|
|
225
|
-
echo_error "phase:run test-spec failed"
|
|
226
|
-
exit 1
|
|
227
|
-
fi
|
|
211
|
+
# Phase 0.3-0.4: test planning is now handled by AI command /michi:test-planning
|
|
212
|
+
# (CLI commands removed)
|
|
228
213
|
|
|
229
214
|
# Phase 1: environment-setup
|
|
230
215
|
echo_info "Testing phase:run environment-setup"
|
|
@@ -260,23 +245,7 @@ echo_step "Testing Validation Commands"
|
|
|
260
245
|
|
|
261
246
|
echo_info "Testing validate:phase commands..."
|
|
262
247
|
|
|
263
|
-
# Phase 0.3
|
|
264
|
-
echo_info "Validating test-type-selection"
|
|
265
|
-
if "$MICHI_CMD" validate:phase test-feature test-type-selection > /dev/null 2>&1; then
|
|
266
|
-
echo_success "validate:phase test-type-selection succeeded"
|
|
267
|
-
else
|
|
268
|
-
echo_error "validate:phase test-type-selection failed"
|
|
269
|
-
exit 1
|
|
270
|
-
fi
|
|
271
|
-
|
|
272
|
-
# Phase 0.4
|
|
273
|
-
echo_info "Validating test-spec"
|
|
274
|
-
if "$MICHI_CMD" validate:phase test-feature test-spec > /dev/null 2>&1; then
|
|
275
|
-
echo_success "validate:phase test-spec succeeded"
|
|
276
|
-
else
|
|
277
|
-
echo_error "validate:phase test-spec failed"
|
|
278
|
-
exit 1
|
|
279
|
-
fi
|
|
248
|
+
# Phase 0.3-0.4: validation removed (test planning is now handled by AI command)
|
|
280
249
|
|
|
281
250
|
# Phase 1
|
|
282
251
|
echo_info "Validating environment-setup"
|
|
@@ -8,10 +8,7 @@ import { join } from 'path';
|
|
|
8
8
|
import {
|
|
9
9
|
extractComponents,
|
|
10
10
|
extractFlows,
|
|
11
|
-
extractRequirements
|
|
12
|
-
type Component,
|
|
13
|
-
type Flow,
|
|
14
|
-
type Requirement
|
|
11
|
+
extractRequirements
|
|
15
12
|
} from './utils/markdown-parser.js';
|
|
16
13
|
import {
|
|
17
14
|
loadTestSpecTemplate,
|
|
@@ -24,9 +21,8 @@ import {
|
|
|
24
21
|
* 単体テスト仕様書を生成
|
|
25
22
|
*/
|
|
26
23
|
export async function generateUnitTestSpec(feature: string, projectRoot: string = process.cwd()): Promise<string> {
|
|
27
|
-
const requirementsPath = join(projectRoot, '.kiro', 'specs', feature, 'requirements.md');
|
|
28
24
|
const designPath = join(projectRoot, '.kiro', 'specs', feature, 'design.md');
|
|
29
|
-
|
|
25
|
+
|
|
30
26
|
if (!existsSync(designPath)) {
|
|
31
27
|
throw new Error(`design.mdが見つかりません: ${designPath}`);
|
|
32
28
|
}
|
|
@@ -229,7 +225,7 @@ export async function generateE2ETestSpec(feature: string, projectRoot: string =
|
|
|
229
225
|
'テストユーザーが作成されている',
|
|
230
226
|
'テストデータが準備されている'
|
|
231
227
|
],
|
|
232
|
-
steps: req.acceptanceCriteria.slice(0, 3).map(
|
|
228
|
+
steps: req.acceptanceCriteria.slice(0, 3).map(ac =>
|
|
233
229
|
`${ac.substring(0, 100)}...を実行`
|
|
234
230
|
),
|
|
235
231
|
expectedResults: req.acceptanceCriteria.map(ac =>
|
|
@@ -6,27 +6,45 @@
|
|
|
6
6
|
import { readFileSync, existsSync, statSync } from 'fs';
|
|
7
7
|
import { resolve, relative, isAbsolute } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { homedir } from 'os';
|
|
9
10
|
import { config } from 'dotenv';
|
|
10
11
|
import { AppConfigSchema, type AppConfig } from '../config/config-schema.js';
|
|
11
12
|
|
|
12
13
|
// 環境変数読み込み
|
|
13
14
|
config();
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* グローバル設定ファイルのパス定数
|
|
18
|
+
*/
|
|
19
|
+
const GLOBAL_CONFIG_DIR = '.michi';
|
|
20
|
+
const GLOBAL_CONFIG_FILE = 'config.json';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* グローバル設定ファイルのパスを取得
|
|
24
|
+
*/
|
|
25
|
+
export function getGlobalConfigPath(): string {
|
|
26
|
+
const home = homedir();
|
|
27
|
+
return resolve(home, GLOBAL_CONFIG_DIR, GLOBAL_CONFIG_FILE);
|
|
28
|
+
}
|
|
29
|
+
|
|
15
30
|
/**
|
|
16
31
|
* 深いマージ(Deep Merge)
|
|
17
32
|
* オブジェクトを再帰的にマージする
|
|
18
33
|
*/
|
|
19
|
-
function deepMerge<T extends Record<string,
|
|
34
|
+
function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {
|
|
20
35
|
const result = { ...target };
|
|
21
|
-
|
|
36
|
+
|
|
22
37
|
for (const key in source) {
|
|
23
38
|
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
24
|
-
result[key] = deepMerge(
|
|
39
|
+
result[key] = deepMerge(
|
|
40
|
+
(result[key] || {}) as Record<string, unknown>,
|
|
41
|
+
source[key] as Record<string, unknown>
|
|
42
|
+
) as T[Extract<keyof T, string>];
|
|
25
43
|
} else if (source[key] !== undefined) {
|
|
26
44
|
result[key] = source[key] as T[Extract<keyof T, string>];
|
|
27
45
|
}
|
|
28
46
|
}
|
|
29
|
-
|
|
47
|
+
|
|
30
48
|
return result;
|
|
31
49
|
}
|
|
32
50
|
|
|
@@ -60,7 +78,7 @@ function expandEnvVars(str: string): string {
|
|
|
60
78
|
* 設定オブジェクト内の文字列値を環境変数で展開
|
|
61
79
|
* 循環参照を防ぐため、処理済みオブジェクトを追跡
|
|
62
80
|
*/
|
|
63
|
-
function expandEnvVarsInConfig(config:
|
|
81
|
+
function expandEnvVarsInConfig(config: unknown, visited: WeakSet<object> = new WeakSet()): unknown {
|
|
64
82
|
if (typeof config === 'string') {
|
|
65
83
|
return expandEnvVars(config);
|
|
66
84
|
}
|
|
@@ -77,9 +95,9 @@ function expandEnvVarsInConfig(config: any, visited: WeakSet<object> = new WeakS
|
|
|
77
95
|
}
|
|
78
96
|
|
|
79
97
|
visited.add(config);
|
|
80
|
-
const result:
|
|
81
|
-
for (const key in config) {
|
|
82
|
-
result[key] = expandEnvVarsInConfig(config[key], visited);
|
|
98
|
+
const result: Record<string, unknown> = {};
|
|
99
|
+
for (const key in config as Record<string, unknown>) {
|
|
100
|
+
result[key] = expandEnvVarsInConfig((config as Record<string, unknown>)[key], visited);
|
|
83
101
|
}
|
|
84
102
|
visited.delete(config);
|
|
85
103
|
return result;
|
|
@@ -113,7 +131,8 @@ function loadDefaultConfig(): AppConfig {
|
|
|
113
131
|
return AppConfigSchema.parse(expanded);
|
|
114
132
|
} catch (error) {
|
|
115
133
|
if (error instanceof SyntaxError) {
|
|
116
|
-
|
|
134
|
+
// SyntaxErrorには標準的なlineやcolumnプロパティはないため、messageのみ使用
|
|
135
|
+
throw new Error(`Invalid JSON in default config file ${defaultConfigPath}: ${error.message}`);
|
|
117
136
|
}
|
|
118
137
|
if (error instanceof Error && error.name === 'ZodError') {
|
|
119
138
|
throw new Error(`Default config validation failed: ${error.message}\nFile: ${defaultConfigPath}`);
|
|
@@ -166,23 +185,23 @@ function resolveConfigPath(projectRoot: string): string {
|
|
|
166
185
|
*/
|
|
167
186
|
function loadProjectConfig(projectRoot: string = process.cwd()): Partial<AppConfig> | null {
|
|
168
187
|
const projectConfigPath = resolveConfigPath(projectRoot);
|
|
169
|
-
|
|
188
|
+
|
|
170
189
|
// パストラバーサル対策: パスを検証
|
|
171
190
|
if (!validateConfigPath(projectConfigPath, projectRoot)) {
|
|
172
191
|
throw new Error(`Invalid config path: ${projectConfigPath} is outside project root`);
|
|
173
192
|
}
|
|
174
|
-
|
|
193
|
+
|
|
175
194
|
if (!existsSync(projectConfigPath)) {
|
|
176
195
|
return null;
|
|
177
196
|
}
|
|
178
|
-
|
|
197
|
+
|
|
179
198
|
try {
|
|
180
199
|
const content = readFileSync(projectConfigPath, 'utf-8');
|
|
181
200
|
const parsed = JSON.parse(content);
|
|
182
|
-
|
|
201
|
+
|
|
183
202
|
// 環境変数を展開
|
|
184
203
|
const expanded = expandEnvVarsInConfig(parsed);
|
|
185
|
-
|
|
204
|
+
|
|
186
205
|
// 部分的な設定なので、スキーマで厳密にバリデーションしない
|
|
187
206
|
// ただし、存在するキーについては型チェック
|
|
188
207
|
return expanded as Partial<AppConfig>;
|
|
@@ -197,25 +216,63 @@ function loadProjectConfig(projectRoot: string = process.cwd()): Partial<AppConf
|
|
|
197
216
|
}
|
|
198
217
|
}
|
|
199
218
|
|
|
219
|
+
/**
|
|
220
|
+
* グローバル設定を読み込む
|
|
221
|
+
*/
|
|
222
|
+
function loadGlobalConfig(): Partial<AppConfig> | null {
|
|
223
|
+
const globalConfigPath = getGlobalConfigPath();
|
|
224
|
+
|
|
225
|
+
if (!existsSync(globalConfigPath)) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const content = readFileSync(globalConfigPath, 'utf-8');
|
|
231
|
+
const parsed = JSON.parse(content);
|
|
232
|
+
|
|
233
|
+
// 環境変数を展開
|
|
234
|
+
const expanded = expandEnvVarsInConfig(parsed);
|
|
235
|
+
|
|
236
|
+
return expanded as Partial<AppConfig>;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (error instanceof SyntaxError) {
|
|
239
|
+
console.warn(`⚠️ Invalid JSON in global config ${globalConfigPath}: ${error.message}`);
|
|
240
|
+
} else {
|
|
241
|
+
console.warn(`⚠️ Failed to load global config: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
200
247
|
/**
|
|
201
248
|
* 設定を読み込んでマージ
|
|
202
|
-
*
|
|
249
|
+
*
|
|
203
250
|
* マージ順序:
|
|
204
251
|
* 1. デフォルト設定
|
|
205
|
-
* 2.
|
|
206
|
-
* 3.
|
|
252
|
+
* 2. グローバル設定(上書き)
|
|
253
|
+
* 3. プロジェクト固有設定(上書き)
|
|
254
|
+
* 4. 環境変数(最終上書き、既存の動作を維持)
|
|
207
255
|
*/
|
|
208
256
|
export function loadConfig(projectRoot: string = process.cwd()): AppConfig {
|
|
209
257
|
// デフォルト設定を読み込み
|
|
210
258
|
const defaultConfig = loadDefaultConfig();
|
|
211
|
-
|
|
259
|
+
|
|
260
|
+
// グローバル設定を読み込み
|
|
261
|
+
const globalConfig = loadGlobalConfig();
|
|
262
|
+
|
|
212
263
|
// プロジェクト固有設定を読み込み
|
|
213
264
|
const projectConfig = loadProjectConfig(projectRoot);
|
|
214
|
-
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
265
|
+
|
|
266
|
+
// マージ(デフォルト → グローバル → プロジェクト)
|
|
267
|
+
let mergedConfig: AppConfig = defaultConfig;
|
|
268
|
+
|
|
269
|
+
if (globalConfig) {
|
|
270
|
+
mergedConfig = deepMerge(mergedConfig, globalConfig);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (projectConfig) {
|
|
274
|
+
mergedConfig = deepMerge(mergedConfig, projectConfig);
|
|
275
|
+
}
|
|
219
276
|
|
|
220
277
|
// 環境変数で最終上書き(条件付き)
|
|
221
278
|
// 注意: config.jsonにspaces設定がある場合は環境変数を無視(config.jsonを優先)
|
|
@@ -266,14 +323,16 @@ let cachedConfig: AppConfig | null = null;
|
|
|
266
323
|
let cachedProjectRoot: string | null = null;
|
|
267
324
|
let cachedConfigMtime: number | null = null;
|
|
268
325
|
let cachedDefaultConfigMtime: number | null = null;
|
|
326
|
+
let cachedGlobalConfigMtime: number | null = null;
|
|
269
327
|
|
|
270
328
|
export function getConfig(projectRoot: string = process.cwd()): AppConfig {
|
|
271
329
|
const projectConfigPath = resolveConfigPath(projectRoot);
|
|
330
|
+
const globalConfigPath = getGlobalConfigPath();
|
|
272
331
|
const currentFileUrl = import.meta.url;
|
|
273
332
|
const currentFilePath = fileURLToPath(currentFileUrl);
|
|
274
333
|
const currentDir = resolve(currentFilePath, '..');
|
|
275
334
|
const defaultConfigPath = resolve(currentDir, '../config/default-config.json');
|
|
276
|
-
|
|
335
|
+
|
|
277
336
|
// デフォルト設定ファイルの更新時刻をチェック
|
|
278
337
|
let defaultConfigChanged = false;
|
|
279
338
|
try {
|
|
@@ -295,7 +354,27 @@ export function getConfig(projectRoot: string = process.cwd()): AppConfig {
|
|
|
295
354
|
defaultConfigChanged = true;
|
|
296
355
|
cachedDefaultConfigMtime = null;
|
|
297
356
|
}
|
|
298
|
-
|
|
357
|
+
|
|
358
|
+
// グローバル設定ファイルの更新時刻をチェック
|
|
359
|
+
let globalConfigChanged = false;
|
|
360
|
+
try {
|
|
361
|
+
if (existsSync(globalConfigPath)) {
|
|
362
|
+
const globalStats = statSync(globalConfigPath);
|
|
363
|
+
if (cachedGlobalConfigMtime !== globalStats.mtimeMs) {
|
|
364
|
+
globalConfigChanged = true;
|
|
365
|
+
cachedGlobalConfigMtime = globalStats.mtimeMs;
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
if (cachedGlobalConfigMtime !== null) {
|
|
369
|
+
globalConfigChanged = true;
|
|
370
|
+
cachedGlobalConfigMtime = null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
} catch {
|
|
374
|
+
globalConfigChanged = true;
|
|
375
|
+
cachedGlobalConfigMtime = null;
|
|
376
|
+
}
|
|
377
|
+
|
|
299
378
|
// プロジェクト設定ファイルの更新時刻をチェック
|
|
300
379
|
let projectConfigChanged = false;
|
|
301
380
|
try {
|
|
@@ -317,12 +396,13 @@ export function getConfig(projectRoot: string = process.cwd()): AppConfig {
|
|
|
317
396
|
projectConfigChanged = true;
|
|
318
397
|
cachedConfigMtime = null;
|
|
319
398
|
}
|
|
320
|
-
|
|
399
|
+
|
|
321
400
|
// キャッシュが有効で、設定ファイルが変更されていない場合はキャッシュを返す
|
|
322
401
|
if (
|
|
323
402
|
cachedConfig &&
|
|
324
403
|
cachedProjectRoot === projectRoot &&
|
|
325
404
|
!defaultConfigChanged &&
|
|
405
|
+
!globalConfigChanged &&
|
|
326
406
|
!projectConfigChanged
|
|
327
407
|
) {
|
|
328
408
|
return cachedConfig;
|
|
@@ -343,6 +423,7 @@ export function clearConfigCache(): void {
|
|
|
343
423
|
cachedProjectRoot = null;
|
|
344
424
|
cachedConfigMtime = null;
|
|
345
425
|
cachedDefaultConfigMtime = null;
|
|
426
|
+
cachedGlobalConfigMtime = null;
|
|
346
427
|
}
|
|
347
428
|
|
|
348
429
|
/**
|