@sk8metal/michi-cli 0.20.0 → 0.22.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 (124) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/README.md +1 -1
  3. package/dist/scripts/multi-project-estimate.js +4 -4
  4. package/dist/scripts/multi-project-estimate.js.map +1 -1
  5. package/dist/scripts/phase-runner.js +16 -16
  6. package/dist/scripts/phase-runner.js.map +1 -1
  7. package/dist/scripts/pr-automation.js +2 -2
  8. package/dist/scripts/pr-automation.js.map +1 -1
  9. package/dist/scripts/pre-flight-check.js +4 -4
  10. package/dist/scripts/pre-flight-check.js.map +1 -1
  11. package/dist/scripts/spec-impl-workflow.js +4 -4
  12. package/dist/scripts/spec-impl-workflow.js.map +1 -1
  13. package/dist/scripts/template/multi-repo-renderer.js +1 -1
  14. package/dist/scripts/template/multi-repo-renderer.js.map +1 -1
  15. package/dist/scripts/template/renderer.d.ts +6 -6
  16. package/dist/scripts/template/renderer.js +7 -7
  17. package/dist/scripts/test-execution-generator.js +11 -11
  18. package/dist/scripts/test-execution-generator.js.map +1 -1
  19. package/dist/scripts/utils/config-loader.d.ts +1 -1
  20. package/dist/scripts/utils/config-loader.js +4 -4
  21. package/dist/scripts/utils/config-loader.js.map +1 -1
  22. package/dist/scripts/utils/confluence-hierarchy.js +1 -1
  23. package/dist/scripts/utils/confluence-hierarchy.js.map +1 -1
  24. package/dist/scripts/utils/docker-requirement-detector.js +3 -3
  25. package/dist/scripts/utils/docker-requirement-detector.js.map +1 -1
  26. package/dist/scripts/utils/language-detector.js +2 -2
  27. package/dist/scripts/utils/language-detector.js.map +1 -1
  28. package/dist/scripts/utils/multi-repo-validator.d.ts +1 -1
  29. package/dist/scripts/utils/multi-repo-validator.js +3 -3
  30. package/dist/scripts/utils/multi-repo-validator.js.map +1 -1
  31. package/dist/scripts/utils/project-analyzer.d.ts +1 -1
  32. package/dist/scripts/utils/project-analyzer.js +2 -2
  33. package/dist/scripts/utils/project-analyzer.js.map +1 -1
  34. package/dist/scripts/utils/spec-archiver.d.ts +1 -1
  35. package/dist/scripts/utils/spec-archiver.js +5 -5
  36. package/dist/scripts/utils/spec-archiver.js.map +1 -1
  37. package/dist/scripts/utils/spec-updater.js +2 -2
  38. package/dist/scripts/utils/spec-updater.js.map +1 -1
  39. package/dist/scripts/utils/tasks-converter.js +2 -2
  40. package/dist/scripts/utils/tasks-converter.js.map +1 -1
  41. package/dist/scripts/utils/template-applier.js +1 -1
  42. package/dist/scripts/utils/template-applier.js.map +1 -1
  43. package/dist/scripts/validate-phase.js +4 -4
  44. package/dist/scripts/validate-phase.js.map +1 -1
  45. package/dist/src/application/use-cases/spec/archive-spec.js +1 -1
  46. package/dist/src/application/use-cases/spec/archive-spec.js.map +1 -1
  47. package/dist/src/commands/migrate.js +14 -14
  48. package/dist/src/commands/migrate.js.map +1 -1
  49. package/dist/src/infrastructure/external-apis/atlassian/confluence/hierarchy.js +1 -1
  50. package/dist/src/infrastructure/external-apis/atlassian/confluence/hierarchy.js.map +1 -1
  51. package/dist/src/infrastructure/external-apis/atlassian/confluence/sync-service.js +2 -2
  52. package/dist/src/infrastructure/external-apis/atlassian/confluence/sync-service.js.map +1 -1
  53. package/dist/src/infrastructure/external-apis/atlassian/jira/issue-builder.js +1 -1
  54. package/dist/src/infrastructure/external-apis/atlassian/jira/issue-builder.js.map +1 -1
  55. package/dist/src/infrastructure/external-apis/atlassian/jira/sync-service.js +3 -3
  56. package/dist/src/infrastructure/external-apis/atlassian/jira/sync-service.js.map +1 -1
  57. package/dist/src/infrastructure/filesystem/project-meta.d.ts +1 -1
  58. package/dist/src/infrastructure/filesystem/project-meta.js +2 -2
  59. package/dist/src/infrastructure/filesystem/project-meta.js.map +1 -1
  60. package/dist/src/presentation/commands/init/handler.js +1 -1
  61. package/dist/src/presentation/commands/init/handler.js.map +1 -1
  62. package/dist/src/presentation/commands/init/register.js +2 -2
  63. package/dist/src/presentation/commands/init/register.js.map +1 -1
  64. package/dist/src/presentation/commands/init/setup.d.ts +1 -1
  65. package/dist/src/presentation/commands/init/setup.js +6 -6
  66. package/dist/src/presentation/commands/init/setup.js.map +1 -1
  67. package/dist/src/presentation/commands/init/templates.js +5 -5
  68. package/dist/src/presentation/commands/init/templates.js.map +1 -1
  69. package/dist/src/presentation/commands/workflow/orchestrator.js +2 -2
  70. package/dist/src/presentation/commands/workflow/orchestrator.js.map +1 -1
  71. package/docs/MIGRATION.md +2 -2
  72. package/docs/architecture.md +5 -5
  73. package/docs/getting-started/configuration.md +2 -2
  74. package/docs/guides/claude-code.md +10 -10
  75. package/docs/guides/comprehensive-verification-guide.md +29 -29
  76. package/docs/guides/interactive-config.md +2 -2
  77. package/docs/guides/workflow.md +25 -25
  78. package/docs/onion-architecture-phase0-complete.md +1 -1
  79. package/docs/reference/ai-commands.md +12 -12
  80. package/docs/reference/cli.md +4 -4
  81. package/docs/reference/environment-variables.md +1 -1
  82. package/docs/troubleshooting.md +6 -6
  83. package/package.json +1 -1
  84. package/scripts/README.md +2 -3
  85. package/scripts/__tests__/create-project.test.ts +6 -6
  86. package/scripts/__tests__/multi-project-estimate.test.ts +1 -1
  87. package/scripts/build/README.md +1 -1
  88. package/scripts/multi-project-estimate.ts +4 -4
  89. package/scripts/phase-runner.ts +16 -16
  90. package/scripts/pr-automation.ts +2 -2
  91. package/scripts/pre-flight-check.ts +4 -4
  92. package/scripts/spec-impl-workflow.ts +4 -4
  93. package/scripts/template/__tests__/renderer.test.ts +34 -34
  94. package/scripts/template/multi-repo-renderer.ts +1 -1
  95. package/scripts/template/renderer.ts +9 -9
  96. package/scripts/test-execution-generator.ts +11 -11
  97. package/scripts/utils/__tests__/config-loader.test.ts +14 -9
  98. package/scripts/utils/__tests__/config-validator.test.ts +8 -8
  99. package/scripts/utils/__tests__/multi-repo-validator.test.ts +17 -17
  100. package/scripts/utils/__tests__/project-analyzer.test.ts +28 -28
  101. package/scripts/utils/__tests__/project-meta.test.ts +22 -22
  102. package/scripts/utils/__tests__/spec-updater.test.ts +3 -3
  103. package/scripts/utils/config-loader.ts +6 -6
  104. package/scripts/utils/confluence-hierarchy.ts +1 -1
  105. package/scripts/utils/docker-requirement-detector.ts +3 -3
  106. package/scripts/utils/language-detector.ts +2 -2
  107. package/scripts/utils/multi-repo-validator.ts +3 -3
  108. package/scripts/utils/project-analyzer.ts +2 -2
  109. package/scripts/utils/spec-archiver.ts +5 -5
  110. package/scripts/utils/spec-updater.ts +2 -2
  111. package/scripts/utils/tasks-converter.ts +2 -2
  112. package/scripts/utils/template-applier.ts +1 -1
  113. package/scripts/validate-phase.ts +4 -4
  114. package/templates/claude-agent/README.md +1 -1
  115. package/templates/claude-agent/agents/designer.md +4 -4
  116. package/templates/claude-agent/agents/developer.md +2 -2
  117. package/templates/claude-agent/agents/doc-reviewer.md +4 -4
  118. package/templates/claude-agent/agents/manager-agent.md +3 -3
  119. package/templates/claude-agent/agents/repo-spec-executor.md +1 -1
  120. package/templates/claude-agent/agents/tester.md +3 -3
  121. package/templates/claude-agent/commands/kiro/kiro-spec-impl.md +6 -6
  122. package/templates/claude-agent/commands/kiro/kiro-spec-tasks.md +10 -10
  123. package/templates/claude-agent/rules/doc-review.md +1 -1
  124. package/templates/common/.kiro/project.json.template +0 -21
