@sk8metal/michi-cli 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +205 -11
  3. package/dist/scripts/__tests__/create-project.test.d.ts +2 -0
  4. package/dist/scripts/__tests__/create-project.test.d.ts.map +1 -0
  5. package/dist/scripts/__tests__/create-project.test.js +247 -0
  6. package/dist/scripts/__tests__/create-project.test.js.map +1 -0
  7. package/dist/scripts/__tests__/multi-project-estimate.test.d.ts +2 -0
  8. package/dist/scripts/__tests__/multi-project-estimate.test.d.ts.map +1 -0
  9. package/dist/scripts/__tests__/multi-project-estimate.test.js +119 -0
  10. package/dist/scripts/__tests__/multi-project-estimate.test.js.map +1 -0
  11. package/dist/scripts/__tests__/setup-existing-project.test.d.ts +2 -0
  12. package/dist/scripts/__tests__/setup-existing-project.test.d.ts.map +1 -0
  13. package/dist/scripts/__tests__/setup-existing-project.test.js +129 -0
  14. package/dist/scripts/__tests__/setup-existing-project.test.js.map +1 -0
  15. package/dist/scripts/__tests__/setup-interactive.test.d.ts +2 -0
  16. package/dist/scripts/__tests__/setup-interactive.test.d.ts.map +1 -0
  17. package/dist/scripts/__tests__/setup-interactive.test.js +160 -0
  18. package/dist/scripts/__tests__/setup-interactive.test.js.map +1 -0
  19. package/dist/scripts/config/default-config.json +57 -0
  20. package/dist/scripts/confluence-sync.d.ts +4 -0
  21. package/dist/scripts/confluence-sync.d.ts.map +1 -1
  22. package/dist/scripts/confluence-sync.js +12 -23
  23. package/dist/scripts/confluence-sync.js.map +1 -1
  24. package/dist/scripts/constants/__tests__/environments.test.d.ts +2 -0
  25. package/dist/scripts/constants/__tests__/environments.test.d.ts.map +1 -0
  26. package/dist/scripts/constants/__tests__/environments.test.js +91 -0
  27. package/dist/scripts/constants/__tests__/environments.test.js.map +1 -0
  28. package/dist/scripts/constants/__tests__/languages.test.d.ts +2 -0
  29. package/dist/scripts/constants/__tests__/languages.test.d.ts.map +1 -0
  30. package/dist/scripts/constants/__tests__/languages.test.js +82 -0
  31. package/dist/scripts/constants/__tests__/languages.test.js.map +1 -0
  32. package/dist/scripts/constants/environments.d.ts +33 -0
  33. package/dist/scripts/constants/environments.d.ts.map +1 -0
  34. package/dist/scripts/constants/environments.js +49 -0
  35. package/dist/scripts/constants/environments.js.map +1 -0
  36. package/dist/scripts/constants/languages.d.ts +23 -0
  37. package/dist/scripts/constants/languages.d.ts.map +1 -0
  38. package/dist/scripts/constants/languages.js +53 -0
  39. package/dist/scripts/constants/languages.js.map +1 -0
  40. package/dist/scripts/create-project.d.ts +4 -0
  41. package/dist/scripts/create-project.d.ts.map +1 -1
  42. package/dist/scripts/create-project.js +227 -137
  43. package/dist/scripts/create-project.js.map +1 -1
  44. package/dist/scripts/jira-sync.d.ts.map +1 -1
  45. package/dist/scripts/jira-sync.js +15 -0
  46. package/dist/scripts/jira-sync.js.map +1 -1
  47. package/dist/scripts/list-projects.d.ts.map +1 -1
  48. package/dist/scripts/list-projects.js +42 -15
  49. package/dist/scripts/list-projects.js.map +1 -1
  50. package/dist/scripts/multi-project-estimate.d.ts.map +1 -1
  51. package/dist/scripts/multi-project-estimate.js +56 -21
  52. package/dist/scripts/multi-project-estimate.js.map +1 -1
  53. package/dist/scripts/resource-dashboard.d.ts.map +1 -1
  54. package/dist/scripts/resource-dashboard.js +74 -17
  55. package/dist/scripts/resource-dashboard.js.map +1 -1
  56. package/dist/scripts/setup-existing-project.d.ts +3 -1
  57. package/dist/scripts/setup-existing-project.d.ts.map +1 -1
  58. package/dist/scripts/setup-existing-project.js +306 -217
  59. package/dist/scripts/setup-existing-project.js.map +1 -1
  60. package/dist/scripts/setup-interactive.d.ts +10 -0
  61. package/dist/scripts/setup-interactive.d.ts.map +1 -0
  62. package/dist/scripts/setup-interactive.js +413 -0
  63. package/dist/scripts/setup-interactive.js.map +1 -0
  64. package/dist/scripts/template/__tests__/renderer.test.d.ts +2 -0
  65. package/dist/scripts/template/__tests__/renderer.test.d.ts.map +1 -0
  66. package/dist/scripts/template/__tests__/renderer.test.js +165 -0
  67. package/dist/scripts/template/__tests__/renderer.test.js.map +1 -0
  68. package/dist/scripts/template/renderer.d.ts +70 -0
  69. package/dist/scripts/template/renderer.d.ts.map +1 -0
  70. package/dist/scripts/template/renderer.js +99 -0
  71. package/dist/scripts/template/renderer.js.map +1 -0
  72. package/dist/scripts/utils/__tests__/config-validator.test.js +5 -0
  73. package/dist/scripts/utils/__tests__/config-validator.test.js.map +1 -1
  74. package/dist/scripts/utils/__tests__/spec-updater.test.d.ts +5 -0
  75. package/dist/scripts/utils/__tests__/spec-updater.test.d.ts.map +1 -0
  76. package/dist/scripts/utils/__tests__/spec-updater.test.js +158 -0
  77. package/dist/scripts/utils/__tests__/spec-updater.test.js.map +1 -0
  78. package/dist/scripts/utils/confluence-hierarchy.d.ts +2 -1
  79. package/dist/scripts/utils/confluence-hierarchy.d.ts.map +1 -1
  80. package/dist/scripts/utils/confluence-hierarchy.js +5 -0
  81. package/dist/scripts/utils/confluence-hierarchy.js.map +1 -1
  82. package/dist/scripts/utils/project-finder.d.ts +30 -0
  83. package/dist/scripts/utils/project-finder.d.ts.map +1 -0
  84. package/dist/scripts/utils/project-finder.js +147 -0
  85. package/dist/scripts/utils/project-finder.js.map +1 -0
  86. package/dist/scripts/utils/spec-updater.d.ts +72 -0
  87. package/dist/scripts/utils/spec-updater.d.ts.map +1 -0
  88. package/dist/scripts/utils/spec-updater.js +141 -0
  89. package/dist/scripts/utils/spec-updater.js.map +1 -0
  90. package/dist/scripts/utils/template-finder.d.ts +37 -0
  91. package/dist/scripts/utils/template-finder.d.ts.map +1 -0
  92. package/dist/scripts/utils/template-finder.js +63 -0
  93. package/dist/scripts/utils/template-finder.js.map +1 -0
  94. package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts +5 -0
  95. package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts.map +1 -0
  96. package/dist/src/__tests__/integration/setup/claude-agent.test.js +125 -0
  97. package/dist/src/__tests__/integration/setup/claude-agent.test.js.map +1 -0
  98. package/dist/src/__tests__/integration/setup/claude.test.d.ts +5 -0
  99. package/dist/src/__tests__/integration/setup/claude.test.d.ts.map +1 -0
  100. package/dist/src/__tests__/integration/setup/claude.test.js +111 -0
  101. package/dist/src/__tests__/integration/setup/claude.test.js.map +1 -0
  102. package/dist/src/__tests__/integration/setup/cursor.test.d.ts +5 -0
  103. package/dist/src/__tests__/integration/setup/cursor.test.d.ts.map +1 -0
  104. package/dist/src/__tests__/integration/setup/cursor.test.js +162 -0
  105. package/dist/src/__tests__/integration/setup/cursor.test.js.map +1 -0
  106. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts +32 -0
  107. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts.map +1 -0
  108. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js +72 -0
  109. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js.map +1 -0
  110. package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts +38 -0
  111. package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts.map +1 -0
  112. package/dist/src/__tests__/integration/setup/helpers/test-project.js +83 -0
  113. package/dist/src/__tests__/integration/setup/helpers/test-project.js.map +1 -0
  114. package/dist/src/__tests__/integration/setup/validation.test.d.ts +5 -0
  115. package/dist/src/__tests__/integration/setup/validation.test.d.ts.map +1 -0
  116. package/dist/src/__tests__/integration/setup/validation.test.js +318 -0
  117. package/dist/src/__tests__/integration/setup/validation.test.js.map +1 -0
  118. package/dist/src/cli.d.ts.map +1 -1
  119. package/dist/src/cli.js +20 -0
  120. package/dist/src/cli.js.map +1 -1
  121. package/dist/src/commands/setup-existing.d.ts +22 -0
  122. package/dist/src/commands/setup-existing.d.ts.map +1 -0
  123. package/dist/src/commands/setup-existing.js +408 -0
  124. package/dist/src/commands/setup-existing.js.map +1 -0
  125. package/dist/vitest.config.d.ts.map +1 -1
  126. package/dist/vitest.config.js +9 -6
  127. package/dist/vitest.config.js.map +1 -1
  128. package/docs/README.md +2 -2
  129. package/docs/contributing/development.md +37 -0
  130. package/docs/getting-started/{new-project-setup.md → new-repository-setup.md} +165 -38
  131. package/docs/getting-started/quick-start.md +57 -6
  132. package/docs/getting-started/setup.md +551 -180
  133. package/docs/guides/customization.md +4 -4
  134. package/docs/guides/multi-project.md +12 -9
  135. package/docs/reference/quick-reference.md +27 -18
  136. package/docs/testing/integration-tests.md +297 -0
  137. package/docs/testing-strategy.md +87 -0
  138. package/package.json +23 -6
  139. package/scripts/__tests__/create-project.test.ts +292 -0
  140. package/scripts/__tests__/multi-project-estimate.test.ts +145 -0
  141. package/scripts/__tests__/setup-existing-project.test.ts +147 -0
  142. package/scripts/__tests__/setup-interactive.test.ts +199 -0
  143. package/scripts/confluence-sync.ts +17 -29
  144. package/scripts/constants/__tests__/environments.test.ts +110 -0
  145. package/scripts/constants/__tests__/languages.test.ts +100 -0
  146. package/scripts/constants/environments.ts +61 -0
  147. package/scripts/constants/languages.ts +70 -0
  148. package/scripts/copy-static-assets.js +50 -0
  149. package/scripts/create-project.ts +251 -158
  150. package/scripts/jira-sync.ts +16 -1
  151. package/scripts/list-projects.ts +51 -24
  152. package/scripts/multi-project-estimate.ts +58 -22
  153. package/scripts/resource-dashboard.ts +91 -26
  154. package/scripts/setup-existing-project.ts +350 -230
  155. package/scripts/setup-existing.sh +159 -25
  156. package/scripts/setup-interactive.ts +565 -0
  157. package/scripts/template/__tests__/renderer.test.ts +207 -0
  158. package/scripts/template/renderer.ts +133 -0
  159. package/scripts/utils/__tests__/config-validator.test.ts +6 -0
  160. package/scripts/utils/__tests__/spec-updater.test.ts +220 -0
  161. package/scripts/utils/confluence-hierarchy.ts +7 -1
  162. package/scripts/utils/project-finder.ts +184 -0
  163. package/scripts/utils/spec-updater.ts +212 -0
  164. package/scripts/utils/template-finder.ts +75 -0
  165. package/templates/claude/commands/michi/confluence-sync.md +38 -0
  166. package/templates/claude/commands/michi/project-switch.md +36 -0
  167. package/templates/claude/rules/atlassian-integration.md +35 -0
  168. package/templates/claude/rules/michi-core.md +54 -0
  169. package/templates/claude-agent/README.md +25 -0
  170. package/templates/cursor/commands/michi/confluence-sync.md +76 -0
  171. package/templates/cursor/commands/michi/project-switch.md +69 -0
  172. package/templates/cursor/rules/atlassian-mcp.mdc +188 -0
  173. package/templates/cursor/rules/github-ssot.mdc +151 -0
  174. package/templates/cursor/rules/multi-project.mdc +81 -0
  175. package/scripts/setup-env.sh +0 -52
