@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
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 設定セクションの対話的取得関数
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type * as readline from 'readline';
|
|
6
|
+
import { select, confirm, question, multiSelect } from './interactive-helpers.js';
|
|
7
|
+
import type { ProjectMetadata } from './project-meta.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Confluence階層設定
|
|
11
|
+
*/
|
|
12
|
+
export interface ConfluenceHierarchyConfig {
|
|
13
|
+
mode?: 'simple' | 'nested';
|
|
14
|
+
parentPageTitle?: string;
|
|
15
|
+
structure?: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Confluence設定結果
|
|
20
|
+
*/
|
|
21
|
+
export interface ConfluenceConfigResult {
|
|
22
|
+
pageCreationGranularity: string;
|
|
23
|
+
pageTitleFormat?: string;
|
|
24
|
+
hierarchy?: ConfluenceHierarchyConfig;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* JIRA設定結果
|
|
29
|
+
*/
|
|
30
|
+
export interface JiraConfigResult {
|
|
31
|
+
createEpic: boolean;
|
|
32
|
+
storyCreationGranularity: string;
|
|
33
|
+
selectedPhases?: string[];
|
|
34
|
+
storyPoints: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* ワークフロー設定結果
|
|
39
|
+
*/
|
|
40
|
+
export interface WorkflowConfigResult {
|
|
41
|
+
enabledPhases: string[];
|
|
42
|
+
approvalGates?: {
|
|
43
|
+
requirements?: string[];
|
|
44
|
+
design?: string[];
|
|
45
|
+
release?: string[];
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Confluence設定を対話的に取得
|
|
51
|
+
*/
|
|
52
|
+
export async function getConfluenceConfig(
|
|
53
|
+
rl: readline.Interface,
|
|
54
|
+
_projectMeta?: ProjectMetadata,
|
|
55
|
+
): Promise<ConfluenceConfigResult> {
|
|
56
|
+
console.log('\n📄 Confluence設定');
|
|
57
|
+
console.log('='.repeat(60));
|
|
58
|
+
|
|
59
|
+
const granularityChoices = [
|
|
60
|
+
{
|
|
61
|
+
value: 'single',
|
|
62
|
+
label: 'single(1ドキュメント = 1ページ)',
|
|
63
|
+
description: 'デフォルト・現在の動作',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: 'by-section',
|
|
67
|
+
label: 'by-section(セクションごとにページ分割)',
|
|
68
|
+
description: '## セクションごとにページを作成',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
value: 'by-hierarchy',
|
|
72
|
+
label: 'by-hierarchy(階層構造)',
|
|
73
|
+
description: '親ページ + 子ページの階層構造',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
value: 'manual',
|
|
77
|
+
label: 'manual(手動指定)',
|
|
78
|
+
description: '設定ファイルで明示的に指定',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const granularity = await select(
|
|
83
|
+
rl,
|
|
84
|
+
'ページ作成粒度を選択してください:',
|
|
85
|
+
granularityChoices,
|
|
86
|
+
'single',
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const config: ConfluenceConfigResult = {
|
|
90
|
+
pageCreationGranularity: granularity,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// タイトル形式のカスタマイズ
|
|
94
|
+
const customTitle = await confirm(
|
|
95
|
+
rl,
|
|
96
|
+
'ページタイトル形式をカスタマイズしますか?',
|
|
97
|
+
false,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (customTitle) {
|
|
101
|
+
const titleFormat = await question(
|
|
102
|
+
rl,
|
|
103
|
+
'タイトル形式を入力してください(例: {projectName} - {featureName}): ',
|
|
104
|
+
);
|
|
105
|
+
if (titleFormat) {
|
|
106
|
+
config.pageTitleFormat = titleFormat;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 階層構造設定
|
|
111
|
+
if (granularity === 'by-hierarchy' || granularity === 'manual') {
|
|
112
|
+
config.hierarchy = {};
|
|
113
|
+
|
|
114
|
+
if (granularity === 'by-hierarchy') {
|
|
115
|
+
const modeChoices = [
|
|
116
|
+
{
|
|
117
|
+
value: 'simple',
|
|
118
|
+
label: 'simple(親ページ + ドキュメントタイプ子ページ)',
|
|
119
|
+
description: '2階層構造',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
value: 'nested',
|
|
123
|
+
label:
|
|
124
|
+
'nested(親ページ → ドキュメントタイプ親 → セクション子ページ)',
|
|
125
|
+
description: '3階層構造',
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
const mode = await select(
|
|
130
|
+
rl,
|
|
131
|
+
'階層構造のモードを選択してください:',
|
|
132
|
+
modeChoices,
|
|
133
|
+
'simple',
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
config.hierarchy.mode = mode as 'simple' | 'nested';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const parentTitle = await question(
|
|
140
|
+
rl,
|
|
141
|
+
'親ページのタイトル形式を入力してください(例: [{projectName}] {featureName}): ',
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
if (parentTitle) {
|
|
145
|
+
config.hierarchy.parentPageTitle = parentTitle;
|
|
146
|
+
} else {
|
|
147
|
+
config.hierarchy.parentPageTitle = '[{projectName}] {featureName}';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (granularity === 'manual') {
|
|
151
|
+
console.log(
|
|
152
|
+
'\n⚠️ manualモードでは、設定ファイルを手動で編集する必要があります。',
|
|
153
|
+
);
|
|
154
|
+
console.log(
|
|
155
|
+
' hierarchy.structure に各ドキュメントタイプのページ構造を定義してください。',
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return config;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* JIRA設定を対話的に取得
|
|
165
|
+
*/
|
|
166
|
+
export async function getJiraConfig(rl: readline.Interface): Promise<JiraConfigResult> {
|
|
167
|
+
console.log('\n📋 JIRA設定');
|
|
168
|
+
console.log('='.repeat(60));
|
|
169
|
+
|
|
170
|
+
const createEpic = await confirm(rl, 'Epicを作成しますか?', true);
|
|
171
|
+
|
|
172
|
+
const granularityChoices = [
|
|
173
|
+
{
|
|
174
|
+
value: 'all',
|
|
175
|
+
label: 'all(全Storyを作成)',
|
|
176
|
+
description: 'デフォルト',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
value: 'by-phase',
|
|
180
|
+
label: 'by-phase(フェーズごとに作成)',
|
|
181
|
+
description: 'フェーズごとに個別に作成',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
value: 'selected-phases',
|
|
185
|
+
label: 'selected-phases(指定フェーズのみ)',
|
|
186
|
+
description: '選択したフェーズのみ作成',
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
const granularity = await select(
|
|
191
|
+
rl,
|
|
192
|
+
'Story作成粒度を選択してください:',
|
|
193
|
+
granularityChoices,
|
|
194
|
+
'all',
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const config: JiraConfigResult = {
|
|
198
|
+
createEpic,
|
|
199
|
+
storyCreationGranularity: granularity,
|
|
200
|
+
storyPoints: 'auto', // デフォルト値(後で上書きされる)
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
if (granularity === 'selected-phases') {
|
|
204
|
+
const phaseChoices = [
|
|
205
|
+
// 新ワークフロー構造
|
|
206
|
+
{ value: 'spec-init', label: 'Phase 0.0: プロジェクト初期化' },
|
|
207
|
+
{ value: 'requirements', label: 'Phase 0.1: 要件定義(Requirements)' },
|
|
208
|
+
{ value: 'design', label: 'Phase 0.2: 設計(Design)' },
|
|
209
|
+
{ value: 'test-type-selection', label: 'Phase 0.3: テストタイプ選択' },
|
|
210
|
+
{ value: 'test-spec', label: 'Phase 0.4: テスト仕様書作成' },
|
|
211
|
+
{ value: 'spec-tasks', label: 'Phase 0.5: タスク分割' },
|
|
212
|
+
{ value: 'environment-setup', label: 'Phase 1: 環境構築' },
|
|
213
|
+
{ value: 'implementation', label: 'Phase 2: TDD実装(Implementation)' },
|
|
214
|
+
{ value: 'phase-a', label: 'Phase A: PR前自動テスト' },
|
|
215
|
+
{ value: 'testing', label: 'Phase 3: 追加QA(Testing)' },
|
|
216
|
+
{ value: 'phase-b', label: 'Phase B: リリース準備テスト' },
|
|
217
|
+
{ value: 'release-prep', label: 'Phase 4: リリース準備(Release Preparation)' },
|
|
218
|
+
{ value: 'release', label: 'Phase 5: リリース(Release)' },
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
const selectedPhases = await multiSelect(
|
|
222
|
+
rl,
|
|
223
|
+
'作成するフェーズを選択してください:',
|
|
224
|
+
phaseChoices,
|
|
225
|
+
['implementation', 'testing'],
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
config.selectedPhases = selectedPhases;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const storyPointsChoices = [
|
|
232
|
+
{ value: 'auto', label: 'auto(自動抽出)', description: 'デフォルト' },
|
|
233
|
+
{ value: 'manual', label: 'manual(手動設定)' },
|
|
234
|
+
{ value: 'disabled', label: 'disabled(設定しない)' },
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
const storyPoints = await select(
|
|
238
|
+
rl,
|
|
239
|
+
'Story Points設定を選択してください:',
|
|
240
|
+
storyPointsChoices,
|
|
241
|
+
'auto',
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
config.storyPoints = storyPoints;
|
|
245
|
+
|
|
246
|
+
return config;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* ワークフロー設定を対話的に取得
|
|
251
|
+
*/
|
|
252
|
+
export async function getWorkflowConfig(rl: readline.Interface): Promise<WorkflowConfigResult> {
|
|
253
|
+
console.log('\n⚙️ ワークフロー設定');
|
|
254
|
+
console.log('='.repeat(60));
|
|
255
|
+
|
|
256
|
+
const phaseChoices = [
|
|
257
|
+
{ value: 'requirements', label: '要件定義(Requirements)' },
|
|
258
|
+
{ value: 'design', label: '設計(Design)' },
|
|
259
|
+
{ value: 'tasks', label: 'タスク分割(Tasks)' },
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
const enabledPhases = await multiSelect(
|
|
263
|
+
rl,
|
|
264
|
+
'有効化するフェーズを選択してください:',
|
|
265
|
+
phaseChoices,
|
|
266
|
+
['requirements', 'design', 'tasks'],
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const config: WorkflowConfigResult = {
|
|
270
|
+
enabledPhases,
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const customApprovalGates = await confirm(
|
|
274
|
+
rl,
|
|
275
|
+
'承認ゲートをカスタマイズしますか?',
|
|
276
|
+
false,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
if (customApprovalGates) {
|
|
280
|
+
config.approvalGates = {};
|
|
281
|
+
|
|
282
|
+
if (enabledPhases.includes('requirements')) {
|
|
283
|
+
const approvers = await question(
|
|
284
|
+
rl,
|
|
285
|
+
'要件定義フェーズの承認者(カンマ区切り、例: pm,director): ',
|
|
286
|
+
);
|
|
287
|
+
if (approvers) {
|
|
288
|
+
config.approvalGates.requirements = approvers
|
|
289
|
+
.split(',')
|
|
290
|
+
.map((s) => s.trim());
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (enabledPhases.includes('design')) {
|
|
295
|
+
const approvers = await question(
|
|
296
|
+
rl,
|
|
297
|
+
'設計フェーズの承認者(カンマ区切り、例: architect,director): ',
|
|
298
|
+
);
|
|
299
|
+
if (approvers) {
|
|
300
|
+
config.approvalGates.design = approvers.split(',').map((s) => s.trim());
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const releaseApprovers = await question(
|
|
305
|
+
rl,
|
|
306
|
+
'リリースフェーズの承認者(カンマ区切り、例: sm,director): ',
|
|
307
|
+
);
|
|
308
|
+
if (releaseApprovers) {
|
|
309
|
+
config.approvalGates.release = releaseApprovers
|
|
310
|
+
.split(',')
|
|
311
|
+
.map((s) => s.trim());
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return config;
|
|
316
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { existsSync, readFileSync } from 'fs';
|
|
6
6
|
import { AppConfigSchema } from '../config/config-schema.js';
|
|
7
7
|
import type { ZodIssue } from 'zod';
|
|
8
|
-
import { getConfig, getConfigPath } from './config-loader.js';
|
|
8
|
+
import { getConfig, getConfigPath, getGlobalConfigPath } from './config-loader.js';
|
|
9
9
|
import { loadProjectMeta } from './project-meta.js';
|
|
10
10
|
import {
|
|
11
11
|
getProjectIssueTypes,
|
|
@@ -528,6 +528,71 @@ export async function validateForJiraSyncAsync(
|
|
|
528
528
|
return result;
|
|
529
529
|
}
|
|
530
530
|
|
|
531
|
+
/**
|
|
532
|
+
* グローバル設定ファイルをバリデーション
|
|
533
|
+
*/
|
|
534
|
+
export function validateGlobalConfig(): ValidationResult {
|
|
535
|
+
const errors: string[] = [];
|
|
536
|
+
const warnings: string[] = [];
|
|
537
|
+
const info: string[] = [];
|
|
538
|
+
|
|
539
|
+
const globalConfigPath = getGlobalConfigPath();
|
|
540
|
+
|
|
541
|
+
if (!existsSync(globalConfigPath)) {
|
|
542
|
+
info.push('Global config file not found. This is optional.');
|
|
543
|
+
return {
|
|
544
|
+
valid: true,
|
|
545
|
+
errors: [],
|
|
546
|
+
warnings: [],
|
|
547
|
+
info,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
const content = readFileSync(globalConfigPath, 'utf-8');
|
|
553
|
+
const parsed = JSON.parse(content);
|
|
554
|
+
|
|
555
|
+
// スキーマでバリデーション
|
|
556
|
+
const result = AppConfigSchema.safeParse(parsed);
|
|
557
|
+
|
|
558
|
+
if (!result.success) {
|
|
559
|
+
result.error.issues.forEach((error: ZodIssue) => {
|
|
560
|
+
const path = error.path.map(String).join('.');
|
|
561
|
+
errors.push(`${path}: ${error.message}`);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
return {
|
|
565
|
+
valid: false,
|
|
566
|
+
errors,
|
|
567
|
+
warnings: [],
|
|
568
|
+
info: [],
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return {
|
|
573
|
+
valid: errors.length === 0,
|
|
574
|
+
errors,
|
|
575
|
+
warnings,
|
|
576
|
+
info: [],
|
|
577
|
+
};
|
|
578
|
+
} catch (error) {
|
|
579
|
+
if (error instanceof SyntaxError) {
|
|
580
|
+
errors.push(`Invalid JSON in global config: ${error.message}`);
|
|
581
|
+
} else {
|
|
582
|
+
errors.push(
|
|
583
|
+
`Error reading global config file: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return {
|
|
588
|
+
valid: false,
|
|
589
|
+
errors,
|
|
590
|
+
warnings: [],
|
|
591
|
+
info: [],
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
531
596
|
// CLI実行
|
|
532
597
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
533
598
|
const valid = validateAndReport();
|
|
@@ -56,7 +56,7 @@ export async function getApprovalStatus(
|
|
|
56
56
|
// 承認ラベルをチェック
|
|
57
57
|
// Confluenceでは通常、承認はカスタムラベルやメタデータで管理される
|
|
58
58
|
// ここでは "approved" ラベルの存在で判定
|
|
59
|
-
const hasApprovedLabel = labels.some((label:
|
|
59
|
+
const hasApprovedLabel = labels.some((label: { name: string }) =>
|
|
60
60
|
label.name === 'approved' || label.name === '承認済み'
|
|
61
61
|
);
|
|
62
62
|
|
|
@@ -97,8 +97,9 @@ export async function getApprovalStatus(
|
|
|
97
97
|
pageId,
|
|
98
98
|
pageTitle
|
|
99
99
|
};
|
|
100
|
-
} catch (error:
|
|
101
|
-
|
|
100
|
+
} catch (error: unknown) {
|
|
101
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
102
|
+
console.error('Failed to get approval status:', message);
|
|
102
103
|
throw error;
|
|
103
104
|
}
|
|
104
105
|
}
|
|
@@ -134,13 +135,14 @@ export async function pollForApproval(
|
|
|
134
135
|
|
|
135
136
|
// 次のチェックまで待機
|
|
136
137
|
await new Promise(resolve => setTimeout(resolve, interval));
|
|
137
|
-
} catch (error:
|
|
138
|
+
} catch (error: unknown) {
|
|
138
139
|
// エラーがタイムアウト以外の場合はリトライ
|
|
139
|
-
|
|
140
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
141
|
+
if (message.includes('timeout')) {
|
|
140
142
|
throw error;
|
|
141
143
|
}
|
|
142
144
|
|
|
143
|
-
console.warn('Error checking approval status, will retry:',
|
|
145
|
+
console.warn('Error checking approval status, will retry:', message);
|
|
144
146
|
await new Promise(resolve => setTimeout(resolve, interval));
|
|
145
147
|
}
|
|
146
148
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* 各パターン(single, by-section, by-hierarchy, manual)に対応
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { ConfluenceClient } from '../confluence-sync.js';
|
|
6
|
+
import type { ConfluenceClient, ConfluencePage } from '../confluence-sync.js';
|
|
7
7
|
import { convertMarkdownToConfluence, createConfluencePage } from '../markdown-to-confluence.js';
|
|
8
8
|
import type { ProjectMetadata } from './project-meta.js';
|
|
9
9
|
import type { ConfluenceConfig } from '../config/config-schema.js';
|
|
@@ -262,26 +262,26 @@ export async function createSinglePage(
|
|
|
262
262
|
|
|
263
263
|
// 既存ページを検索
|
|
264
264
|
const existingPage = await client.searchPage(spaceKey, pageTitle);
|
|
265
|
-
|
|
266
|
-
let page:
|
|
265
|
+
|
|
266
|
+
let page: ConfluencePage;
|
|
267
267
|
if (existingPage) {
|
|
268
268
|
page = await client.updatePage(
|
|
269
269
|
existingPage.id,
|
|
270
270
|
pageTitle,
|
|
271
271
|
fullContent,
|
|
272
|
-
existingPage.version
|
|
272
|
+
existingPage.version!.number
|
|
273
273
|
);
|
|
274
274
|
console.log(`✅ Page updated: ${pageTitle}`);
|
|
275
275
|
} else {
|
|
276
276
|
page = await client.createPage(spaceKey, pageTitle, fullContent, labels);
|
|
277
277
|
console.log(`✅ Page created: ${pageTitle}`);
|
|
278
278
|
}
|
|
279
|
-
|
|
279
|
+
|
|
280
280
|
const baseUrl = process.env.ATLASSIAN_URL || '';
|
|
281
281
|
return {
|
|
282
282
|
pages: [{
|
|
283
283
|
id: page.id,
|
|
284
|
-
url: `${baseUrl}/wiki${page._links
|
|
284
|
+
url: `${baseUrl}/wiki${page._links!.webui}`,
|
|
285
285
|
pageId: page.id,
|
|
286
286
|
title: pageTitle
|
|
287
287
|
}]
|
|
@@ -334,25 +334,25 @@ export async function createBySectionPages(
|
|
|
334
334
|
|
|
335
335
|
// 既存ページを検索
|
|
336
336
|
const existingPage = await client.searchPage(spaceKey, pageTitle);
|
|
337
|
-
|
|
338
|
-
let page:
|
|
337
|
+
|
|
338
|
+
let page: ConfluencePage;
|
|
339
339
|
if (existingPage) {
|
|
340
340
|
page = await client.updatePage(
|
|
341
341
|
existingPage.id,
|
|
342
342
|
pageTitle,
|
|
343
343
|
fullContent,
|
|
344
|
-
existingPage.version
|
|
344
|
+
existingPage.version!.number
|
|
345
345
|
);
|
|
346
346
|
console.log(`✅ Page updated: ${pageTitle}`);
|
|
347
347
|
} else {
|
|
348
348
|
page = await client.createPage(spaceKey, pageTitle, fullContent, labels);
|
|
349
349
|
console.log(`✅ Page created: ${pageTitle}`);
|
|
350
350
|
}
|
|
351
|
-
|
|
351
|
+
|
|
352
352
|
const baseUrl = process.env.ATLASSIAN_URL || '';
|
|
353
353
|
pages.push({
|
|
354
354
|
id: page.id,
|
|
355
|
-
url: `${baseUrl}/wiki${page._links
|
|
355
|
+
url: `${baseUrl}/wiki${page._links!.webui}`,
|
|
356
356
|
pageId: page.id,
|
|
357
357
|
title: pageTitle
|
|
358
358
|
});
|
|
@@ -449,15 +449,15 @@ export async function createByHierarchySimplePages(
|
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
}
|
|
452
|
-
|
|
453
|
-
let childPage:
|
|
452
|
+
|
|
453
|
+
let childPage: ConfluencePage;
|
|
454
454
|
if (existingChild) {
|
|
455
|
-
console.log(`📄 Found existing child page: ${existingChild.id} (version ${existingChild.version
|
|
455
|
+
console.log(`📄 Found existing child page: ${existingChild.id} (version ${existingChild.version!.number})`);
|
|
456
456
|
childPage = await client.updatePage(
|
|
457
457
|
existingChild.id,
|
|
458
458
|
childPageTitle,
|
|
459
459
|
fullContent,
|
|
460
|
-
existingChild.version
|
|
460
|
+
existingChild.version!.number
|
|
461
461
|
);
|
|
462
462
|
console.log(`✅ Child page updated: ${childPageTitle}`);
|
|
463
463
|
} else {
|
|
@@ -471,12 +471,12 @@ export async function createByHierarchySimplePages(
|
|
|
471
471
|
);
|
|
472
472
|
console.log(`✅ Child page created: ${childPageTitle} (under ${parentTitle})`);
|
|
473
473
|
}
|
|
474
|
-
|
|
474
|
+
|
|
475
475
|
const baseUrl = process.env.ATLASSIAN_URL || '';
|
|
476
476
|
return {
|
|
477
477
|
pages: [{
|
|
478
478
|
id: childPage.id,
|
|
479
|
-
url: `${baseUrl}/wiki${childPage._links
|
|
479
|
+
url: `${baseUrl}/wiki${childPage._links!.webui}`,
|
|
480
480
|
pageId: childPage.id,
|
|
481
481
|
title: childPageTitle
|
|
482
482
|
}],
|
|
@@ -588,14 +588,14 @@ export async function createByHierarchyNestedPages(
|
|
|
588
588
|
// 既存のセクションページを検索(docTypeParentIdで絞り込んで検索)
|
|
589
589
|
// これにより、同じタイトルでも別機能のページがヒットすることを防ぐ
|
|
590
590
|
const existingSectionPage = await client.searchPage(spaceKey, sectionPageTitle, docTypeParentId);
|
|
591
|
-
|
|
592
|
-
let sectionPage:
|
|
591
|
+
|
|
592
|
+
let sectionPage: ConfluencePage;
|
|
593
593
|
if (existingSectionPage) {
|
|
594
594
|
sectionPage = await client.updatePage(
|
|
595
595
|
existingSectionPage.id,
|
|
596
596
|
sectionPageTitle,
|
|
597
597
|
fullContent,
|
|
598
|
-
existingSectionPage.version
|
|
598
|
+
existingSectionPage.version!.number
|
|
599
599
|
);
|
|
600
600
|
console.log(`✅ Section page updated: ${sectionPageTitle}`);
|
|
601
601
|
} else {
|
|
@@ -608,11 +608,11 @@ export async function createByHierarchyNestedPages(
|
|
|
608
608
|
);
|
|
609
609
|
console.log(`✅ Section page created: ${sectionPageTitle} (under ${docTypeParentTitle})`);
|
|
610
610
|
}
|
|
611
|
-
|
|
611
|
+
|
|
612
612
|
const baseUrl = process.env.ATLASSIAN_URL || '';
|
|
613
613
|
pages.push({
|
|
614
614
|
id: sectionPage.id,
|
|
615
|
-
url: `${baseUrl}/wiki${sectionPage._links
|
|
615
|
+
url: `${baseUrl}/wiki${sectionPage._links!.webui}`,
|
|
616
616
|
pageId: sectionPage.id,
|
|
617
617
|
title: sectionPageTitle
|
|
618
618
|
});
|
|
@@ -731,14 +731,14 @@ export async function createManualPages(
|
|
|
731
731
|
|
|
732
732
|
// 既存ページを検索(親ページIDが指定されている場合は絞り込んで検索)
|
|
733
733
|
const existingPage = await client.searchPage(spaceKey, pageTitle, parentPageId);
|
|
734
|
-
|
|
735
|
-
let page:
|
|
734
|
+
|
|
735
|
+
let page: ConfluencePage;
|
|
736
736
|
if (existingPage) {
|
|
737
737
|
page = await client.updatePage(
|
|
738
738
|
existingPage.id,
|
|
739
739
|
pageTitle,
|
|
740
740
|
fullContent,
|
|
741
|
-
existingPage.version
|
|
741
|
+
existingPage.version!.number
|
|
742
742
|
);
|
|
743
743
|
console.log(`✅ Page updated: ${pageTitle}`);
|
|
744
744
|
} else {
|
|
@@ -756,11 +756,11 @@ export async function createManualPages(
|
|
|
756
756
|
console.log(`✅ Page created: ${pageTitle}`);
|
|
757
757
|
}
|
|
758
758
|
}
|
|
759
|
-
|
|
759
|
+
|
|
760
760
|
const baseUrl = process.env.ATLASSIAN_URL || '';
|
|
761
761
|
pages.push({
|
|
762
762
|
id: page.id,
|
|
763
|
-
url: `${baseUrl}/wiki${page._links
|
|
763
|
+
url: `${baseUrl}/wiki${page._links!.webui}`,
|
|
764
764
|
pageId: page.id,
|
|
765
765
|
title: pageTitle
|
|
766
766
|
});
|