@@ -175,9 +175,9 @@ export async function generateLoadTestExecution(
175
175
  const files: string[] = [];
176
176
 
177
177
  try {
178
- const designPath = join(projectRoot, '.kiro', 'specs', feature, 'design.md');
179
- const requirementsPath = join(projectRoot, '.kiro', 'specs', feature, 'requirements.md');
180
- const outputDir = join(projectRoot, '.kiro', 'specs', feature, 'test-execution', 'performance');
178
+ const designPath = join(projectRoot, '.michi', 'specs', feature, 'design.md');
179
+ const requirementsPath = join(projectRoot, '.michi', 'specs', feature, 'requirements.md');
180
+ const outputDir = join(projectRoot, '.michi', 'specs', feature, 'test-execution', 'performance');
181
181
 
182
182
  mkdirSync(outputDir, { recursive: true });
183
183
 
@@ -327,7 +327,7 @@ pip install locust
327
327
 
328
328
  \`\`\`bash
329
329
  # このディレクトリに移動
330
- cd .kiro/specs/${feature}/test-execution/performance
330
+ cd .michi/specs/${feature}/test-execution/performance
331
331
 
332
332
  # Locust起動(Web UI)
333
333
  locust -f locustfile.py
@@ -369,8 +369,8 @@ export async function generateSecurityTestExecution(
369
369
  const files: string[] = [];
370
370
 
371
371
  try {
372
- const designPath = join(projectRoot, '.kiro', 'specs', feature, 'design.md');
373
- const outputDir = join(projectRoot, '.kiro', 'specs', feature, 'test-execution', 'security');
372
+ const designPath = join(projectRoot, '.michi', 'specs', feature, 'design.md');
373
+ const outputDir = join(projectRoot, '.michi', 'specs', feature, 'test-execution', 'security');
374
374
 
375
375
  mkdirSync(outputDir, { recursive: true });
376
376
 
@@ -530,7 +530,7 @@ function generateSecurityTestPlan(
530
530
 
531
531
  \`\`\`bash
532
532
  # このディレクトリに移動
533
- cd .kiro/specs/${feature}/test-execution/security
533
+ cd .michi/specs/${feature}/test-execution/security
534
534
 
535
535
  # スキャン実行
536
536
  ./run-zap-scan.sh
@@ -564,8 +564,8 @@ export async function generateManualRegressionExecution(
564
564
  const files: string[] = [];
565
565
 
566
566
  try {
567
- const designPath = join(projectRoot, '.kiro', 'specs', feature, 'design.md');
568
- const outputDir = join(projectRoot, '.kiro', 'specs', feature, 'test-execution', 'manual-regression');
567
+ const designPath = join(projectRoot, '.michi', 'specs', feature, 'design.md');
568
+ const outputDir = join(projectRoot, '.michi', 'specs', feature, 'test-execution', 'manual-regression');
569
569
 
570
570
  mkdirSync(outputDir, { recursive: true });
571
571
 
@@ -658,7 +658,7 @@ export async function generateIntegrationE2EExecution(
658
658
  const files: string[] = [];
659
659
 
660
660
  try {
661
- const outputDir = join(projectRoot, '.kiro', 'specs', feature, 'test-execution', testType);
661
+ const outputDir = join(projectRoot, '.michi', 'specs', feature, 'test-execution', testType);
662
662
  mkdirSync(outputDir, { recursive: true });
663
663
 
664
664
  // チェックリストを生成
@@ -766,7 +766,7 @@ export async function generateAllTestExecutions(
766
766
  feature: string,
767
767
  projectRoot: string = process.cwd()
768
768
  ): Promise<GenerationResult[]> {
769
- const selectionPath = join(projectRoot, '.kiro', 'specs', feature, 'test-type-selection.json');
769
+ const selectionPath = join(projectRoot, '.michi', 'specs', feature, 'test-type-selection.json');
770
770
 
771
771
  if (!existsSync(selectionPath)) {
772
772
  throw new Error('test-type-selection.jsonが存在しません。先にtest-type-selectionフェーズを実行してください');
@@ -143,6 +143,10 @@ describe('config-loader', () => {
143
143
  rmSync(legacyDir, { recursive: true, force: true });
144
144
  }
145
145
 
146
+ // .michiディレクトリを作成
147
+ const michiDir = join(testProjectRoot, '.michi');
148
+ mkdirSync(michiDir, { recursive: true });
149
+
146
150
  const configPath = join(testProjectRoot, '.michi/config.json');
147
151
  writeFileSync(configPath, JSON.stringify({
148
152
  confluence: {
@@ -209,7 +213,7 @@ describe('config-loader', () => {
209
213
  rmSync(michiDir, { recursive: true, force: true });
210
214
  }
211
215
 
212
- // legacyパスにファイルを作成
216
+ // legacyパス(.kiro)にファイルを作成
213
217
  mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
214
218
  const legacyConfigPath = join(testProjectRoot, '.kiro/config.json');
215
219
  writeFileSync(legacyConfigPath, JSON.stringify({
@@ -230,13 +234,14 @@ describe('config-loader', () => {
230
234
 
231
235
  consoleWarnSpy.mockRestore();
232
236
 
233
- // 次のテストのために.michiディレクトリを再作成
237
+ // 次のテストのために.michiディレクトリを作成
234
238
  mkdirSync(michiDir, { recursive: true });
235
239
  });
236
240
 
237
241
  it('legacyパスと新規パスの両方が存在する場合は警告を表示しない', () => {
238
242
  // 両方のパスにファイルを作成
239
243
  mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
244
+ mkdirSync(join(testProjectRoot, '.michi'), { recursive: true });
240
245
  const legacyConfigPath = join(testProjectRoot, '.kiro/config.json');
241
246
  const michiConfigPath = join(testProjectRoot, '.michi/config.json');
242
247
  writeFileSync(legacyConfigPath, JSON.stringify({}));
@@ -297,9 +302,9 @@ describe('config-loader', () => {
297
302
  it('project.jsonからプロジェクトメタデータを読み込む', () => {
298
303
  clearConfigCache();
299
304
 
300
- // .kiro/project.json を作成
301
- const projectJsonPath = join(testProjectRoot, '.kiro', 'project.json');
302
- mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
305
+ // .michi/project.json を作成
306
+ const projectJsonPath = join(testProjectRoot, '.michi', 'project.json');
307
+ mkdirSync(join(testProjectRoot, '.michi'), { recursive: true });
303
308
  writeFileSync(projectJsonPath, JSON.stringify({
304
309
  projectId: 'test-project',
305
310
  projectName: 'Test Project',
@@ -316,8 +321,8 @@ describe('config-loader', () => {
316
321
  it('project.jsonが存在しない場合でもエラーにならない', () => {
317
322
  clearConfigCache();
318
323
 
319
- // .kiro/project.json を削除
320
- const projectJsonPath = join(testProjectRoot, '.kiro', 'project.json');
324
+ // .michi/project.json を削除
325
+ const projectJsonPath = join(testProjectRoot, '.michi', 'project.json');
321
326
  if (existsSync(projectJsonPath)) {
322
327
  unlinkSync(projectJsonPath);
323
328
  }
@@ -374,8 +379,8 @@ describe('config-loader', () => {
374
379
  clearConfigCache();
375
380
 
376
381
  // 最初の設定
377
- const projectJsonPath = join(testProjectRoot, '.kiro', 'project.json');
378
- mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
382
+ const projectJsonPath = join(testProjectRoot, '.michi', 'project.json');
383
+ mkdirSync(join(testProjectRoot, '.michi'), { recursive: true });
379
384
  writeFileSync(projectJsonPath, JSON.stringify({
380
385
  projectId: 'initial-id',
381
386
  projectName: 'Initial Name'
@@ -477,8 +477,8 @@ describe('config-validator', () => {
477
477
  );
478
478
 
479
479
  // project.jsonを作成
480
- const projectJsonPath = join(testProjectRoot, '.kiro/project.json');
481
- mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
480
+ const projectJsonPath = join(testProjectRoot, '.michi/project.json');
481
+ mkdirSync(join(testProjectRoot, '.michi'), { recursive: true });
482
482
  writeFileSync(
483
483
  projectJsonPath,
484
484
  JSON.stringify({
@@ -510,8 +510,8 @@ describe('config-validator', () => {
510
510
  );
511
511
 
512
512
  // project.jsonを作成(すべての必須フィールドを含める)
513
- const projectJsonPath = join(testProjectRoot, '.kiro/project.json');
514
- mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
513
+ const projectJsonPath = join(testProjectRoot, '.michi/project.json');
514
+ mkdirSync(join(testProjectRoot, '.michi'), { recursive: true });
515
515
  writeFileSync(
516
516
  projectJsonPath,
517
517
  JSON.stringify({
@@ -562,8 +562,8 @@ describe('config-validator', () => {
562
562
  );
563
563
 
564
564
  // project.jsonを作成(すべての必須フィールドを含める)
565
- const projectJsonPath = join(testProjectRoot, '.kiro/project.json');
566
- mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
565
+ const projectJsonPath = join(testProjectRoot, '.michi/project.json');
566
+ mkdirSync(join(testProjectRoot, '.michi'), { recursive: true });
567
567
  writeFileSync(
568
568
  projectJsonPath,
569
569
  JSON.stringify({
@@ -613,8 +613,8 @@ describe('config-validator', () => {
613
613
  );
614
614
 
615
615
  // project.jsonを作成(すべての必須フィールドを含める)
616
- const projectJsonPath = join(testProjectRoot, '.kiro/project.json');
617
- mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
616
+ const projectJsonPath = join(testProjectRoot, '.michi/project.json');
617
+ mkdirSync(join(testProjectRoot, '.michi'), { recursive: true });
618
618
  writeFileSync(
619
619
  projectJsonPath,
620
620
  JSON.stringify({
@@ -355,13 +355,13 @@ describe('hasMichiSetup', () => {
355
355
  });
356
356
 
357
357
  describe('Michi導入済みの場合', () => {
358
- it('.kiro/project.json が存在する場合はtrueを返す', () => {
359
- // .kiro ディレクトリを作成
360
- const kiroDir = path.join(tempDir, '.kiro');
361
- fs.mkdirSync(kiroDir);
358
+ it('.michi/project.json が存在する場合はtrueを返す', () => {
359
+ // .michi ディレクトリを作成
360
+ const specDir = path.join(tempDir, '.michi');
361
+ fs.mkdirSync(specDir);
362
362
 
363
363
  // project.json を作成
364
- const projectJson = path.join(kiroDir, 'project.json');
364
+ const projectJson = path.join(specDir, 'project.json');
365
365
  fs.writeFileSync(projectJson, '{}');
366
366
 
367
367
  const result = hasMichiSetup(tempDir);
@@ -370,17 +370,17 @@ describe('hasMichiSetup', () => {
370
370
  });
371
371
 
372
372
  describe('Michi未導入の場合', () => {
373
- it('.kiro/project.json が存在しない場合はfalseを返す', () => {
374
- // .kiro ディレクトリのみ作成(project.jsonなし)
375
- const kiroDir = path.join(tempDir, '.kiro');
376
- fs.mkdirSync(kiroDir);
373
+ it('.michi/project.json が存在しない場合はfalseを返す', () => {
374
+ // .michi ディレクトリのみ作成(project.jsonなし)
375
+ const specDir = path.join(tempDir, '.michi');
376
+ fs.mkdirSync(specDir);
377
377
 
378
378
  const result = hasMichiSetup(tempDir);
379
379
  expect(result).toBe(false);
380
380
  });
381
381
 
382
- it('.kiro ディレクトリ自体が存在しない場合はfalseを返す', () => {
383
- // .kiro ディレクトリを作成しない
382
+ it('.michi ディレクトリ自体が存在しない場合はfalseを返す', () => {
383
+ // .michi ディレクトリを作成しない
384
384
  const result = hasMichiSetup(tempDir);
385
385
  expect(result).toBe(false);
386
386
  });
@@ -455,10 +455,10 @@ describe('validateLocalPath - Michi導入チェック', () => {
455
455
  // .git ディレクトリを作成(Gitリポジトリとして認識させる)
456
456
  fs.mkdirSync(path.join(tempDir, '.git'));
457
457
 
458
- // .kiro/project.json を作成(Michi導入済み)
459
- const kiroDir = path.join(tempDir, '.kiro');
460
- fs.mkdirSync(kiroDir);
461
- fs.writeFileSync(path.join(kiroDir, 'project.json'), '{}');
458
+ // .michi/project.json を作成(Michi導入済み)
459
+ const specDir = path.join(tempDir, '.michi');
460
+ fs.mkdirSync(specDir);
461
+ fs.writeFileSync(path.join(specDir, 'project.json'), '{}');
462
462
 
463
463
  const result = validateLocalPath(repository);
464
464
  expect(result.hasMichiSetup).toBe(true);
@@ -469,13 +469,13 @@ describe('validateLocalPath - Michi導入チェック', () => {
469
469
  // .git ディレクトリを作成(Gitリポジトリとして認識させる)
470
470
  fs.mkdirSync(path.join(tempDir, '.git'));
471
471
 
472
- // .kiro/project.json は作成しない(Michi未導入)
472
+ // .michi/project.json は作成しない(Michi未導入)
473
473
 
474
474
  const result = validateLocalPath(repository);
475
475
  expect(result.hasMichiSetup).toBe(false);
476
476
  expect(result.michiSetupCommand).not.toBeNull();
477
477
  expect(result.warnings).toContain(
478
- `Repository 'test-repo' does not have Michi setup (.kiro/project.json not found)`,
478
+ `Repository 'test-repo' does not have Michi setup (.michi/project.json not found)`,
479
479
  );
480
480
  });
481
481
 
@@ -129,10 +129,10 @@ describe('ProjectAnalyzer', () => {
129
129
  });
130
130
 
131
131
  describe('getProjectMetadata', () => {
132
- it('should load project metadata from .kiro/project.json', () => {
133
- // Setup: create .kiro/project.json
134
- const kiroDir = join(testDir, '.kiro');
135
- mkdirSync(kiroDir);
132
+ it('should load project metadata from .michi/project.json', () => {
133
+ // Setup: create .michi/project.json
134
+ const specDir = join(testDir, '.michi');
135
+ mkdirSync(specDir);
136
136
  const projectJson = {
137
137
  projectId: 'test-project',
138
138
  projectName: 'Test Project',
@@ -143,7 +143,7 @@ describe('ProjectAnalyzer', () => {
143
143
  stakeholders: ['pm1'],
144
144
  repository: 'https://github.com/test/repo'
145
145
  };
146
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectJson));
146
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectJson));
147
147
 
148
148
  // Execute
149
149
  const result = analyzer.getProjectMetadata(testDir);
@@ -157,7 +157,7 @@ describe('ProjectAnalyzer', () => {
157
157
  }
158
158
  });
159
159
 
160
- it('should return error if .kiro/project.json does not exist', () => {
160
+ it('should return error if .michi/project.json does not exist', () => {
161
161
  // Execute
162
162
  const result = analyzer.getProjectMetadata(testDir);
163
163
 
@@ -169,10 +169,10 @@ describe('ProjectAnalyzer', () => {
169
169
  });
170
170
 
171
171
  it('should return error if project.json has invalid JSON', () => {
172
- // Setup: create .kiro/project.json with invalid JSON
173
- const kiroDir = join(testDir, '.kiro');
174
- mkdirSync(kiroDir);
175
- writeFileSync(join(kiroDir, 'project.json'), '{ invalid json }');
172
+ // Setup: create .michi/project.json with invalid JSON
173
+ const specDir = join(testDir, '.michi');
174
+ mkdirSync(specDir);
175
+ writeFileSync(join(specDir, 'project.json'), '{ invalid json }');
176
176
 
177
177
  // Execute
178
178
  const result = analyzer.getProjectMetadata(testDir);
@@ -186,15 +186,15 @@ describe('ProjectAnalyzer', () => {
186
186
 
187
187
  it('should reject path traversal attacks in projectId (..)', () => {
188
188
  // Setup: malicious projectId
189
- const kiroDir = join(testDir, '.kiro');
190
- mkdirSync(kiroDir);
189
+ const specDir = join(testDir, '.michi');
190
+ mkdirSync(specDir);
191
191
  const projectJson = {
192
192
  projectId: '../tmp/evil',
193
193
  projectName: 'Evil Project',
194
194
  jiraProjectKey: 'EVIL',
195
195
  confluenceLabels: ['test']
196
196
  };
197
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectJson));
197
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectJson));
198
198
 
199
199
  // Execute
200
200
  const result = analyzer.getProjectMetadata(testDir);
@@ -208,15 +208,15 @@ describe('ProjectAnalyzer', () => {
208
208
 
209
209
  it('should reject path traversal attacks in projectId (/)', () => {
210
210
  // Setup: malicious projectId
211
- const kiroDir = join(testDir, '.kiro');
212
- mkdirSync(kiroDir);
211
+ const specDir = join(testDir, '.michi');
212
+ mkdirSync(specDir);
213
213
  const projectJson = {
214
214
  projectId: 'foo/bar',
215
215
  projectName: 'Evil Project',
216
216
  jiraProjectKey: 'EVIL',
217
217
  confluenceLabels: ['test']
218
218
  };
219
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectJson));
219
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectJson));
220
220
 
221
221
  // Execute
222
222
  const result = analyzer.getProjectMetadata(testDir);
@@ -230,15 +230,15 @@ describe('ProjectAnalyzer', () => {
230
230
 
231
231
  it('should reject path traversal attacks in projectId (\\)', () => {
232
232
  // Setup: malicious projectId
233
- const kiroDir = join(testDir, '.kiro');
234
- mkdirSync(kiroDir);
233
+ const specDir = join(testDir, '.michi');
234
+ mkdirSync(specDir);
235
235
  const projectJson = {
236
236
  projectId: 'foo\\bar',
237
237
  projectName: 'Evil Project',
238
238
  jiraProjectKey: 'EVIL',
239
239
  confluenceLabels: ['test']
240
240
  };
241
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectJson));
241
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectJson));
242
242
 
243
243
  // Execute
244
244
  const result = analyzer.getProjectMetadata(testDir);
@@ -252,15 +252,15 @@ describe('ProjectAnalyzer', () => {
252
252
 
253
253
  it('should reject empty projectId', () => {
254
254
  // Setup: empty projectId
255
- const kiroDir = join(testDir, '.kiro');
256
- mkdirSync(kiroDir);
255
+ const specDir = join(testDir, '.michi');
256
+ mkdirSync(specDir);
257
257
  const projectJson = {
258
258
  projectId: ' ',
259
259
  projectName: 'Test Project',
260
260
  jiraProjectKey: 'TEST',
261
261
  confluenceLabels: ['test']
262
262
  };
263
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectJson));
263
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectJson));
264
264
 
265
265
  // Execute
266
266
  const result = analyzer.getProjectMetadata(testDir);
@@ -274,15 +274,15 @@ describe('ProjectAnalyzer', () => {
274
274
 
275
275
  it('should reject projectId with invalid characters', () => {
276
276
  // Setup: invalid characters in projectId
277
- const kiroDir = join(testDir, '.kiro');
278
- mkdirSync(kiroDir);
277
+ const specDir = join(testDir, '.michi');
278
+ mkdirSync(specDir);
279
279
  const projectJson = {
280
280
  projectId: 'test@project!',
281
281
  projectName: 'Test Project',
282
282
  jiraProjectKey: 'TEST',
283
283
  confluenceLabels: ['test']
284
284
  };
285
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectJson));
285
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectJson));
286
286
 
287
287
  // Execute
288
288
  const result = analyzer.getProjectMetadata(testDir);
@@ -296,8 +296,8 @@ describe('ProjectAnalyzer', () => {
296
296
 
297
297
  it('should accept valid projectId with alphanumeric, hyphens, and underscores', () => {
298
298
  // Setup: valid projectId
299
- const kiroDir = join(testDir, '.kiro');
300
- mkdirSync(kiroDir);
299
+ const specDir = join(testDir, '.michi');
300
+ mkdirSync(specDir);
301
301
  const projectJson = {
302
302
  projectId: 'Valid-Project_123',
303
303
  projectName: 'Test Project',
@@ -308,7 +308,7 @@ describe('ProjectAnalyzer', () => {
308
308
  stakeholders: [],
309
309
  repository: ''
310
310
  };
311
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectJson));
311
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectJson));
312
312
 
313
313
  // Execute
314
314
  const result = analyzer.getProjectMetadata(testDir);
@@ -26,8 +26,8 @@ describe('project-meta', () => {
26
26
 
27
27
  describe('loadProjectMeta', () => {
28
28
  it('正しいproject.jsonを読み込める', () => {
29
- const kiroDir = join(testRoot, '.kiro');
30
- mkdirSync(kiroDir, { recursive: true });
29
+ const specDir = join(testRoot, '.michi');
30
+ mkdirSync(specDir, { recursive: true });
31
31
 
32
32
  const projectMeta = {
33
33
  projectId: 'test-project',
@@ -40,7 +40,7 @@ describe('project-meta', () => {
40
40
  repository: 'https://github.com/owner/repo.git',
41
41
  };
42
42
 
43
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(projectMeta, null, 2));
43
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(projectMeta, null, 2));
44
44
 
45
45
  const result = loadProjectMeta(testRoot);
46
46
 
@@ -51,21 +51,21 @@ describe('project-meta', () => {
51
51
  expect(() => loadProjectMeta(testRoot)).toThrow('Project metadata not found');
52
52
  });
53
53
 
54
- it('.kiroディレクトリが存在しない場合はエラー', () => {
54
+ it('.michiディレクトリが存在しない場合はエラー', () => {
55
55
  expect(() => loadProjectMeta(testRoot)).toThrow('Project metadata not found');
56
56
  });
57
57
 
58
58
  it('不正なJSON形式の場合はエラー', () => {
59
- const kiroDir = join(testRoot, '.kiro');
60
- mkdirSync(kiroDir, { recursive: true });
61
- writeFileSync(join(kiroDir, 'project.json'), 'invalid json');
59
+ const specDir = join(testRoot, '.michi');
60
+ mkdirSync(specDir, { recursive: true });
61
+ writeFileSync(join(specDir, 'project.json'), 'invalid json');
62
62
 
63
63
  expect(() => loadProjectMeta(testRoot)).toThrow('Invalid JSON');
64
64
  });
65
65
 
66
66
  it('必須フィールド projectName が欠けている場合はエラー', () => {
67
- const kiroDir = join(testRoot, '.kiro');
68
- mkdirSync(kiroDir, { recursive: true });
67
+ const specDir = join(testRoot, '.michi');
68
+ mkdirSync(specDir, { recursive: true });
69
69
 
70
70
  const invalidMeta = {
71
71
  projectId: 'test-project',
@@ -78,14 +78,14 @@ describe('project-meta', () => {
78
78
  repository: 'https://github.com/owner/repo.git',
79
79
  };
80
80
 
81
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(invalidMeta));
81
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(invalidMeta));
82
82
 
83
83
  expect(() => loadProjectMeta(testRoot)).toThrow('Required field missing');
84
84
  });
85
85
 
86
86
  it('必須フィールド confluenceLabels が欠けている場合はエラー', () => {
87
- const kiroDir = join(testRoot, '.kiro');
88
- mkdirSync(kiroDir, { recursive: true });
87
+ const specDir = join(testRoot, '.michi');
88
+ mkdirSync(specDir, { recursive: true });
89
89
 
90
90
  const invalidMeta = {
91
91
  projectId: 'test-project',
@@ -98,7 +98,7 @@ describe('project-meta', () => {
98
98
  repository: 'https://github.com/owner/repo.git',
99
99
  };
100
100
 
101
- writeFileSync(join(kiroDir, 'project.json'), JSON.stringify(invalidMeta));
101
+ writeFileSync(join(specDir, 'project.json'), JSON.stringify(invalidMeta));
102
102
 
103
103
  expect(() => loadProjectMeta(testRoot)).toThrow('Required field missing');
104
104
  });
@@ -117,13 +117,13 @@ describe('project-meta', () => {
117
117
  });
118
118
 
119
119
  beforeEach(() => {
120
- const kiroDir = join(testRoot, '.kiro');
121
- mkdirSync(kiroDir, { recursive: true });
120
+ const specDir = join(testRoot, '.michi');
121
+ mkdirSync(specDir, { recursive: true });
122
122
  });
123
123
 
124
124
  it('HTTPS URL (.git付き) から owner/repo を抽出できる', () => {
125
125
  const projectMeta = createValidProjectMeta('https://github.com/owner/repo.git');
126
- writeFileSync(join(testRoot, '.kiro/project.json'), JSON.stringify(projectMeta));
126
+ writeFileSync(join(testRoot, '.michi/project.json'), JSON.stringify(projectMeta));
127
127
 
128
128
  const result = getRepositoryInfo(testRoot);
129
129
  expect(result).toBe('owner/repo');
@@ -131,7 +131,7 @@ describe('project-meta', () => {
131
131
 
132
132
  it('HTTPS URL (.gitなし) から owner/repo を抽出できる', () => {
133
133
  const projectMeta = createValidProjectMeta('https://github.com/owner/repo');
134
- writeFileSync(join(testRoot, '.kiro/project.json'), JSON.stringify(projectMeta));
134
+ writeFileSync(join(testRoot, '.michi/project.json'), JSON.stringify(projectMeta));
135
135
 
136
136
  const result = getRepositoryInfo(testRoot);
137
137
  expect(result).toBe('owner/repo');
@@ -139,7 +139,7 @@ describe('project-meta', () => {
139
139
 
140
140
  it('SSH URL (.git付き) から owner/repo を抽出できる', () => {
141
141
  const projectMeta = createValidProjectMeta('git@github.com:owner/repo.git');
142
- writeFileSync(join(testRoot, '.kiro/project.json'), JSON.stringify(projectMeta));
142
+ writeFileSync(join(testRoot, '.michi/project.json'), JSON.stringify(projectMeta));
143
143
 
144
144
  const result = getRepositoryInfo(testRoot);
145
145
  expect(result).toBe('owner/repo');
@@ -147,7 +147,7 @@ describe('project-meta', () => {
147
147
 
148
148
  it('SSH URL (.gitなし) から owner/repo を抽出できる', () => {
149
149
  const projectMeta = createValidProjectMeta('git@github.com:owner/repo');
150
- writeFileSync(join(testRoot, '.kiro/project.json'), JSON.stringify(projectMeta));
150
+ writeFileSync(join(testRoot, '.michi/project.json'), JSON.stringify(projectMeta));
151
151
 
152
152
  const result = getRepositoryInfo(testRoot);
153
153
  expect(result).toBe('owner/repo');
@@ -165,21 +165,21 @@ describe('project-meta', () => {
165
165
  repository: '',
166
166
  };
167
167
 
168
- writeFileSync(join(testRoot, '.kiro/project.json'), JSON.stringify(projectMeta));
168
+ writeFileSync(join(testRoot, '.michi/project.json'), JSON.stringify(projectMeta));
169
169
 
170
170
  expect(() => getRepositoryInfo(testRoot)).toThrow('Repository information not found');
171
171
  });
172
172
 
173
173
  it('不正な repository 形式の場合はエラー', () => {
174
174
  const projectMeta = createValidProjectMeta('https://example.com/not-github/repo.git');
175
- writeFileSync(join(testRoot, '.kiro/project.json'), JSON.stringify(projectMeta));
175
+ writeFileSync(join(testRoot, '.michi/project.json'), JSON.stringify(projectMeta));
176
176
 
177
177
  expect(() => getRepositoryInfo(testRoot)).toThrow('Invalid GitHub repository format');
178
178
  });
179
179
 
180
180
  it('owner/repo にハイフンが含まれる場合も正しく抽出できる', () => {
181
181
  const projectMeta = createValidProjectMeta('https://github.com/my-org/my-repo.git');
182
- writeFileSync(join(testRoot, '.kiro/project.json'), JSON.stringify(projectMeta));
182
+ writeFileSync(join(testRoot, '.michi/project.json'), JSON.stringify(projectMeta));
183
183
 
184
184
  const result = getRepositoryInfo(testRoot);
185
185
  expect(result).toBe('my-org/my-repo');
@@ -22,7 +22,7 @@ describe('spec-updater', () => {
22
22
  if (existsSync(testDir)) {
23
23
  rmSync(testDir, { recursive: true });
24
24
  }
25
- mkdirSync(resolve(testDir, '.kiro/specs', testFeatureName), { recursive: true });
25
+ mkdirSync(resolve(testDir, '.michi/specs', testFeatureName), { recursive: true });
26
26
  });
27
27
 
28
28
  afterEach(() => {
@@ -45,7 +45,7 @@ describe('spec-updater', () => {
45
45
  });
46
46
 
47
47
  it('spec.jsonが存在する場合、その内容を返す', () => {
48
- const specPath = resolve(testDir, '.kiro/specs', testFeatureName, 'spec.json');
48
+ const specPath = resolve(testDir, '.michi/specs', testFeatureName, 'spec.json');
49
49
  const testSpec: SpecJson = {
50
50
  featureName: testFeatureName,
51
51
  projectName: 'Test Project',
@@ -74,7 +74,7 @@ describe('spec-updater', () => {
74
74
 
75
75
  saveSpecJson(testFeatureName, spec, testDir);
76
76
 
77
- const specPath = resolve(testDir, '.kiro/specs', testFeatureName, 'spec.json');
77
+ const specPath = resolve(testDir, '.michi/specs', testFeatureName, 'spec.json');
78
78
  expect(existsSync(specPath)).toBe(true);
79
79
 
80
80
  const saved = JSON.parse(readFileSync(specPath, 'utf-8'));
@@ -190,7 +190,7 @@ function validateConfigPath(configPath: string, projectRoot: string): boolean {
190
190
  function resolveConfigPath(projectRoot: string): string {
191
191
  const michiConfigPath = resolve(projectRoot, '.michi/config.json');
192
192
  const legacyConfigPath = resolve(projectRoot, '.kiro/config.json');
193
-
193
+
194
194
  // legacyパスが存在する場合は警告(移行推奨)
195
195
  if (existsSync(legacyConfigPath) && !existsSync(michiConfigPath)) {
196
196
  console.warn(
@@ -199,7 +199,7 @@ function resolveConfigPath(projectRoot: string): string {
199
199
  ' The legacy path will not be supported in future versions.\n'
200
200
  );
201
201
  }
202
-
202
+
203
203
  return michiConfigPath;
204
204
  }
205
205
 
@@ -306,10 +306,10 @@ function loadProjectEnv(projectRoot: string): Record<string, string> {
306
306
 
307
307
  /**
308
308
  * プロジェクトメタデータを読み込み
309
- * .kiro/project.json からプロジェクト情報を読み込む
309
+ * .michi/project.json からプロジェクト情報を読み込む
310
310
  */
311
311
  function loadProjectMetadata(projectRoot: string): Partial<AppConfig> | null {
312
- const projectJsonPath = resolve(projectRoot, '.kiro/project.json');
312
+ const projectJsonPath = resolve(projectRoot, '.michi/project.json');
313
313
 
314
314
  if (!existsSync(projectJsonPath)) {
315
315
  return null;
@@ -392,7 +392,7 @@ function applyEnvVarsToConfig(
392
392
  * 1. デフォルト設定
393
393
  * 2. グローバル.env(~/.michi/.env)
394
394
  * 3. グローバル設定(~/.michi/config.json)
395
- * 4. プロジェクトメタデータ(.kiro/project.json)
395
+ * 4. プロジェクトメタデータ(.michi/project.json)
396
396
  * 5. プロジェクト設定(.michi/config.json)
397
397
  * 6. プロジェクト.env(.env)- 最高優先度
398
398
  */
@@ -451,7 +451,7 @@ export function getConfig(projectRoot: string = process.cwd()): AppConfig {
451
451
  const projectConfigPath = resolveConfigPath(projectRoot);
452
452
  const globalConfigPath = getGlobalConfigPath();
453
453
  const globalEnvPath = getGlobalEnvPath();
454
- const projectMetaPath = resolve(projectRoot, '.kiro/project.json');
454
+ const projectMetaPath = resolve(projectRoot, '.michi/project.json');
455
455
  const projectEnvPath = resolve(projectRoot, '.env');
456
456
  const currentFileUrl = import.meta.url;
457
457
  const currentFilePath = fileURLToPath(currentFileUrl);
@@ -209,7 +209,7 @@ async function getOrCreateParentPage(
209
209
  // 親ページを作成
210
210
  const parentContent = createConfluencePage({
211
211
  title: parentTitle,
212
- githubUrl: `${projectMeta.repository}/tree/main/.kiro/specs/${featureName}`,
212
+ githubUrl: `${projectMeta.repository}/tree/main/.michi/specs/${featureName}`,
213
213
  content: `<p>機能: <strong>${featureName}</strong></p><p>このページの下に、要件定義・設計・タスク分割のページが配置されます。</p>`,
214
214
  approvers: projectMeta.stakeholders,
215
215
  projectName: projectMeta.projectName