@sk8metal/michi-cli 0.0.2 → 0.0.4
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 +26 -0
- package/README.md +37 -0
- package/dist/scripts/config/config-schema.d.ts +109 -600
- package/dist/scripts/config/config-schema.d.ts.map +1 -1
- package/dist/scripts/config/config-schema.js.map +1 -1
- package/dist/scripts/config-interactive.js +3 -3
- package/dist/scripts/confluence-sync.js +3 -3
- package/dist/scripts/create-project.js.map +1 -1
- package/dist/scripts/jira-sync.js +5 -5
- package/dist/scripts/markdown-to-confluence.js +1 -1
- package/dist/scripts/markdown-to-confluence.js.map +1 -1
- package/dist/scripts/multi-project-estimate.js +1 -1
- package/dist/scripts/phase-runner.js.map +1 -1
- package/dist/scripts/pre-flight-check.js +1 -1
- package/dist/scripts/setup-existing-project.js.map +1 -1
- package/dist/scripts/utils/config-loader.js +1 -1
- package/dist/scripts/utils/config-loader.js.map +1 -1
- package/dist/scripts/utils/config-validator.d.ts.map +1 -1
- package/dist/scripts/utils/config-validator.js +46 -46
- package/dist/scripts/utils/config-validator.js.map +1 -1
- package/dist/scripts/utils/confluence-hierarchy.d.ts.map +1 -1
- package/dist/scripts/utils/confluence-hierarchy.js +9 -8
- package/dist/scripts/utils/confluence-hierarchy.js.map +1 -1
- package/dist/scripts/validate-phase.js.map +1 -1
- package/dist/scripts/workflow-orchestrator.js.map +1 -1
- package/dist/src/cli.js +0 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +33 -0
- package/dist/vitest.config.js.map +1 -0
- package/docs/release.md +365 -0
- package/package.json +16 -12
- package/scripts/config/config-schema.ts +5 -5
- package/scripts/config-interactive.ts +3 -3
- package/scripts/confluence-sync.ts +3 -3
- package/scripts/create-project.ts +17 -17
- package/scripts/jira-sync.ts +5 -5
- package/scripts/markdown-to-confluence.ts +1 -1
- package/scripts/multi-project-estimate.ts +1 -1
- package/scripts/phase-runner.ts +8 -8
- package/scripts/pre-flight-check.ts +1 -1
- package/scripts/setup-existing-project.ts +9 -9
- package/scripts/utils/config-loader.ts +1 -1
- package/scripts/utils/config-validator.ts +47 -46
- package/scripts/utils/confluence-hierarchy.ts +52 -51
- package/scripts/validate-phase.ts +11 -11
- package/scripts/workflow-orchestrator.ts +27 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sk8metal/michi-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Managed Intelligent Comprehensive Hub for Integration - AI-driven development workflow automation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "https://github.com/sk8metalme/michi.git"
|
|
12
|
+
"url": "git+https://github.com/sk8metalme/michi.git"
|
|
13
13
|
},
|
|
14
14
|
"homepage": "https://github.com/sk8metalme/michi#readme",
|
|
15
15
|
"bugs": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"github"
|
|
30
30
|
],
|
|
31
31
|
"bin": {
|
|
32
|
-
"michi": "
|
|
32
|
+
"michi": "dist/src/cli.js"
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
|
35
35
|
"dist",
|
|
@@ -64,33 +64,37 @@
|
|
|
64
64
|
"test": "vitest",
|
|
65
65
|
"test:run": "vitest --run",
|
|
66
66
|
"test:ui": "vitest --ui",
|
|
67
|
+
"test:coverage": "vitest --run --coverage",
|
|
67
68
|
"lint": "eslint .",
|
|
68
69
|
"lint:fix": "eslint . --fix",
|
|
69
70
|
"type-check": "tsc --noEmit"
|
|
70
71
|
},
|
|
71
72
|
"dependencies": {
|
|
72
|
-
"@octokit/rest": "^
|
|
73
|
+
"@octokit/rest": "^22.0.1",
|
|
73
74
|
"axios": "^1.13.1",
|
|
74
75
|
"commander": "^14.0.2",
|
|
75
76
|
"dotenv": "^16.3.1",
|
|
76
77
|
"exceljs": "^4.4.0",
|
|
77
|
-
"googleapis": "^
|
|
78
|
+
"googleapis": "^166.0.0",
|
|
78
79
|
"jira-client": "^8.2.2",
|
|
79
80
|
"markdown-it": "^14.0.0",
|
|
80
81
|
"turndown": "^7.1.2",
|
|
81
|
-
"zod": "^
|
|
82
|
+
"zod": "^4.1.12"
|
|
82
83
|
},
|
|
83
84
|
"devDependencies": {
|
|
84
|
-
"@
|
|
85
|
-
"@types/
|
|
85
|
+
"@eslint/js": "^9.39.1",
|
|
86
|
+
"@types/markdown-it": "^14.1.2",
|
|
87
|
+
"@types/node": "^24.10.1",
|
|
86
88
|
"@types/turndown": "^5.0.4",
|
|
87
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
88
|
-
"@typescript-eslint/parser": "^
|
|
89
|
-
"eslint": "^
|
|
89
|
+
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
|
90
|
+
"@typescript-eslint/parser": "^8.46.4",
|
|
91
|
+
"eslint": "^9.39.1",
|
|
90
92
|
"prettier": "^3.1.1",
|
|
91
93
|
"tsx": "^4.7.0",
|
|
92
94
|
"typescript": "^5.3.3",
|
|
93
|
-
"
|
|
95
|
+
"typescript-eslint": "^8.46.4",
|
|
96
|
+
"vitest": "^4.0.8",
|
|
97
|
+
"@vitest/coverage-v8": "^4.0.8"
|
|
94
98
|
},
|
|
95
99
|
"engines": {
|
|
96
100
|
"node": ">=20.0.0",
|
|
@@ -86,11 +86,11 @@ export const JiraConfigSchema = z.object({
|
|
|
86
86
|
createEpic: z.boolean().default(true),
|
|
87
87
|
storyPoints: JiraStoryPointsSchema.default('auto'),
|
|
88
88
|
autoLabels: z.array(z.string()).default(['{projectLabel}', '{featureName}', '{phaseLabel}']),
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
issueTypes: z.object({
|
|
90
|
+
epic: z.string().default('Epic'),
|
|
91
|
+
story: z.string().nullish().default(null), // null | undefined | string
|
|
92
|
+
subtask: z.string().nullish().default(null) // null | undefined | string
|
|
93
|
+
}).optional(),
|
|
94
94
|
selectedPhases: z.array(z.string()).optional()
|
|
95
95
|
});
|
|
96
96
|
|
|
@@ -102,7 +102,7 @@ async function multiSelect(
|
|
|
102
102
|
console.log(` ${checked} ${index + 1}. ${choice.label}`);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
const answer = await question(rl,
|
|
105
|
+
const answer = await question(rl, '\n選択してください(カンマ区切り、例: 1,2,3): ');
|
|
106
106
|
|
|
107
107
|
if (!answer && defaults.length > 0) {
|
|
108
108
|
return defaults;
|
|
@@ -204,13 +204,13 @@ async function getConfluenceConfig(rl: readline.Interface, projectMeta: any): Pr
|
|
|
204
204
|
|
|
205
205
|
const parentTitle = await question(
|
|
206
206
|
rl,
|
|
207
|
-
|
|
207
|
+
'親ページのタイトル形式を入力してください(例: [{projectName}] {featureName}): '
|
|
208
208
|
);
|
|
209
209
|
|
|
210
210
|
if (parentTitle) {
|
|
211
211
|
config.hierarchy.parentPageTitle = parentTitle;
|
|
212
212
|
} else {
|
|
213
|
-
config.hierarchy.parentPageTitle =
|
|
213
|
+
config.hierarchy.parentPageTitle = '[{projectName}] {featureName}';
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
if (granularity === 'manual') {
|
|
@@ -107,7 +107,7 @@ class ConfluenceClient {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// CQLクエリで見つからない場合、従来の方法で検索(親ページIDでフィルタリング)
|
|
110
|
-
console.log(
|
|
110
|
+
console.log(' Falling back to standard search (may find pages in different parent)');
|
|
111
111
|
return null;
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -388,7 +388,7 @@ async function syncToConfluence(
|
|
|
388
388
|
} else if (process.env.CONFLUENCE_PRD_SPACE) {
|
|
389
389
|
console.log(`📝 Config source: environment variable (CONFLUENCE_PRD_SPACE = ${process.env.CONFLUENCE_PRD_SPACE})`);
|
|
390
390
|
} else {
|
|
391
|
-
console.log(
|
|
391
|
+
console.log('📝 Config source: default config');
|
|
392
392
|
}
|
|
393
393
|
|
|
394
394
|
// Markdownファイル読み込み
|
|
@@ -446,7 +446,7 @@ async function syncToConfluence(
|
|
|
446
446
|
console.log(`✅ Sync completed: ${result.pages.length} page(s) created/updated`);
|
|
447
447
|
|
|
448
448
|
if (result.pages.length > 1) {
|
|
449
|
-
console.log(
|
|
449
|
+
console.log('📄 Created pages:');
|
|
450
450
|
result.pages.forEach((page, index) => {
|
|
451
451
|
console.log(` ${index + 1}. ${page.title} - ${page.url}`);
|
|
452
452
|
});
|
|
@@ -38,22 +38,22 @@ function parseArgs(): ProjectConfig {
|
|
|
38
38
|
const value = args[i + 1];
|
|
39
39
|
|
|
40
40
|
switch (key) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
41
|
+
case 'name':
|
|
42
|
+
config.name = value;
|
|
43
|
+
break;
|
|
44
|
+
case 'project-name':
|
|
45
|
+
config.projectName = value;
|
|
46
|
+
break;
|
|
47
|
+
case 'jira-key':
|
|
48
|
+
config.jiraKey = value;
|
|
49
|
+
break;
|
|
50
|
+
case 'org':
|
|
51
|
+
config.org = value;
|
|
52
|
+
break;
|
|
53
|
+
case 'labels':
|
|
54
|
+
// カンマ区切りでラベル配列に変換
|
|
55
|
+
config.labels = value.split(',').map(l => l.trim());
|
|
56
|
+
break;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -133,7 +133,7 @@ async function createProject(config: ProjectConfig): Promise<void> {
|
|
|
133
133
|
|
|
134
134
|
// ハイフンが存在する場合のみサービスラベルを生成
|
|
135
135
|
if (repoName.includes('-')) {
|
|
136
|
-
|
|
136
|
+
const parts = repoName.split('-');
|
|
137
137
|
const servicePart = parts[parts.length - 1];
|
|
138
138
|
const serviceLabel = servicePart.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
139
139
|
|
package/scripts/jira-sync.ts
CHANGED
|
@@ -600,13 +600,13 @@ async function syncTasksToJIRA(featureName: string): Promise<void> {
|
|
|
600
600
|
|
|
601
601
|
// JIRA APIエラーの詳細を表示
|
|
602
602
|
if (error.response?.data) {
|
|
603
|
-
console.error(
|
|
603
|
+
console.error(' 📋 JIRA API Error Details:', JSON.stringify(error.response.data, null, 2));
|
|
604
604
|
|
|
605
605
|
// Story Pointsフィールドのエラーの場合、警告を表示
|
|
606
606
|
if (error.response.data.errors && Object.keys(error.response.data.errors).some(key => key.includes('customfield'))) {
|
|
607
|
-
console.error(
|
|
608
|
-
console.error(
|
|
609
|
-
console.error(
|
|
607
|
+
console.error(' ⚠️ Story Pointsフィールドの設定に失敗しました。');
|
|
608
|
+
console.error(' 💡 環境変数 JIRA_STORY_POINTS_FIELD を正しいカスタムフィールドIDに設定してください。');
|
|
609
|
+
console.error(' 💡 JIRA管理画面でStory PointsのカスタムフィールドIDを確認してください。');
|
|
610
610
|
}
|
|
611
611
|
}
|
|
612
612
|
|
|
@@ -618,7 +618,7 @@ async function syncTasksToJIRA(featureName: string): Promise<void> {
|
|
|
618
618
|
const newStoryCount = createdStories.filter(key => !existingStoryKeys.has(key)).length;
|
|
619
619
|
const reusedStoryCount = createdStories.filter(key => existingStoryKeys.has(key)).length;
|
|
620
620
|
|
|
621
|
-
console.log(
|
|
621
|
+
console.log('\n✅ JIRA sync completed');
|
|
622
622
|
console.log(` Epic: ${epic.key}`);
|
|
623
623
|
console.log(` Stories: ${createdStories.length} processed (${newStoryCount} new, ${reusedStoryCount} reused)`);
|
|
624
624
|
}
|
|
@@ -153,7 +153,7 @@ function parseEstimateFromContent(content: string, featureName: string): Estimat
|
|
|
153
153
|
|
|
154
154
|
return estimate;
|
|
155
155
|
} catch (error) {
|
|
156
|
-
console.warn(
|
|
156
|
+
console.warn(' ⚠️ Failed to parse estimate:', error instanceof Error ? error.message : error);
|
|
157
157
|
return null;
|
|
158
158
|
} finally {
|
|
159
159
|
// 一時ファイルをクリーンアップ
|
package/scripts/phase-runner.ts
CHANGED
|
@@ -256,14 +256,14 @@ export async function runPhase(feature: string, phase: Phase): Promise<PhaseRunR
|
|
|
256
256
|
validateFeatureNameOrThrow(feature);
|
|
257
257
|
|
|
258
258
|
switch (phase) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
259
|
+
case 'requirements':
|
|
260
|
+
return await runRequirementsPhase(feature);
|
|
261
|
+
case 'design':
|
|
262
|
+
return await runDesignPhase(feature);
|
|
263
|
+
case 'tasks':
|
|
264
|
+
return await runTasksPhase(feature);
|
|
265
|
+
default:
|
|
266
|
+
throw new Error(`Unknown phase: ${phase}`);
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
|
@@ -178,7 +178,7 @@ async function checkJiraProject(projectKey: string): Promise<{ errors: string[],
|
|
|
178
178
|
errors.push(` 現在の設定: "${projectKey}" → 実際に存在するキーに変更`);
|
|
179
179
|
} else if (error.response?.status === 401) {
|
|
180
180
|
errors.push('❌ JIRA認証エラー(.envの認証情報を確認)');
|
|
181
|
-
errors.push(
|
|
181
|
+
errors.push(' → API Token管理: https://id.atlassian.com/manage-profile/security/api-tokens');
|
|
182
182
|
} else {
|
|
183
183
|
warnings.push(`⚠️ JIRAプロジェクトチェック失敗: ${error.message}`);
|
|
184
184
|
}
|
|
@@ -30,15 +30,15 @@ function parseArgs(): SetupConfig {
|
|
|
30
30
|
const value = args[i + 1];
|
|
31
31
|
|
|
32
32
|
switch (key) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
case 'michi-path':
|
|
34
|
+
config.michiPath = value;
|
|
35
|
+
break;
|
|
36
|
+
case 'project-name':
|
|
37
|
+
config.projectName = value;
|
|
38
|
+
break;
|
|
39
|
+
case 'jira-key':
|
|
40
|
+
config.jiraKey = value;
|
|
41
|
+
break;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -192,7 +192,7 @@ export function loadConfig(projectRoot: string = process.cwd()): AppConfig {
|
|
|
192
192
|
const projectConfig = loadProjectConfig(projectRoot);
|
|
193
193
|
|
|
194
194
|
// マージ(プロジェクト設定がデフォルトを上書き)
|
|
195
|
-
|
|
195
|
+
const mergedConfig: AppConfig = projectConfig
|
|
196
196
|
? deepMerge(defaultConfig, projectConfig)
|
|
197
197
|
: defaultConfig;
|
|
198
198
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { existsSync, readFileSync } from 'fs';
|
|
6
6
|
import { resolve } from 'path';
|
|
7
7
|
import { AppConfigSchema } from '../config/config-schema.js';
|
|
8
|
+
import type { ZodIssue } from 'zod';
|
|
8
9
|
import type { AppConfig } from '../config/config-schema.js';
|
|
9
10
|
import { getConfig } from './config-loader.js';
|
|
10
11
|
|
|
@@ -47,8 +48,8 @@ export function validateProjectConfig(projectRoot: string = process.cwd()): Vali
|
|
|
47
48
|
const result = AppConfigSchema.safeParse(parsed);
|
|
48
49
|
|
|
49
50
|
if (!result.success) {
|
|
50
|
-
result.error.
|
|
51
|
-
const path = error.path.join('.');
|
|
51
|
+
result.error.issues.forEach((error: ZodIssue) => {
|
|
52
|
+
const path = error.path.map(String).join('.');
|
|
52
53
|
errors.push(`${path}: ${error.message}`);
|
|
53
54
|
});
|
|
54
55
|
|
|
@@ -196,15 +197,15 @@ export function validateForConfluenceSync(
|
|
|
196
197
|
if (!process.env.CONFLUENCE_PRD_SPACE) {
|
|
197
198
|
warnings.push(
|
|
198
199
|
`confluence.spaces.${docType}が設定されていません。` +
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
'環境変数CONFLUENCE_PRD_SPACEも設定されていないため、デフォルト値(PRD)を使用します。' +
|
|
201
|
+
'\n 推奨: .kiro/config.jsonに以下を追加してください:\n' +
|
|
202
|
+
' {\n' +
|
|
203
|
+
' "confluence": {\n' +
|
|
204
|
+
' "spaces": {\n' +
|
|
204
205
|
` "${docType}": "YOUR_SPACE_KEY"\n` +
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
' }\n' +
|
|
207
|
+
' }\n' +
|
|
208
|
+
' }'
|
|
208
209
|
);
|
|
209
210
|
} else {
|
|
210
211
|
info.push(`confluence.spaces.${docType}が設定されていませんが、環境変数CONFLUENCE_PRD_SPACE(${process.env.CONFLUENCE_PRD_SPACE})を使用します。`);
|
|
@@ -215,29 +216,29 @@ export function validateForConfluenceSync(
|
|
|
215
216
|
if (confluence.pageCreationGranularity === 'by-hierarchy' || confluence.pageCreationGranularity === 'manual') {
|
|
216
217
|
if (!confluence.hierarchy) {
|
|
217
218
|
errors.push(
|
|
218
|
-
|
|
219
|
+
'confluence.hierarchyが設定されていません。' +
|
|
219
220
|
`pageCreationGranularityが"${confluence.pageCreationGranularity}"の場合、hierarchy設定が必須です。` +
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
221
|
+
'\n 解決方法: .kiro/config.jsonに以下を追加してください:\n' +
|
|
222
|
+
' {\n' +
|
|
223
|
+
' "confluence": {\n' +
|
|
224
|
+
' "hierarchy": {\n' +
|
|
225
|
+
' "mode": "simple",\n' +
|
|
226
|
+
' "parentPageTitle": "[{projectName}] {featureName}"\n' +
|
|
227
|
+
' }\n' +
|
|
228
|
+
' }\n' +
|
|
229
|
+
' }'
|
|
229
230
|
);
|
|
230
231
|
} else if (confluence.pageCreationGranularity === 'by-hierarchy' && confluence.hierarchy && !confluence.hierarchy.parentPageTitle) {
|
|
231
232
|
warnings.push(
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
'confluence.hierarchy.parentPageTitleが設定されていません。' +
|
|
234
|
+
'by-hierarchyモードでは推奨されます。'
|
|
234
235
|
);
|
|
235
236
|
}
|
|
236
237
|
|
|
237
238
|
if (confluence.pageCreationGranularity === 'manual' && confluence.hierarchy && !confluence.hierarchy.structure) {
|
|
238
239
|
errors.push(
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
'confluence.hierarchy.structureが設定されていません。' +
|
|
241
|
+
'pageCreationGranularityが"manual"の場合、structure設定が必須です。'
|
|
241
242
|
);
|
|
242
243
|
}
|
|
243
244
|
}
|
|
@@ -274,20 +275,20 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
274
275
|
if (!jira.issueTypes) {
|
|
275
276
|
if (!process.env.JIRA_ISSUE_TYPE_STORY) {
|
|
276
277
|
errors.push(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
278
|
+
'jira.issueTypes.storyが設定されていません。' +
|
|
279
|
+
'環境変数JIRA_ISSUE_TYPE_STORYも設定されていないため、JIRA同期を実行できません。' +
|
|
280
|
+
'\n 解決方法1: 環境変数を設定:\n' +
|
|
281
|
+
' export JIRA_ISSUE_TYPE_STORY=10036 # JIRAインスタンス固有のID\n' +
|
|
282
|
+
'\n 解決方法2: .kiro/config.jsonに以下を追加:\n' +
|
|
283
|
+
' {\n' +
|
|
284
|
+
' "jira": {\n' +
|
|
285
|
+
' "issueTypes": {\n' +
|
|
286
|
+
' "story": "10036",\n' +
|
|
287
|
+
' "subtask": "10037"\n' +
|
|
288
|
+
' }\n' +
|
|
289
|
+
' }\n' +
|
|
290
|
+
' }' +
|
|
291
|
+
'\n 確認方法: JIRA管理画面(Settings > Issues > Issue types)またはREST API: GET /rest/api/3/issuetype'
|
|
291
292
|
);
|
|
292
293
|
} else {
|
|
293
294
|
info.push(`jira.issueTypes.storyが設定されていませんが、環境変数JIRA_ISSUE_TYPE_STORY(${process.env.JIRA_ISSUE_TYPE_STORY})を使用します。`);
|
|
@@ -296,10 +297,10 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
296
297
|
if (!jira.issueTypes.story) {
|
|
297
298
|
if (!process.env.JIRA_ISSUE_TYPE_STORY) {
|
|
298
299
|
errors.push(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
300
|
+
'jira.issueTypes.storyが設定されていません。' +
|
|
301
|
+
'環境変数JIRA_ISSUE_TYPE_STORYも設定されていないため、JIRA同期を実行できません。' +
|
|
302
|
+
'\n 解決方法: .kiro/config.jsonのjira.issueTypes.storyに値を設定するか、' +
|
|
303
|
+
'環境変数JIRA_ISSUE_TYPE_STORYを設定してください。'
|
|
303
304
|
);
|
|
304
305
|
} else {
|
|
305
306
|
info.push(`jira.issueTypes.storyが設定されていませんが、環境変数JIRA_ISSUE_TYPE_STORY(${process.env.JIRA_ISSUE_TYPE_STORY})を使用します。`);
|
|
@@ -309,8 +310,8 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
309
310
|
if (!jira.issueTypes.subtask) {
|
|
310
311
|
if (!process.env.JIRA_ISSUE_TYPE_SUBTASK) {
|
|
311
312
|
warnings.push(
|
|
312
|
-
|
|
313
|
-
|
|
313
|
+
'jira.issueTypes.subtaskが設定されていません。' +
|
|
314
|
+
'環境変数JIRA_ISSUE_TYPE_SUBTASKも設定されていないため、サブタスクは作成されません。'
|
|
314
315
|
);
|
|
315
316
|
} else {
|
|
316
317
|
info.push(`jira.issueTypes.subtaskが設定されていませんが、環境変数JIRA_ISSUE_TYPE_SUBTASK(${process.env.JIRA_ISSUE_TYPE_SUBTASK})を使用します。`);
|
|
@@ -321,8 +322,8 @@ export function validateForJiraSync(projectRoot: string = process.cwd()): Valida
|
|
|
321
322
|
// selectedPhases設定のチェック
|
|
322
323
|
if (jira.storyCreationGranularity === 'selected-phases' && !jira.selectedPhases) {
|
|
323
324
|
errors.push(
|
|
324
|
-
|
|
325
|
-
|
|
325
|
+
'jira.selectedPhasesが設定されていません。' +
|
|
326
|
+
'storyCreationGranularityが"selected-phases"の場合、selectedPhases設定が必須です。'
|
|
326
327
|
);
|
|
327
328
|
}
|
|
328
329
|
|
|
@@ -401,7 +401,7 @@ export async function createByHierarchySimplePages(
|
|
|
401
401
|
|
|
402
402
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
403
403
|
if (!childPageTitle.includes(featureName)) {
|
|
404
|
-
console.warn(
|
|
404
|
+
console.warn('⚠️ Warning: pageTitleFormat does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
405
405
|
childPageTitle = `[${featureName}] ${childPageTitle}`;
|
|
406
406
|
}
|
|
407
407
|
|
|
@@ -423,7 +423,7 @@ export async function createByHierarchySimplePages(
|
|
|
423
423
|
|
|
424
424
|
// CQLクエリで見つからない場合、親ページIDなしで検索(既存ページが別の親の下にある可能性)
|
|
425
425
|
if (!existingChild) {
|
|
426
|
-
console.log(
|
|
426
|
+
console.log(' CQL search found nothing, trying search without parent filter');
|
|
427
427
|
existingChild = await client.searchPage(spaceKey, childPageTitle);
|
|
428
428
|
if (existingChild) {
|
|
429
429
|
console.log(` ⚠️ Found page with same title: ${existingChild.id}, verifying parent page ID`);
|
|
@@ -436,14 +436,14 @@ export async function createByHierarchySimplePages(
|
|
|
436
436
|
console.log(` ✅ Parent page ID matches (${parentPageId}), proceeding with update`);
|
|
437
437
|
} else {
|
|
438
438
|
// 親ページIDが一致しない場合、エラーをスロー
|
|
439
|
-
console.error(
|
|
439
|
+
console.error(' ❌ Parent page ID mismatch!');
|
|
440
440
|
console.error(` Expected parent: ${parentPageId}`);
|
|
441
441
|
console.error(` Actual parent: ${actualParentId || 'root (no parent)'}`);
|
|
442
442
|
console.error(` Page ID: ${existingChild.id}`);
|
|
443
443
|
throw new Error(
|
|
444
444
|
`Page conflict: Found page "${childPageTitle}" (ID: ${existingChild.id}) ` +
|
|
445
445
|
`under different parent (expected: ${parentPageId}, actual: ${actualParentId || 'root'}). ` +
|
|
446
|
-
|
|
446
|
+
'Cannot update foreign page. Please rename or delete the conflicting page.'
|
|
447
447
|
);
|
|
448
448
|
}
|
|
449
449
|
}
|
|
@@ -523,7 +523,7 @@ export async function createByHierarchyNestedPages(
|
|
|
523
523
|
|
|
524
524
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
525
525
|
if (!docTypeParentTitle.includes(featureName)) {
|
|
526
|
-
console.warn(
|
|
526
|
+
console.warn('⚠️ Warning: pageTitleFormat does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
527
527
|
docTypeParentTitle = `[${featureName}] ${docTypeParentTitle}`;
|
|
528
528
|
}
|
|
529
529
|
|
|
@@ -569,7 +569,7 @@ export async function createByHierarchyNestedPages(
|
|
|
569
569
|
|
|
570
570
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
571
571
|
if (!sectionPageTitle.includes(featureName)) {
|
|
572
|
-
console.warn(
|
|
572
|
+
console.warn('⚠️ Warning: pageTitleFormat does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
573
573
|
sectionPageTitle = `[${featureName}] ${sectionPageTitle}`;
|
|
574
574
|
}
|
|
575
575
|
const confluenceContent = convertMarkdownToConfluence(section.content);
|
|
@@ -697,7 +697,7 @@ export async function createManualPages(
|
|
|
697
697
|
|
|
698
698
|
// タイトルに機能名が含まれていない場合、自動的に追加(重複を避けるため)
|
|
699
699
|
if (!pageTitle.includes(featureName)) {
|
|
700
|
-
console.warn(
|
|
700
|
+
console.warn('⚠️ Warning: Manual page title does not include {featureName}. Adding feature name to ensure uniqueness.');
|
|
701
701
|
pageTitle = `[${featureName}] ${pageTitle}`;
|
|
702
702
|
}
|
|
703
703
|
|
|
@@ -785,20 +785,34 @@ export async function createPagesByGranularity(
|
|
|
785
785
|
const granularity = config.pageCreationGranularity || 'single';
|
|
786
786
|
|
|
787
787
|
switch (granularity) {
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
788
|
+
case 'single':
|
|
789
|
+
return await createSinglePage(
|
|
790
|
+
client,
|
|
791
|
+
spaceKey,
|
|
792
|
+
markdown,
|
|
793
|
+
config,
|
|
794
|
+
projectMeta,
|
|
795
|
+
featureName,
|
|
796
|
+
docType,
|
|
797
|
+
githubUrl
|
|
798
|
+
);
|
|
799
799
|
|
|
800
|
-
|
|
801
|
-
|
|
800
|
+
case 'by-section':
|
|
801
|
+
return await createBySectionPages(
|
|
802
|
+
client,
|
|
803
|
+
spaceKey,
|
|
804
|
+
markdown,
|
|
805
|
+
config,
|
|
806
|
+
projectMeta,
|
|
807
|
+
featureName,
|
|
808
|
+
docType,
|
|
809
|
+
githubUrl
|
|
810
|
+
);
|
|
811
|
+
|
|
812
|
+
case 'by-hierarchy': {
|
|
813
|
+
const hierarchyMode = config.hierarchy?.mode || 'simple';
|
|
814
|
+
if (hierarchyMode === 'nested') {
|
|
815
|
+
return await createByHierarchyNestedPages(
|
|
802
816
|
client,
|
|
803
817
|
spaceKey,
|
|
804
818
|
markdown,
|
|
@@ -808,35 +822,8 @@ export async function createPagesByGranularity(
|
|
|
808
822
|
docType,
|
|
809
823
|
githubUrl
|
|
810
824
|
);
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
const hierarchyMode = config.hierarchy?.mode || 'simple';
|
|
814
|
-
if (hierarchyMode === 'nested') {
|
|
815
|
-
return await createByHierarchyNestedPages(
|
|
816
|
-
client,
|
|
817
|
-
spaceKey,
|
|
818
|
-
markdown,
|
|
819
|
-
config,
|
|
820
|
-
projectMeta,
|
|
821
|
-
featureName,
|
|
822
|
-
docType,
|
|
823
|
-
githubUrl
|
|
824
|
-
);
|
|
825
|
-
} else {
|
|
826
|
-
return await createByHierarchySimplePages(
|
|
827
|
-
client,
|
|
828
|
-
spaceKey,
|
|
829
|
-
markdown,
|
|
830
|
-
config,
|
|
831
|
-
projectMeta,
|
|
832
|
-
featureName,
|
|
833
|
-
docType,
|
|
834
|
-
githubUrl
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
case 'manual':
|
|
839
|
-
return await createManualPages(
|
|
825
|
+
} else {
|
|
826
|
+
return await createByHierarchySimplePages(
|
|
840
827
|
client,
|
|
841
828
|
spaceKey,
|
|
842
829
|
markdown,
|
|
@@ -846,9 +833,23 @@ export async function createPagesByGranularity(
|
|
|
846
833
|
docType,
|
|
847
834
|
githubUrl
|
|
848
835
|
);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
case 'manual':
|
|
840
|
+
return await createManualPages(
|
|
841
|
+
client,
|
|
842
|
+
spaceKey,
|
|
843
|
+
markdown,
|
|
844
|
+
config,
|
|
845
|
+
projectMeta,
|
|
846
|
+
featureName,
|
|
847
|
+
docType,
|
|
848
|
+
githubUrl
|
|
849
|
+
);
|
|
849
850
|
|
|
850
|
-
|
|
851
|
-
|
|
851
|
+
default:
|
|
852
|
+
throw new Error(`Unknown page creation granularity: ${granularity}`);
|
|
852
853
|
}
|
|
853
854
|
}
|
|
854
855
|
|