@@ -0,0 +1,184 @@
1
+ /**
2
+ * プロジェクト検出ユーティリティ
3
+ * リポジトリルートを検出し、projects/配下のプロジェクトを検索
4
+ * 複数プロジェクトが存在する場合、選択機能を提供
5
+ */
6
+
7
+ import { existsSync, readdirSync } from 'fs';
8
+ import { resolve, join, dirname } from 'path';
9
+ import { readFileSync } from 'fs';
10
+ import type { ProjectMetadata } from './project-meta.js';
11
+
12
+ export interface ProjectLocation {
13
+ path: string;
14
+ projectId: string;
15
+ projectName: string;
16
+ jiraProjectKey: string;
17
+ }
18
+
19
+ /**
20
+ * 指定されたディレクトリに.kiro/project.jsonが存在するか確認
21
+ */
22
+ function hasProjectJson(dir: string): boolean {
23
+ const projectJsonPath = join(dir, '.kiro', 'project.json');
24
+ return existsSync(projectJsonPath);
25
+ }
26
+
27
+ /**
28
+ * プロジェクトメタデータを読み込む
29
+ */
30
+ function loadProjectMetadata(dir: string): ProjectMetadata | null {
31
+ const projectJsonPath = join(dir, '.kiro', 'project.json');
32
+
33
+ if (!existsSync(projectJsonPath)) {
34
+ return null;
35
+ }
36
+
37
+ try {
38
+ const content = readFileSync(projectJsonPath, 'utf-8');
39
+ const meta = JSON.parse(content) as ProjectMetadata;
40
+ return meta;
41
+ } catch (error) {
42
+ // パースエラーなどは無視
43
+ return null;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * 現在のディレクトリから親ディレクトリを遡って.kiro/project.jsonを検索
49
+ */
50
+ export function findCurrentProject(startDir: string = process.cwd()): ProjectLocation | null {
51
+ let currentDir = resolve(startDir);
52
+ const root = resolve('/');
53
+
54
+ while (currentDir !== root && currentDir !== dirname(currentDir)) {
55
+ if (hasProjectJson(currentDir)) {
56
+ const meta = loadProjectMetadata(currentDir);
57
+ if (meta) {
58
+ return {
59
+ path: currentDir,
60
+ projectId: meta.projectId,
61
+ projectName: meta.projectName,
62
+ jiraProjectKey: meta.jiraProjectKey
63
+ };
64
+ }
65
+ }
66
+
67
+ const parentDir = dirname(currentDir);
68
+ if (parentDir === currentDir) {
69
+ break;
70
+ }
71
+ currentDir = parentDir;
72
+ }
73
+
74
+ return null;
75
+ }
76
+
77
+ /**
78
+ * リポジトリルートを検出
79
+ * .gitディレクトリまたはprojects/ディレクトリの存在から判断
80
+ */
81
+ export function findRepositoryRoot(startDir: string = process.cwd()): string {
82
+ let currentDir = resolve(startDir);
83
+ const root = resolve('/');
84
+
85
+ while (currentDir !== root && currentDir !== dirname(currentDir)) {
86
+ // .gitディレクトリまたはprojects/ディレクトリが存在する場合、リポジトリルートと判断
87
+ if (existsSync(join(currentDir, '.git')) || existsSync(join(currentDir, 'projects'))) {
88
+ return currentDir;
89
+ }
90
+
91
+ const parentDir = dirname(currentDir);
92
+ if (parentDir === currentDir) {
93
+ break;
94
+ }
95
+ currentDir = parentDir;
96
+ }
97
+
98
+ // リポジトリルートが見つからない場合、現在のディレクトリを返す
99
+ return resolve(startDir);
100
+ }
101
+
102
+ /**
103
+ * リポジトリルートからprojects/配下の全プロジェクトを検索
104
+ * 統一されたディレクトリ構成: すべてのプロジェクトはprojects/{project-id}/配下に配置
105
+ */
106
+ export function findAllProjects(
107
+ searchDir?: string
108
+ ): ProjectLocation[] {
109
+ const projects: ProjectLocation[] = [];
110
+
111
+ // リポジトリルートを検出
112
+ const repoRoot = searchDir ? findRepositoryRoot(searchDir) : findRepositoryRoot();
113
+ const projectsDir = join(repoRoot, 'projects');
114
+
115
+ // projects/ディレクトリが存在しない場合は空配列を返す
116
+ if (!existsSync(projectsDir)) {
117
+ return projects;
118
+ }
119
+
120
+ try {
121
+ // projects/配下のディレクトリを取得
122
+ const entries = readdirSync(projectsDir, { withFileTypes: true });
123
+
124
+ for (const entry of entries) {
125
+ // 隠しディレクトリはスキップ
126
+ if (entry.name.startsWith('.')) {
127
+ continue;
128
+ }
129
+
130
+ if (entry.isDirectory()) {
131
+ const projectDir = join(projectsDir, entry.name);
132
+ // プロジェクトディレクトリに.kiro/project.jsonがあるか確認
133
+ if (hasProjectJson(projectDir)) {
134
+ const meta = loadProjectMetadata(projectDir);
135
+ if (meta) {
136
+ projects.push({
137
+ path: projectDir,
138
+ projectId: meta.projectId,
139
+ projectName: meta.projectName,
140
+ jiraProjectKey: meta.jiraProjectKey
141
+ });
142
+ }
143
+ }
144
+ }
145
+ }
146
+ } catch (error) {
147
+ // アクセス権限エラーなどは無視
148
+ }
149
+
150
+ return projects;
151
+ }
152
+
153
+ /**
154
+ * 複数プロジェクトから選択する(対話的)
155
+ */
156
+ export async function selectProject(
157
+ projects: ProjectLocation[],
158
+ question: (prompt: string) => Promise<string>
159
+ ): Promise<ProjectLocation | null> {
160
+ if (projects.length === 0) {
161
+ return null;
162
+ }
163
+
164
+ if (projects.length === 1) {
165
+ return projects[0];
166
+ }
167
+
168
+ console.log('\n📋 複数のプロジェクトが見つかりました:');
169
+ projects.forEach((project, index) => {
170
+ console.log(` ${index + 1}. ${project.projectName} (${project.projectId}) - ${project.path}`);
171
+ });
172
+
173
+ const answer = await question(`\n選択してください [1-${projects.length}]: `);
174
+ const index = parseInt(answer.trim(), 10) - 1;
175
+
176
+ if (index >= 0 && index < projects.length) {
177
+ return projects[index];
178
+ }
179
+
180
+ // 無効な入力の場合は最初のプロジェクトを返す
181
+ console.log('⚠️ 無効な選択です。最初のプロジェクトを使用します。');
182
+ return projects[0];
183
+ }
184
+
@@ -0,0 +1,212 @@
1
+ /**
2
+ * spec.json 更新ユーティリティ
3
+ * Confluence/JIRA 同期後に spec.json を更新する
4
+ */
5
+
6
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
7
+ import { resolve, dirname } from 'path';
8
+
9
+ /**
10
+ * spec.json の型定義
11
+ */
12
+ export interface SpecJson {
13
+ featureName?: string;
14
+ projectName?: string;
15
+ confluence?: {
16
+ spaceKey?: string;
17
+ requirements?: {
18
+ pageId?: string;
19
+ url?: string;
20
+ title?: string;
21
+ };
22
+ design?: {
23
+ pageId?: string;
24
+ url?: string;
25
+ title?: string;
26
+ };
27
+ tasks?: {
28
+ pageId?: string;
29
+ url?: string;
30
+ title?: string;
31
+ };
32
+ };
33
+ jira?: {
34
+ projectKey?: string;
35
+ epicKey?: string;
36
+ epicUrl?: string;
37
+ storyKeys?: string[];
38
+ };
39
+ milestones?: {
40
+ requirementsCompleted?: boolean;
41
+ designCompleted?: boolean;
42
+ tasksCompleted?: boolean;
43
+ jiraSyncCompleted?: boolean;
44
+ };
45
+ lastUpdated?: string;
46
+ }
47
+
48
+ /**
49
+ * spec.json を読み込む
50
+ */
51
+ export function loadSpecJson(featureName: string, projectRoot: string = process.cwd()): SpecJson {
52
+ const specPath = resolve(projectRoot, `.kiro/specs/${featureName}/spec.json`);
53
+
54
+ if (!existsSync(specPath)) {
55
+ // 新規作成する場合は最低限の構造を返す
56
+ return {
57
+ featureName,
58
+ confluence: {},
59
+ jira: {},
60
+ milestones: {},
61
+ };
62
+ }
63
+
64
+ try {
65
+ const content = readFileSync(specPath, 'utf-8');
66
+ return JSON.parse(content);
67
+ } catch (error) {
68
+ console.warn(`⚠️ Failed to load spec.json from ${specPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
69
+ return {
70
+ featureName,
71
+ confluence: {},
72
+ jira: {},
73
+ milestones: {},
74
+ };
75
+ }
76
+ }
77
+
78
+ /**
79
+ * spec.json を保存する
80
+ * @param featureName 機能名
81
+ * @param spec 保存する spec オブジェクト(lastUpdated フィールドが更新されます)
82
+ * @param projectRoot プロジェクトルート(デフォルト: process.cwd())
83
+ */
84
+ export function saveSpecJson(featureName: string, spec: SpecJson, projectRoot: string = process.cwd()): void {
85
+ const specDir = resolve(projectRoot, `.kiro/specs/${featureName}`);
86
+ const specPath = resolve(specDir, 'spec.json');
87
+
88
+ // ディレクトリが存在しない場合は作成
89
+ if (!existsSync(specDir)) {
90
+ mkdirSync(specDir, { recursive: true });
91
+ }
92
+
93
+ // lastUpdated を更新
94
+ spec.lastUpdated = new Date().toISOString();
95
+
96
+ try {
97
+ writeFileSync(specPath, JSON.stringify(spec, null, 2), 'utf-8');
98
+ console.log(`✅ Updated spec.json: ${specPath}`);
99
+ } catch (error) {
100
+ console.error(`❌ Failed to save spec.json to ${specPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
101
+ throw error;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Confluence 同期後に spec.json を更新
107
+ */
108
+ export function updateSpecJsonAfterConfluenceSync(
109
+ featureName: string,
110
+ docType: 'requirements' | 'design' | 'tasks',
111
+ pageInfo: {
112
+ pageId: string;
113
+ url: string;
114
+ title: string;
115
+ spaceKey: string;
116
+ },
117
+ projectRoot: string = process.cwd()
118
+ ): void {
119
+ const spec = loadSpecJson(featureName, projectRoot);
120
+
121
+ // Confluence 情報を更新
122
+ if (!spec.confluence) {
123
+ spec.confluence = {};
124
+ }
125
+
126
+ // スペースキーを設定
127
+ if (pageInfo.spaceKey) {
128
+ spec.confluence.spaceKey = pageInfo.spaceKey;
129
+ }
130
+
131
+ // 新形式:ドキュメントタイプごとのページ情報を更新
132
+ spec.confluence[docType] = {
133
+ pageId: pageInfo.pageId,
134
+ url: pageInfo.url,
135
+ title: pageInfo.title,
136
+ };
137
+
138
+ // 旧形式(後方互換性のため併記)
139
+ if (docType === 'requirements') {
140
+ (spec.confluence as any).requirementsPageId = pageInfo.pageId;
141
+ (spec.confluence as any).requirementsUrl = pageInfo.url;
142
+ } else if (docType === 'design') {
143
+ (spec.confluence as any).designPageId = pageInfo.pageId;
144
+ (spec.confluence as any).designUrl = pageInfo.url;
145
+ } else if (docType === 'tasks') {
146
+ (spec.confluence as any).tasksPageId = pageInfo.pageId;
147
+ (spec.confluence as any).tasksUrl = pageInfo.url;
148
+ }
149
+
150
+ // マイルストーンを更新
151
+ if (!spec.milestones) {
152
+ spec.milestones = {};
153
+ }
154
+
155
+ // 新形式:フラットなフィールド
156
+ if (docType === 'requirements') {
157
+ spec.milestones.requirementsCompleted = true;
158
+ // 旧形式(後方互換性のため併記)
159
+ if (!(spec.milestones as any).requirements) {
160
+ (spec.milestones as any).requirements = {};
161
+ }
162
+ (spec.milestones as any).requirements.completed = true;
163
+ } else if (docType === 'design') {
164
+ spec.milestones.designCompleted = true;
165
+ // 旧形式(後方互換性のため併記)
166
+ if (!(spec.milestones as any).design) {
167
+ (spec.milestones as any).design = {};
168
+ }
169
+ (spec.milestones as any).design.completed = true;
170
+ } else if (docType === 'tasks') {
171
+ spec.milestones.tasksCompleted = true;
172
+ // 旧形式(後方互換性のため併記)
173
+ if (!(spec.milestones as any).tasks) {
174
+ (spec.milestones as any).tasks = {};
175
+ }
176
+ (spec.milestones as any).tasks.completed = true;
177
+ }
178
+
179
+ saveSpecJson(featureName, spec, projectRoot);
180
+ }
181
+
182
+ /**
183
+ * JIRA 同期後に spec.json を更新
184
+ */
185
+ export function updateSpecJsonAfterJiraSync(
186
+ featureName: string,
187
+ jiraInfo: {
188
+ projectKey: string;
189
+ epicKey: string;
190
+ epicUrl: string;
191
+ storyKeys: string[];
192
+ },
193
+ projectRoot: string = process.cwd()
194
+ ): void {
195
+ const spec = loadSpecJson(featureName, projectRoot);
196
+
197
+ // JIRA 情報を更新
198
+ spec.jira = {
199
+ projectKey: jiraInfo.projectKey,
200
+ epicKey: jiraInfo.epicKey,
201
+ epicUrl: jiraInfo.epicUrl,
202
+ storyKeys: jiraInfo.storyKeys,
203
+ };
204
+
205
+ // マイルストーンを更新
206
+ if (!spec.milestones) {
207
+ spec.milestones = {};
208
+ }
209
+ spec.milestones.jiraSyncCompleted = true;
210
+
211
+ saveSpecJson(featureName, spec, projectRoot);
212
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * テンプレートファイル検索ユーティリティ
3
+ *
4
+ * Issue #35: cc-sdd準拠のテンプレート検索
5
+ * Cursor/Claude両環境のテンプレートを優先順位付きで検索
6
+ */
7
+
8
+ import { existsSync } from 'fs';
9
+ import { join } from 'path';
10
+
11
+ /**
12
+ * templates/ディレクトリからファイルを検索
13
+ *
14
+ * @param michiPath - Michiリポジトリのルートパス
15
+ * @param relativePath - templates/配下の相対パス(例: 'rules/github-ssot.mdc')
16
+ * @returns 見つかったファイルの絶対パス、見つからない場合はnull
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const path = findTemplateFile('/path/to/michi', 'rules/github-ssot.mdc');
21
+ * // returns: '/path/to/michi/templates/cursor/rules/github-ssot.mdc'
22
+ * ```
23
+ */
24
+ export function findTemplateFile(michiPath: string, relativePath: string): string | null {
25
+ // 優先順位1: templates/cursor/
26
+ const cursorPath = join(michiPath, 'templates/cursor', relativePath);
27
+ if (existsSync(cursorPath)) {
28
+ return cursorPath;
29
+ }
30
+
31
+ // 優先順位2: templates/claude/
32
+ const claudePath = join(michiPath, 'templates/claude', relativePath);
33
+ if (existsSync(claudePath)) {
34
+ return claudePath;
35
+ }
36
+
37
+ return null;
38
+ }
39
+
40
+ /**
41
+ * 必須テンプレートファイルのバリデーション
42
+ *
43
+ * @param michiPath - Michiリポジトリのルートパス
44
+ * @param requiredFiles - 必須ファイルのリスト
45
+ * @throws Error - 必須ファイルが見つからない場合
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * validateRequiredTemplates('/path/to/michi', [
50
+ * 'rules/github-ssot.mdc',
51
+ * 'commands/michi/confluence-sync.md'
52
+ * ]);
53
+ * ```
54
+ */
55
+ export function validateRequiredTemplates(
56
+ michiPath: string,
57
+ requiredFiles: string[]
58
+ ): void {
59
+ const missingFiles: string[] = [];
60
+
61
+ for (const file of requiredFiles) {
62
+ const path = findTemplateFile(michiPath, file);
63
+ if (!path) {
64
+ missingFiles.push(file);
65
+ }
66
+ }
67
+
68
+ if (missingFiles.length > 0) {
69
+ throw new Error(
70
+ `Missing required template files:\n - ${missingFiles.join('\n - ')}\n\n` +
71
+ `Please check that Michi templates are properly installed at: ${michiPath}/templates/`
72
+ );
73
+ }
74
+ }
75
+
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: /michi:confluence-sync
3
+ description: Sync specifications to Confluence
4
+ ---
5
+
6
+ # Confluence Sync Command
7
+
8
+ **Important**: Generate output in language specified in {{KIRO_DIR}}/project.json.
9
+
10
+ ## Usage
11
+
12
+ ```
13
+ /michi:confluence-sync <feature_name>
14
+ ```
15
+
16
+ **Parameters**:
17
+ - `feature_name`: Feature name (e.g., user-auth, payment-api)
18
+
19
+ ## Execution Steps
20
+
21
+ 1. Read specifications from {{KIRO_DIR}}/specs/{{FEATURE_NAME}}/
22
+ 2. Load project metadata from {{KIRO_DIR}}/project.json
23
+ 3. Sync requirements.md to Confluence
24
+ 4. Sync design.md to Confluence
25
+ 5. Create/update Confluence pages with proper labels
26
+ 6. Link pages to JIRA Epic (if exists)
27
+
28
+ ## Language Handling
29
+
30
+ - Read language from {{KIRO_DIR}}/project.json
31
+ - Generate all output in the specified language
32
+ - Use Confluence labels from project.json for page organization
33
+
34
+ ## Project Metadata
35
+
36
+ - Project ID: {{PROJECT_ID}}
37
+ - Kiro directory: {{KIRO_DIR}}
38
+ - Agent directory: {{AGENT_DIR}}
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: /michi:project-switch
3
+ description: Switch between projects
4
+ ---
5
+
6
+ # Project Switch Command
7
+
8
+ **Important**: Generate output in language specified in {{KIRO_DIR}}/project.json.
9
+
10
+ ## Usage
11
+
12
+ ```
13
+ /michi:project-switch <project_id>
14
+ ```
15
+
16
+ **Parameters**:
17
+ - `project_id`: Project ID (e.g., customer-a-service-1, michi)
18
+
19
+ **Examples**:
20
+ ```
21
+ /michi:project-switch michi
22
+ /michi:project-switch customer-a-service-1
23
+ ```
24
+
25
+ ## Execution Steps
26
+
27
+ 1. Identify GitHub repository corresponding to project ID
28
+ 2. Clone locally (if not cloned) or checkout
29
+ 3. Load and display {{KIRO_DIR}}/project.json
30
+ 4. Display corresponding Confluence project page URL
31
+
32
+ ## Language Handling
33
+
34
+ - Read language from {{KIRO_DIR}}/project.json
35
+ - Generate all output in the specified language
36
+ - Default to English if language field is missing
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Atlassian Integration
3
+ description: Integration rules for Confluence and JIRA via MCP
4
+ ---
5
+
6
+ # Atlassian Integration
7
+
8
+ ## Development Guidelines
9
+ {{DEV_GUIDELINES}}
10
+
11
+ ## Language
12
+ All generated documents should be in: **{{LANG_CODE}}**
13
+
14
+ ## MCP Integration
15
+
16
+ ### Confluence Sync
17
+ - Sync specifications from {{KIRO_DIR}}/specs/ to Confluence
18
+ - Use MCP server for Confluence operations
19
+ - Project labels: Check {{KIRO_DIR}}/project.json
20
+
21
+ ### JIRA Sync
22
+ - Create Epic and Stories from {{KIRO_DIR}}/specs/{{FEATURE_NAME}}/tasks.md
23
+ - Use JIRA project key: {{PROJECT_ID}}
24
+ - Link Confluence pages automatically
25
+
26
+ ## Project Metadata
27
+ - Project ID: {{PROJECT_ID}}
28
+ - Kiro directory: {{KIRO_DIR}}
29
+ - Agent directory: {{AGENT_DIR}}
30
+
31
+ ## Workflow
32
+ 1. Create spec in {{KIRO_DIR}}/specs/{{FEATURE_NAME}}/
33
+ 2. Sync to Confluence via MCP
34
+ 3. Create JIRA Epic/Stories
35
+ 4. Link Confluence pages to JIRA
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: Michi Core Principles
3
+ description: Core principles for GitHub SSoT and multi-project management
4
+ ---
5
+
6
+ # Michi Core Principles
7
+
8
+ ## Development Guidelines
9
+ {{DEV_GUIDELINES}}
10
+
11
+ ## Language
12
+ All generated documents should be in: **{{LANG_CODE}}**
13
+
14
+ Reference the language field in {{KIRO_DIR}}/project.json.
15
+
16
+ ## Single Source of Truth (SSoT)
17
+
18
+ ### GitHub as SSoT
19
+ - **All specifications are managed in GitHub** ({{KIRO_DIR}}/specs/)
20
+ - Confluence is **reference and approval only** (editing is GitHub only)
21
+ - Avoid duplicate management
22
+
23
+ ### Data Flow
24
+ ```
25
+ GitHub ({{KIRO_DIR}}/specs/) ← Source of truth (editable)
26
+ ↓ sync
27
+ Confluence ← Display and approval (read-only)
28
+ ```
29
+
30
+ ## Multi-Project Management
31
+
32
+ ### Project Identification
33
+ - All operations reference {{KIRO_DIR}}/project.json
34
+ - Dynamically use project ID, JIRA key, Confluence labels
35
+ - Project ID: {{PROJECT_ID}}
36
+
37
+ ### Naming Conventions
38
+
39
+ #### Confluence Pages
40
+ - Format: `[{projectName}] {document_type}`
41
+ - Example: `[{{PROJECT_ID}}] Requirements`
42
+
43
+ #### JIRA Epic/Story
44
+ - Format: `[{JIRA_KEY}] {title}`
45
+ - Use project metadata from {{KIRO_DIR}}/project.json
46
+
47
+ ## Agent Directory
48
+ - Agent configuration: {{AGENT_DIR}}
49
+ - Rules location: {{AGENT_DIR}}/rules/
50
+ - Commands location: {{AGENT_DIR}}/commands/
51
+
52
+ ## Feature Development
53
+ - Feature name: {{FEATURE_NAME}}
54
+ - Spec location: {{KIRO_DIR}}/specs/{{FEATURE_NAME}}/
@@ -0,0 +1,25 @@
1
+ # Claude Agent Templates
2
+
3
+ This directory contains templates for Claude Agent configuration.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ claude-agent/
9
+ ├── README.md
10
+ └── (additional templates)
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ These templates are used when setting up Claude Agent for a project.
16
+ Placeholders are replaced with project-specific values during setup.
17
+
18
+ ## Placeholders
19
+
20
+ - {{LANG_CODE}}: Language code (ja, en, etc.)
21
+ - {{DEV_GUIDELINES}}: Development guidelines
22
+ - {{KIRO_DIR}}: Kiro directory (default: .kiro)
23
+ - {{AGENT_DIR}}: Agent directory (default: .claude)
24
+ - {{PROJECT_ID}}: Project ID
25
+ - {{FEATURE_NAME}}: Feature name