@sk8metal/michi-cli 0.5.0 → 0.8.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.
Files changed (284) hide show
  1. package/CHANGELOG.md +136 -1
  2. package/README.md +2 -1
  3. package/dist/scripts/config/config-schema.d.ts +35 -0
  4. package/dist/scripts/config/config-schema.d.ts.map +1 -1
  5. package/dist/scripts/config/config-schema.js +56 -0
  6. package/dist/scripts/config/config-schema.js.map +1 -1
  7. package/dist/scripts/confluence-sync.d.ts.map +1 -1
  8. package/dist/scripts/confluence-sync.js +15 -2
  9. package/dist/scripts/confluence-sync.js.map +1 -1
  10. package/dist/scripts/github-actions-client.d.ts +79 -0
  11. package/dist/scripts/github-actions-client.d.ts.map +1 -0
  12. package/dist/scripts/github-actions-client.js +182 -0
  13. package/dist/scripts/github-actions-client.js.map +1 -0
  14. package/dist/scripts/health-check-service.d.ts +46 -0
  15. package/dist/scripts/health-check-service.d.ts.map +1 -0
  16. package/dist/scripts/health-check-service.js +114 -0
  17. package/dist/scripts/health-check-service.js.map +1 -0
  18. package/dist/scripts/markdown-to-confluence.d.ts.map +1 -1
  19. package/dist/scripts/markdown-to-confluence.js +25 -3
  20. package/dist/scripts/markdown-to-confluence.js.map +1 -1
  21. package/dist/scripts/mermaid-converter.d.ts +24 -0
  22. package/dist/scripts/mermaid-converter.d.ts.map +1 -0
  23. package/dist/scripts/mermaid-converter.js +49 -0
  24. package/dist/scripts/mermaid-converter.js.map +1 -0
  25. package/dist/scripts/template/multi-repo-renderer.d.ts +67 -0
  26. package/dist/scripts/template/multi-repo-renderer.d.ts.map +1 -0
  27. package/dist/scripts/template/multi-repo-renderer.js +123 -0
  28. package/dist/scripts/template/multi-repo-renderer.js.map +1 -0
  29. package/dist/scripts/template/renderer.d.ts +4 -0
  30. package/dist/scripts/template/renderer.d.ts.map +1 -1
  31. package/dist/scripts/template/renderer.js.map +1 -1
  32. package/dist/scripts/test-execution-generator.d.ts.map +1 -1
  33. package/dist/scripts/test-execution-generator.js +94 -11
  34. package/dist/scripts/test-execution-generator.js.map +1 -1
  35. package/dist/scripts/test-script-runner.d.ts +33 -0
  36. package/dist/scripts/test-script-runner.d.ts.map +1 -0
  37. package/dist/scripts/test-script-runner.js +77 -0
  38. package/dist/scripts/test-script-runner.js.map +1 -0
  39. package/dist/scripts/utils/config-loader.d.ts +21 -1
  40. package/dist/scripts/utils/config-loader.d.ts.map +1 -1
  41. package/dist/scripts/utils/config-loader.js +149 -3
  42. package/dist/scripts/utils/config-loader.js.map +1 -1
  43. package/dist/scripts/utils/multi-repo-validator.d.ts +30 -0
  44. package/dist/scripts/utils/multi-repo-validator.d.ts.map +1 -0
  45. package/dist/scripts/utils/multi-repo-validator.js +105 -0
  46. package/dist/scripts/utils/multi-repo-validator.js.map +1 -0
  47. package/dist/scripts/utils/spec-archiver.d.ts +38 -0
  48. package/dist/scripts/utils/spec-archiver.d.ts.map +1 -0
  49. package/dist/scripts/utils/spec-archiver.js +210 -0
  50. package/dist/scripts/utils/spec-archiver.js.map +1 -0
  51. package/dist/scripts/utils/spec-updater.d.ts +4 -0
  52. package/dist/scripts/utils/spec-updater.d.ts.map +1 -1
  53. package/dist/scripts/utils/spec-updater.js.map +1 -1
  54. package/dist/src/cli.d.ts.map +1 -1
  55. package/dist/src/cli.js +262 -14
  56. package/dist/src/cli.js.map +1 -1
  57. package/dist/src/commands/multi-repo-add-repo.d.ts +26 -0
  58. package/dist/src/commands/multi-repo-add-repo.d.ts.map +1 -0
  59. package/dist/src/commands/multi-repo-add-repo.js +56 -0
  60. package/dist/src/commands/multi-repo-add-repo.js.map +1 -0
  61. package/dist/src/commands/multi-repo-ci-status.d.ts +46 -0
  62. package/dist/src/commands/multi-repo-ci-status.d.ts.map +1 -0
  63. package/dist/src/commands/multi-repo-ci-status.js +285 -0
  64. package/dist/src/commands/multi-repo-ci-status.js.map +1 -0
  65. package/dist/src/commands/multi-repo-confluence-sync.d.ts +45 -0
  66. package/dist/src/commands/multi-repo-confluence-sync.d.ts.map +1 -0
  67. package/dist/src/commands/multi-repo-confluence-sync.js +135 -0
  68. package/dist/src/commands/multi-repo-confluence-sync.js.map +1 -0
  69. package/dist/src/commands/multi-repo-init.d.ts +26 -0
  70. package/dist/src/commands/multi-repo-init.d.ts.map +1 -0
  71. package/dist/src/commands/multi-repo-init.js +101 -0
  72. package/dist/src/commands/multi-repo-init.js.map +1 -0
  73. package/dist/src/commands/multi-repo-list.d.ts +28 -0
  74. package/dist/src/commands/multi-repo-list.d.ts.map +1 -0
  75. package/dist/src/commands/multi-repo-list.js +38 -0
  76. package/dist/src/commands/multi-repo-list.js.map +1 -0
  77. package/dist/src/commands/multi-repo-test.d.ts +56 -0
  78. package/dist/src/commands/multi-repo-test.d.ts.map +1 -0
  79. package/dist/src/commands/multi-repo-test.js +70 -0
  80. package/dist/src/commands/multi-repo-test.js.map +1 -0
  81. package/dist/src/commands/setup-existing.d.ts.map +1 -1
  82. package/dist/src/commands/setup-existing.js +30 -8
  83. package/dist/src/commands/setup-existing.js.map +1 -1
  84. package/dist/src/commands/spec-archive.d.ts +17 -0
  85. package/dist/src/commands/spec-archive.d.ts.map +1 -0
  86. package/dist/src/commands/spec-archive.js +40 -0
  87. package/dist/src/commands/spec-archive.js.map +1 -0
  88. package/dist/src/commands/spec-list.d.ts +15 -0
  89. package/dist/src/commands/spec-list.d.ts.map +1 -0
  90. package/dist/src/commands/spec-list.js +55 -0
  91. package/dist/src/commands/spec-list.js.map +1 -0
  92. package/docs/user-guide/guides/multi-repo-guide.md +591 -0
  93. package/docs/user-guide/guides/multi-repo-migration-guide.md +516 -0
  94. package/docs/user-guide/reference/multi-repo-api.md +771 -0
  95. package/docs/user-guide/reference/quick-reference.md +22 -37
  96. package/package.json +1 -4
  97. package/scripts/__tests__/config-loader-multi-repo.test.ts +342 -0
  98. package/scripts/__tests__/github-actions-client.test.ts +543 -0
  99. package/scripts/__tests__/health-check-service.test.ts +142 -0
  100. package/scripts/__tests__/markdown-to-confluence.test.ts +262 -0
  101. package/scripts/__tests__/mermaid-converter.test.ts +236 -0
  102. package/scripts/__tests__/multi-repo-config-schema.test.ts +335 -0
  103. package/scripts/__tests__/multi-repo-validator.test.ts +524 -0
  104. package/scripts/__tests__/spec-archiver.test.ts +512 -0
  105. package/scripts/__tests__/test-script-runner.test.ts +217 -0
  106. package/scripts/config/config-schema.ts +64 -0
  107. package/scripts/confluence-sync.ts +16 -2
  108. package/scripts/github-actions-client.ts +258 -0
  109. package/scripts/health-check-service.ts +171 -0
  110. package/scripts/markdown-to-confluence.ts +37 -6
  111. package/scripts/mermaid-converter.ts +56 -0
  112. package/scripts/template/__tests__/multi-repo-renderer.test.ts +261 -0
  113. package/scripts/template/multi-repo-renderer.ts +172 -0
  114. package/scripts/template/renderer.ts +5 -0
  115. package/scripts/test-execution-generator.ts +104 -11
  116. package/scripts/test-script-runner.ts +130 -0
  117. package/scripts/utils/__tests__/config-validator.test.ts +104 -6
  118. package/scripts/utils/__tests__/multi-repo-validator.test.ts +335 -0
  119. package/scripts/utils/config-loader.ts +197 -3
  120. package/scripts/utils/multi-repo-validator.ts +141 -0
  121. package/scripts/utils/spec-archiver.ts +260 -0
  122. package/scripts/utils/spec-updater.ts +4 -0
  123. package/templates/claude/agents/pr-size-monitor/AGENT.md +330 -0
  124. package/templates/claude/commands/michi/spec-impl.md +208 -35
  125. package/templates/claude-agent/agents/doc-reviewer.md +176 -0
  126. package/templates/claude-agent/rules/doc-review-rules.md +98 -0
  127. package/templates/claude-agent/rules/doc-review.md +91 -0
  128. package/templates/multi-repo/docs/ci-status.md +51 -0
  129. package/templates/multi-repo/docs/release-notes.md +99 -0
  130. package/templates/multi-repo/overview/architecture.md +102 -0
  131. package/templates/multi-repo/overview/requirements.md +68 -0
  132. package/templates/multi-repo/overview/sequence.md +79 -0
  133. package/templates/multi-repo/steering/multi-repo.md +74 -0
  134. package/templates/multi-repo/tests/strategy.md +89 -0
  135. package/dist/scripts/__tests__/create-project.test.d.ts +0 -2
  136. package/dist/scripts/__tests__/create-project.test.d.ts.map +0 -1
  137. package/dist/scripts/__tests__/create-project.test.js +0 -243
  138. package/dist/scripts/__tests__/create-project.test.js.map +0 -1
  139. package/dist/scripts/__tests__/jira-transitions.test.d.ts +0 -5
  140. package/dist/scripts/__tests__/jira-transitions.test.d.ts.map +0 -1
  141. package/dist/scripts/__tests__/jira-transitions.test.js +0 -172
  142. package/dist/scripts/__tests__/jira-transitions.test.js.map +0 -1
  143. package/dist/scripts/__tests__/multi-project-estimate.test.d.ts +0 -2
  144. package/dist/scripts/__tests__/multi-project-estimate.test.d.ts.map +0 -1
  145. package/dist/scripts/__tests__/multi-project-estimate.test.js +0 -118
  146. package/dist/scripts/__tests__/multi-project-estimate.test.js.map +0 -1
  147. package/dist/scripts/__tests__/setup-existing-project.test.d.ts +0 -2
  148. package/dist/scripts/__tests__/setup-existing-project.test.d.ts.map +0 -1
  149. package/dist/scripts/__tests__/setup-existing-project.test.js +0 -208
  150. package/dist/scripts/__tests__/setup-existing-project.test.js.map +0 -1
  151. package/dist/scripts/__tests__/setup-interactive.test.d.ts +0 -2
  152. package/dist/scripts/__tests__/setup-interactive.test.d.ts.map +0 -1
  153. package/dist/scripts/__tests__/setup-interactive.test.js +0 -166
  154. package/dist/scripts/__tests__/setup-interactive.test.js.map +0 -1
  155. package/dist/scripts/__tests__/spec-impl-workflow.test.d.ts +0 -5
  156. package/dist/scripts/__tests__/spec-impl-workflow.test.d.ts.map +0 -1
  157. package/dist/scripts/__tests__/spec-impl-workflow.test.js +0 -323
  158. package/dist/scripts/__tests__/spec-impl-workflow.test.js.map +0 -1
  159. package/dist/scripts/__tests__/spec-loader.test.d.ts +0 -5
  160. package/dist/scripts/__tests__/spec-loader.test.d.ts.map +0 -1
  161. package/dist/scripts/__tests__/spec-loader.test.js +0 -153
  162. package/dist/scripts/__tests__/spec-loader.test.js.map +0 -1
  163. package/dist/scripts/__tests__/validate-phase.test.d.ts +0 -5
  164. package/dist/scripts/__tests__/validate-phase.test.d.ts.map +0 -1
  165. package/dist/scripts/__tests__/validate-phase.test.js +0 -249
  166. package/dist/scripts/__tests__/validate-phase.test.js.map +0 -1
  167. package/dist/scripts/constants/__tests__/environments.test.d.ts +0 -2
  168. package/dist/scripts/constants/__tests__/environments.test.d.ts.map +0 -1
  169. package/dist/scripts/constants/__tests__/environments.test.js +0 -125
  170. package/dist/scripts/constants/__tests__/environments.test.js.map +0 -1
  171. package/dist/scripts/constants/__tests__/languages.test.d.ts +0 -2
  172. package/dist/scripts/constants/__tests__/languages.test.d.ts.map +0 -1
  173. package/dist/scripts/constants/__tests__/languages.test.js +0 -82
  174. package/dist/scripts/constants/__tests__/languages.test.js.map +0 -1
  175. package/dist/scripts/create-project.d.ts +0 -16
  176. package/dist/scripts/create-project.d.ts.map +0 -1
  177. package/dist/scripts/create-project.js +0 -334
  178. package/dist/scripts/create-project.js.map +0 -1
  179. package/dist/scripts/list-projects.d.ts +0 -7
  180. package/dist/scripts/list-projects.d.ts.map +0 -1
  181. package/dist/scripts/list-projects.js +0 -88
  182. package/dist/scripts/list-projects.js.map +0 -1
  183. package/dist/scripts/template/__tests__/renderer.test.d.ts +0 -2
  184. package/dist/scripts/template/__tests__/renderer.test.d.ts.map +0 -1
  185. package/dist/scripts/template/__tests__/renderer.test.js +0 -165
  186. package/dist/scripts/template/__tests__/renderer.test.js.map +0 -1
  187. package/dist/scripts/utils/__tests__/aidlc-parser.test.d.ts +0 -5
  188. package/dist/scripts/utils/__tests__/aidlc-parser.test.d.ts.map +0 -1
  189. package/dist/scripts/utils/__tests__/aidlc-parser.test.js +0 -315
  190. package/dist/scripts/utils/__tests__/aidlc-parser.test.js.map +0 -1
  191. package/dist/scripts/utils/__tests__/business-days.test.d.ts +0 -5
  192. package/dist/scripts/utils/__tests__/business-days.test.d.ts.map +0 -1
  193. package/dist/scripts/utils/__tests__/business-days.test.js +0 -171
  194. package/dist/scripts/utils/__tests__/business-days.test.js.map +0 -1
  195. package/dist/scripts/utils/__tests__/config-loader.test.d.ts +0 -5
  196. package/dist/scripts/utils/__tests__/config-loader.test.d.ts.map +0 -1
  197. package/dist/scripts/utils/__tests__/config-loader.test.js +0 -314
  198. package/dist/scripts/utils/__tests__/config-loader.test.js.map +0 -1
  199. package/dist/scripts/utils/__tests__/config-validator.test.d.ts +0 -5
  200. package/dist/scripts/utils/__tests__/config-validator.test.d.ts.map +0 -1
  201. package/dist/scripts/utils/__tests__/config-validator.test.js +0 -396
  202. package/dist/scripts/utils/__tests__/config-validator.test.js.map +0 -1
  203. package/dist/scripts/utils/__tests__/env-config.test.d.ts +0 -5
  204. package/dist/scripts/utils/__tests__/env-config.test.d.ts.map +0 -1
  205. package/dist/scripts/utils/__tests__/env-config.test.js +0 -216
  206. package/dist/scripts/utils/__tests__/env-config.test.js.map +0 -1
  207. package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts +0 -5
  208. package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts.map +0 -1
  209. package/dist/scripts/utils/__tests__/feature-name-validator.test.js +0 -106
  210. package/dist/scripts/utils/__tests__/feature-name-validator.test.js.map +0 -1
  211. package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.d.ts +0 -5
  212. package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.d.ts.map +0 -1
  213. package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.js +0 -202
  214. package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.js.map +0 -1
  215. package/dist/scripts/utils/__tests__/project-meta.test.d.ts +0 -6
  216. package/dist/scripts/utils/__tests__/project-meta.test.d.ts.map +0 -1
  217. package/dist/scripts/utils/__tests__/project-meta.test.js +0 -154
  218. package/dist/scripts/utils/__tests__/project-meta.test.js.map +0 -1
  219. package/dist/scripts/utils/__tests__/security-validator.test.d.ts +0 -6
  220. package/dist/scripts/utils/__tests__/security-validator.test.d.ts.map +0 -1
  221. package/dist/scripts/utils/__tests__/security-validator.test.js +0 -219
  222. package/dist/scripts/utils/__tests__/security-validator.test.js.map +0 -1
  223. package/dist/scripts/utils/__tests__/spec-updater.test.d.ts +0 -5
  224. package/dist/scripts/utils/__tests__/spec-updater.test.d.ts.map +0 -1
  225. package/dist/scripts/utils/__tests__/spec-updater.test.js +0 -158
  226. package/dist/scripts/utils/__tests__/spec-updater.test.js.map +0 -1
  227. package/dist/scripts/utils/__tests__/tasks-converter.test.d.ts +0 -5
  228. package/dist/scripts/utils/__tests__/tasks-converter.test.d.ts.map +0 -1
  229. package/dist/scripts/utils/__tests__/tasks-converter.test.js +0 -500
  230. package/dist/scripts/utils/__tests__/tasks-converter.test.js.map +0 -1
  231. package/dist/scripts/utils/__tests__/tasks-format-validator.test.d.ts +0 -5
  232. package/dist/scripts/utils/__tests__/tasks-format-validator.test.d.ts.map +0 -1
  233. package/dist/scripts/utils/__tests__/tasks-format-validator.test.js +0 -314
  234. package/dist/scripts/utils/__tests__/tasks-format-validator.test.js.map +0 -1
  235. package/dist/scripts/utils/__tests__/test-runner.test.d.ts +0 -5
  236. package/dist/scripts/utils/__tests__/test-runner.test.d.ts.map +0 -1
  237. package/dist/scripts/utils/__tests__/test-runner.test.js +0 -64
  238. package/dist/scripts/utils/__tests__/test-runner.test.js.map +0 -1
  239. package/dist/src/__tests__/cli.test.d.ts +0 -5
  240. package/dist/src/__tests__/cli.test.d.ts.map +0 -1
  241. package/dist/src/__tests__/cli.test.js +0 -58
  242. package/dist/src/__tests__/cli.test.js.map +0 -1
  243. package/dist/src/__tests__/integration/internationalization.test.d.ts +0 -8
  244. package/dist/src/__tests__/integration/internationalization.test.d.ts.map +0 -1
  245. package/dist/src/__tests__/integration/internationalization.test.js +0 -333
  246. package/dist/src/__tests__/integration/internationalization.test.js.map +0 -1
  247. package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts +0 -5
  248. package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts.map +0 -1
  249. package/dist/src/__tests__/integration/setup/claude-agent.test.js +0 -122
  250. package/dist/src/__tests__/integration/setup/claude-agent.test.js.map +0 -1
  251. package/dist/src/__tests__/integration/setup/claude.test.d.ts +0 -5
  252. package/dist/src/__tests__/integration/setup/claude.test.d.ts.map +0 -1
  253. package/dist/src/__tests__/integration/setup/claude.test.js +0 -193
  254. package/dist/src/__tests__/integration/setup/claude.test.js.map +0 -1
  255. package/dist/src/__tests__/integration/setup/cursor.test.d.ts +0 -5
  256. package/dist/src/__tests__/integration/setup/cursor.test.d.ts.map +0 -1
  257. package/dist/src/__tests__/integration/setup/cursor.test.js +0 -166
  258. package/dist/src/__tests__/integration/setup/cursor.test.js.map +0 -1
  259. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts +0 -32
  260. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts.map +0 -1
  261. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js +0 -72
  262. package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js.map +0 -1
  263. package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts +0 -38
  264. package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts.map +0 -1
  265. package/dist/src/__tests__/integration/setup/helpers/test-project.js +0 -83
  266. package/dist/src/__tests__/integration/setup/helpers/test-project.js.map +0 -1
  267. package/dist/src/__tests__/integration/setup/init.test.d.ts +0 -5
  268. package/dist/src/__tests__/integration/setup/init.test.d.ts.map +0 -1
  269. package/dist/src/__tests__/integration/setup/init.test.js +0 -352
  270. package/dist/src/__tests__/integration/setup/init.test.js.map +0 -1
  271. package/dist/src/__tests__/integration/setup/validation.test.d.ts +0 -5
  272. package/dist/src/__tests__/integration/setup/validation.test.d.ts.map +0 -1
  273. package/dist/src/__tests__/integration/setup/validation.test.js +0 -301
  274. package/dist/src/__tests__/integration/setup/validation.test.js.map +0 -1
  275. package/dist/src/commands/__tests__/init.test.d.ts +0 -5
  276. package/dist/src/commands/__tests__/init.test.d.ts.map +0 -1
  277. package/dist/src/commands/__tests__/init.test.js +0 -255
  278. package/dist/src/commands/__tests__/init.test.js.map +0 -1
  279. package/dist/src/commands/__tests__/migrate.test.d.ts +0 -5
  280. package/dist/src/commands/__tests__/migrate.test.d.ts.map +0 -1
  281. package/dist/src/commands/__tests__/migrate.test.js +0 -216
  282. package/dist/src/commands/__tests__/migrate.test.js.map +0 -1
  283. package/scripts/create-project.ts +0 -386
  284. package/scripts/list-projects.ts +0 -112
@@ -0,0 +1,171 @@
1
+ /**
2
+ * ヘルスチェックサービス
3
+ * 依存サービスの状態を確認してテスト実行前の環境チェックを行う
4
+ */
5
+
6
+ import { existsSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { execSync } from 'child_process';
9
+
10
+ /**
11
+ * サービスステータス
12
+ */
13
+ export interface ServiceStatus {
14
+ serviceName: string;
15
+ status: 'healthy' | 'unhealthy';
16
+ message?: string;
17
+ }
18
+
19
+ /**
20
+ * ヘルスチェック結果
21
+ */
22
+ export interface HealthCheckResult {
23
+ success: boolean;
24
+ servicesStatus: ServiceStatus[];
25
+ }
26
+
27
+ /**
28
+ * execSync実行時のエラー型
29
+ */
30
+ interface ExecError extends Error {
31
+ status?: number;
32
+ stdout?: Buffer | string;
33
+ stderr?: Buffer | string;
34
+ }
35
+
36
+ /**
37
+ * ヘルスチェックサービス
38
+ */
39
+ export class HealthCheckService {
40
+ /**
41
+ * ヘルスチェックを実行
42
+ *
43
+ * @param projectName プロジェクト名
44
+ * @param projectRoot プロジェクトルートディレクトリ(デフォルト: process.cwd())
45
+ * @returns ヘルスチェック結果
46
+ */
47
+ async runHealthCheck(
48
+ projectName: string,
49
+ projectRoot: string = process.cwd()
50
+ ): Promise<HealthCheckResult> {
51
+ // 1. ヘルスチェックスクリプトの存在確認
52
+ const scriptPath = join(
53
+ projectRoot,
54
+ 'docs',
55
+ 'michi',
56
+ projectName,
57
+ 'tests',
58
+ 'scripts',
59
+ 'health-check.sh'
60
+ );
61
+
62
+ if (!existsSync(scriptPath)) {
63
+ console.log(
64
+ `ℹ️ ヘルスチェックスクリプトが見つかりません: ${scriptPath}。ヘルスチェックをスキップします。`
65
+ );
66
+ return {
67
+ success: true,
68
+ servicesStatus: [],
69
+ };
70
+ }
71
+
72
+ // 2. ヘルスチェックスクリプトを実行
73
+ try {
74
+ console.log('🔍 ヘルスチェックを実行中...');
75
+ const output = execSync(scriptPath, {
76
+ encoding: 'utf-8',
77
+ timeout: 30000, // 30秒タイムアウト
78
+ }) as string;
79
+
80
+ // 3. スクリプト出力を解析
81
+ const servicesStatus = this.parseHealthCheckOutput(output);
82
+
83
+ // 4. unhealthyなサービスがある場合は失敗
84
+ const hasUnhealthyServices = servicesStatus.some(
85
+ (s) => s.status === 'unhealthy'
86
+ );
87
+
88
+ if (hasUnhealthyServices) {
89
+ console.log('❌ ヘルスチェックが失敗しました');
90
+ servicesStatus.forEach((s) => {
91
+ const icon = s.status === 'healthy' ? '✅' : '❌';
92
+ const message = s.message ? ` - ${s.message}` : '';
93
+ console.log(` ${icon} ${s.serviceName}: ${s.status}${message}`);
94
+ });
95
+
96
+ return {
97
+ success: false,
98
+ servicesStatus,
99
+ };
100
+ }
101
+
102
+ console.log('✅ ヘルスチェックが成功しました');
103
+ servicesStatus.forEach((s) => {
104
+ console.log(` ✅ ${s.serviceName}: ${s.status}`);
105
+ });
106
+
107
+ return {
108
+ success: true,
109
+ servicesStatus,
110
+ };
111
+ } catch (error) {
112
+ // スクリプト実行エラー
113
+ const execError = error as ExecError;
114
+ console.error('❌ ヘルスチェックスクリプトの実行に失敗しました:', execError.message);
115
+
116
+ if (execError.status !== undefined && execError.status !== 0) {
117
+ // 終了コードが非0の場合は失敗
118
+ const output = execError.stdout || execError.stderr || '';
119
+ const outputStr = Buffer.isBuffer(output) ? output.toString('utf-8') : String(output);
120
+ const servicesStatus = this.parseHealthCheckOutput(outputStr);
121
+
122
+ return {
123
+ success: false,
124
+ servicesStatus,
125
+ };
126
+ }
127
+
128
+ // その他のエラー(タイムアウト、パーミッションエラーなど)
129
+ return {
130
+ success: false,
131
+ servicesStatus: [],
132
+ };
133
+ }
134
+ }
135
+
136
+ /**
137
+ * ヘルスチェックスクリプトの出力を解析
138
+ *
139
+ * 出力形式:
140
+ * ```
141
+ * service-name: healthy
142
+ * service-name: unhealthy - error message
143
+ * ```
144
+ *
145
+ * @param output スクリプト出力
146
+ * @returns サービスステータス配列
147
+ */
148
+ private parseHealthCheckOutput(output: string): ServiceStatus[] {
149
+ const servicesStatus: ServiceStatus[] = [];
150
+ const lines = output.trim().split('\n');
151
+
152
+ for (const line of lines) {
153
+ const match = line.match(/^(\S+):\s+(healthy|unhealthy)(?:\s+-\s+(.+))?$/);
154
+ if (!match) {
155
+ continue; // 不正な形式の行はスキップ
156
+ }
157
+
158
+ const serviceName = match[1];
159
+ const status = match[2] as 'healthy' | 'unhealthy';
160
+ const message = match[3];
161
+
162
+ servicesStatus.push({
163
+ serviceName,
164
+ status,
165
+ message,
166
+ });
167
+ }
168
+
169
+ return servicesStatus;
170
+ }
171
+ }
@@ -14,14 +14,37 @@ const md = new MarkdownIt({
14
14
  * Markdown を Confluence Storage Format (HTML) に変換
15
15
  */
16
16
  export function convertMarkdownToConfluence(markdown: string): string {
17
- // MarkdownIt でHTMLに変換
18
- let html = md.render(markdown);
19
-
20
- // Confluence固有の変換
17
+ // 1. Mermaidブロックをプレースホルダーに置き換え
18
+ const mermaidBlocks: string[] = [];
19
+ const withPlaceholders = markdown.replace(
20
+ /```mermaid\n([\s\S]*?)```/g,
21
+ (match, diagram) => {
22
+ const placeholder = `<!--MERMAID_BLOCK_${mermaidBlocks.length}-->`;
23
+ mermaidBlocks.push(diagram.trim());
24
+ return placeholder;
25
+ }
26
+ );
27
+
28
+ // 2. MarkdownIt でHTMLに変換
29
+ let html = md.render(withPlaceholders);
30
+
31
+ // 3. Confluence固有の変換
21
32
  html = convertCodeBlocks(html);
22
33
  html = convertTables(html);
23
34
  html = convertInfoBoxes(html);
24
-
35
+
36
+ // 4. プレースホルダーをConfluenceマクロに戻す
37
+ html = html.replace(
38
+ /<!--MERMAID_BLOCK_(\d+)-->/g,
39
+ (match, index) => {
40
+ const diagram = mermaidBlocks[parseInt(index)];
41
+ const escapedDiagram = escapeCDATA(diagram);
42
+ return `<ac:structured-macro ac:name="mermaid">
43
+ <ac:plain-text-body><![CDATA[${escapedDiagram}]]></ac:plain-text-body>
44
+ </ac:structured-macro>`;
45
+ }
46
+ );
47
+
25
48
  return html;
26
49
  }
27
50
 
@@ -96,12 +119,20 @@ function decodeHtmlEntities(text: string): string {
96
119
  '&#39;': '\'',
97
120
  '&nbsp;': ' '
98
121
  };
99
-
122
+
100
123
  return text.replace(/&[a-z]+;|&#\d+;/g, (entity) => {
101
124
  return entities[entity] || entity;
102
125
  });
103
126
  }
104
127
 
128
+ /**
129
+ * CDATA内の ]]> をエスケープ
130
+ */
131
+ function escapeCDATA(text: string): string {
132
+ // ]]> を ]]]]><![CDATA[> に置換してエスケープ
133
+ return text.replace(/]]>/g, ']]]]><![CDATA[>');
134
+ }
135
+
105
136
  /**
106
137
  * Confluenceページテンプレートを生成
107
138
  */
@@ -0,0 +1,56 @@
1
+ /**
2
+ * MermaidダイアグラムをConfluenceマクロ形式に変換
3
+ */
4
+
5
+ /**
6
+ * MermaidConverter
7
+ * MarkdownテキストからMermaidブロックを検出し、Confluenceマクロ形式に変換
8
+ */
9
+ export class MermaidConverter {
10
+ /**
11
+ * MarkdownテキストからMermaidブロックをConfluenceマクロ形式に変換
12
+ *
13
+ * @param markdown Markdownテキスト
14
+ * @returns 変換後のテキスト
15
+ */
16
+ convertMermaidToConfluence(markdown: string): string {
17
+ // Mermaidブロックを検出する正規表現
18
+ // ```mermaid\n([\s\S]*?)\n```
19
+ const mermaidBlockRegex = /```mermaid\n([\s\S]*?)```/g;
20
+
21
+ // Mermaidブロックを検出
22
+ const matches = Array.from(markdown.matchAll(mermaidBlockRegex));
23
+
24
+ // Mermaidブロックがない場合は変更なし
25
+ if (matches.length === 0) {
26
+ return markdown;
27
+ }
28
+
29
+ // Mermaidブロックを Confluence マクロ形式に変換
30
+ const converted = markdown.replace(mermaidBlockRegex, (match, diagram) => {
31
+ // 前後の空白を削除
32
+ const trimmedDiagram = diagram.trim();
33
+
34
+ // CDATA終了マーカー ]]> をエスケープ
35
+ const escapedDiagram = this.escapeCDATA(trimmedDiagram);
36
+
37
+ // Confluenceマクロ形式に変換
38
+ return `<ac:structured-macro ac:name="mermaid">
39
+ <ac:plain-text-body><![CDATA[${escapedDiagram}]]></ac:plain-text-body>
40
+ </ac:structured-macro>`;
41
+ });
42
+
43
+ return converted;
44
+ }
45
+
46
+ /**
47
+ * CDATA内の ]]> をエスケープ
48
+ *
49
+ * @param text テキスト
50
+ * @returns エスケープ後のテキスト
51
+ */
52
+ private escapeCDATA(text: string): string {
53
+ // ]]> を ]]]]><![CDATA[> に置換してエスケープ
54
+ return text.replace(/]]>/g, ']]]]><![CDATA[>');
55
+ }
56
+ }
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Tests for Multi-Repo template renderer
3
+ */
4
+
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
6
+ import {
7
+ createMultiRepoTemplateContext,
8
+ loadMultiRepoTemplate,
9
+ renderMultiRepoTemplate,
10
+ loadAndRenderMultiRepoTemplate,
11
+ renderMultiRepoTemplates,
12
+ MULTI_REPO_TEMPLATES,
13
+ type MultiRepoTemplateContext,
14
+ } from '../multi-repo-renderer.js';
15
+ import * as fs from 'fs';
16
+
17
+ vi.mock('fs');
18
+
19
+ describe('createMultiRepoTemplateContext', () => {
20
+ it('必須フィールドを含むコンテキストを作成する', () => {
21
+ const context = createMultiRepoTemplateContext(
22
+ 'test-project',
23
+ 'TEST',
24
+ 'SPACE'
25
+ );
26
+
27
+ expect(context.PROJECT_NAME).toBe('test-project');
28
+ expect(context.JIRA_KEY).toBe('TEST');
29
+ expect(context.CONFLUENCE_SPACE).toBe('SPACE');
30
+ expect(context.CREATED_AT).toBeDefined();
31
+ });
32
+
33
+ it('CREATED_ATにカスタム値を指定できる', () => {
34
+ const customDate = '2025-12-14T10:00:00Z';
35
+ const context = createMultiRepoTemplateContext(
36
+ 'test-project',
37
+ 'TEST',
38
+ 'SPACE',
39
+ customDate
40
+ );
41
+
42
+ expect(context.CREATED_AT).toBe(customDate);
43
+ });
44
+
45
+ it('CREATED_ATが省略された場合は現在時刻を使用する', () => {
46
+ const context = createMultiRepoTemplateContext(
47
+ 'test-project',
48
+ 'TEST',
49
+ 'SPACE'
50
+ );
51
+
52
+ // ISO 8601形式であることを確認
53
+ expect(context.CREATED_AT).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
54
+ });
55
+ });
56
+
57
+ describe('loadMultiRepoTemplate', () => {
58
+ beforeEach(() => {
59
+ vi.clearAllMocks();
60
+ });
61
+
62
+ it('テンプレートファイルを読み込む', () => {
63
+ const mockContent = '# {{PROJECT_NAME}} - Requirements';
64
+ vi.spyOn(fs, 'readFileSync').mockReturnValue(mockContent);
65
+
66
+ const content = loadMultiRepoTemplate('overview/requirements', '/test/root');
67
+
68
+ expect(fs.readFileSync).toHaveBeenCalledWith(
69
+ '/test/root/templates/multi-repo/overview/requirements.md',
70
+ 'utf-8'
71
+ );
72
+ expect(content).toBe(mockContent);
73
+ });
74
+
75
+ it('テンプレートが存在しない場合はエラーをスロー', () => {
76
+ vi.spyOn(fs, 'readFileSync').mockImplementation(() => {
77
+ throw new Error('ENOENT: no such file or directory');
78
+ });
79
+
80
+ expect(() => loadMultiRepoTemplate('invalid/template', '/test/root')).toThrow(
81
+ 'Multi-Repo template not found: invalid/template.md'
82
+ );
83
+ });
84
+ });
85
+
86
+ describe('renderMultiRepoTemplate', () => {
87
+ it('プレースホルダーを置換する', () => {
88
+ const template = '# {{PROJECT_NAME}} - {{JIRA_KEY}}\n\nCreated: {{CREATED_AT}}';
89
+ const context: MultiRepoTemplateContext = {
90
+ PROJECT_NAME: 'test-project',
91
+ JIRA_KEY: 'TEST',
92
+ CONFLUENCE_SPACE: 'SPACE',
93
+ CREATED_AT: '2025-12-14T10:00:00Z',
94
+ };
95
+
96
+ const rendered = renderMultiRepoTemplate(template, context);
97
+
98
+ expect(rendered).toBe('# test-project - TEST\n\nCreated: 2025-12-14T10:00:00Z');
99
+ });
100
+
101
+ it('すべてのMulti-Repoプレースホルダーを置換する', () => {
102
+ const template = [
103
+ '{{PROJECT_NAME}}',
104
+ '{{JIRA_KEY}}',
105
+ '{{CONFLUENCE_SPACE}}',
106
+ '{{CREATED_AT}}',
107
+ ].join(' / ');
108
+
109
+ const context: MultiRepoTemplateContext = {
110
+ PROJECT_NAME: 'my-project',
111
+ JIRA_KEY: 'PROJ',
112
+ CONFLUENCE_SPACE: 'MYSPACE',
113
+ CREATED_AT: '2025-12-14T10:00:00Z',
114
+ };
115
+
116
+ const rendered = renderMultiRepoTemplate(template, context);
117
+
118
+ expect(rendered).toBe('my-project / PROJ / MYSPACE / 2025-12-14T10:00:00Z');
119
+ });
120
+
121
+ it('存在しないプレースホルダーはそのまま残す', () => {
122
+ const template = '{{PROJECT_NAME}} - {{UNKNOWN_PLACEHOLDER}}';
123
+ const context: MultiRepoTemplateContext = {
124
+ PROJECT_NAME: 'test-project',
125
+ JIRA_KEY: 'TEST',
126
+ CONFLUENCE_SPACE: 'SPACE',
127
+ CREATED_AT: '2025-12-14T10:00:00Z',
128
+ };
129
+
130
+ const rendered = renderMultiRepoTemplate(template, context);
131
+
132
+ expect(rendered).toBe('test-project - {{UNKNOWN_PLACEHOLDER}}');
133
+ });
134
+ });
135
+
136
+ describe('loadAndRenderMultiRepoTemplate', () => {
137
+ beforeEach(() => {
138
+ vi.clearAllMocks();
139
+ });
140
+
141
+ it('テンプレートを読み込んでレンダリングする', () => {
142
+ const mockContent = '# {{PROJECT_NAME}} Requirements\n\n**JIRA**: {{JIRA_KEY}}';
143
+ vi.spyOn(fs, 'readFileSync').mockReturnValue(mockContent);
144
+
145
+ const context: MultiRepoTemplateContext = {
146
+ PROJECT_NAME: 'test-project',
147
+ JIRA_KEY: 'TEST',
148
+ CONFLUENCE_SPACE: 'SPACE',
149
+ CREATED_AT: '2025-12-14T10:00:00Z',
150
+ };
151
+
152
+ const rendered = loadAndRenderMultiRepoTemplate(
153
+ 'overview/requirements',
154
+ context,
155
+ '/test/root'
156
+ );
157
+
158
+ expect(rendered).toBe('# test-project Requirements\n\n**JIRA**: TEST');
159
+ });
160
+ });
161
+
162
+ describe('renderMultiRepoTemplates', () => {
163
+ beforeEach(() => {
164
+ vi.clearAllMocks();
165
+ });
166
+
167
+ it('複数のテンプレートを一括レンダリングする', () => {
168
+ vi.spyOn(fs, 'readFileSync').mockImplementation((path) => {
169
+ if (path.toString().includes('requirements')) {
170
+ return '# {{PROJECT_NAME}} Requirements';
171
+ }
172
+ if (path.toString().includes('architecture')) {
173
+ return '# {{PROJECT_NAME}} Architecture';
174
+ }
175
+ return 'Template not found';
176
+ });
177
+
178
+ const context: MultiRepoTemplateContext = {
179
+ PROJECT_NAME: 'test-project',
180
+ JIRA_KEY: 'TEST',
181
+ CONFLUENCE_SPACE: 'SPACE',
182
+ CREATED_AT: '2025-12-14T10:00:00Z',
183
+ };
184
+
185
+ const rendered = renderMultiRepoTemplates(
186
+ ['overview/requirements', 'overview/architecture'],
187
+ context,
188
+ '/test/root'
189
+ );
190
+
191
+ expect(rendered['overview/requirements']).toBe('# test-project Requirements');
192
+ expect(rendered['overview/architecture']).toBe('# test-project Architecture');
193
+ });
194
+
195
+ it('空の配列を渡した場合は空のオブジェクトを返す', () => {
196
+ const context: MultiRepoTemplateContext = {
197
+ PROJECT_NAME: 'test-project',
198
+ JIRA_KEY: 'TEST',
199
+ CONFLUENCE_SPACE: 'SPACE',
200
+ CREATED_AT: '2025-12-14T10:00:00Z',
201
+ };
202
+
203
+ const rendered = renderMultiRepoTemplates([], context, '/test/root');
204
+
205
+ expect(rendered).toEqual({});
206
+ });
207
+ });
208
+
209
+ describe('MULTI_REPO_TEMPLATES', () => {
210
+ it('すべてのMulti-Repoテンプレート名を含む', () => {
211
+ expect(MULTI_REPO_TEMPLATES).toContain('overview/requirements');
212
+ expect(MULTI_REPO_TEMPLATES).toContain('overview/architecture');
213
+ expect(MULTI_REPO_TEMPLATES).toContain('overview/sequence');
214
+ expect(MULTI_REPO_TEMPLATES).toContain('steering/multi-repo');
215
+ expect(MULTI_REPO_TEMPLATES).toContain('tests/strategy');
216
+ expect(MULTI_REPO_TEMPLATES).toContain('docs/ci-status');
217
+ expect(MULTI_REPO_TEMPLATES).toContain('docs/release-notes');
218
+ });
219
+
220
+ it('テンプレート数は7つ', () => {
221
+ expect(MULTI_REPO_TEMPLATES.length).toBe(7);
222
+ });
223
+ });
224
+
225
+ describe('統合テスト', () => {
226
+ beforeEach(() => {
227
+ vi.clearAllMocks();
228
+ });
229
+
230
+ it('実際のテンプレートファイルをレンダリングできる(モック使用)', () => {
231
+ const mockRequirementsTemplate = `# {{PROJECT_NAME}} - 要件定義書
232
+
233
+ ## プロジェクト情報
234
+
235
+ - **プロジェクト名**: {{PROJECT_NAME}}
236
+ - **JIRAキー**: {{JIRA_KEY}}
237
+ - **Confluenceスペース**: {{CONFLUENCE_SPACE}}
238
+ - **作成日時**: {{CREATED_AT}}`;
239
+
240
+ vi.spyOn(fs, 'readFileSync').mockReturnValue(mockRequirementsTemplate);
241
+
242
+ const context: MultiRepoTemplateContext = {
243
+ PROJECT_NAME: 'my-awesome-project',
244
+ JIRA_KEY: 'AWESOME',
245
+ CONFLUENCE_SPACE: 'PROJ',
246
+ CREATED_AT: '2025-12-14T10:30:00Z',
247
+ };
248
+
249
+ const rendered = loadAndRenderMultiRepoTemplate(
250
+ 'overview/requirements',
251
+ context,
252
+ '/test/root'
253
+ );
254
+
255
+ expect(rendered).toContain('# my-awesome-project - 要件定義書');
256
+ expect(rendered).toContain('- **プロジェクト名**: my-awesome-project');
257
+ expect(rendered).toContain('- **JIRAキー**: AWESOME');
258
+ expect(rendered).toContain('- **Confluenceスペース**: PROJ');
259
+ expect(rendered).toContain('- **作成日時**: 2025-12-14T10:30:00Z');
260
+ });
261
+ });