@sk8metal/michi-cli 0.4.0 → 0.5.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 (99) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/scripts/__tests__/spec-impl-workflow.test.js +4 -2
  3. package/dist/scripts/__tests__/spec-impl-workflow.test.js.map +1 -1
  4. package/dist/scripts/config/config-schema.d.ts +52 -0
  5. package/dist/scripts/config/config-schema.d.ts.map +1 -1
  6. package/dist/scripts/config/config-schema.js +25 -0
  7. package/dist/scripts/config/config-schema.js.map +1 -1
  8. package/dist/scripts/pr-automation.d.ts.map +1 -1
  9. package/dist/scripts/pr-automation.js +11 -3
  10. package/dist/scripts/pr-automation.js.map +1 -1
  11. package/dist/scripts/spec-impl-workflow.d.ts.map +1 -1
  12. package/dist/scripts/spec-impl-workflow.js +22 -6
  13. package/dist/scripts/spec-impl-workflow.js.map +1 -1
  14. package/dist/scripts/utils/__tests__/config-loader.test.js +114 -1
  15. package/dist/scripts/utils/__tests__/config-loader.test.js.map +1 -1
  16. package/dist/scripts/utils/__tests__/config-validator.test.js +2 -0
  17. package/dist/scripts/utils/__tests__/config-validator.test.js.map +1 -1
  18. package/dist/scripts/utils/__tests__/env-config.test.js +0 -2
  19. package/dist/scripts/utils/__tests__/env-config.test.js.map +1 -1
  20. package/dist/scripts/utils/__tests__/project-meta.test.d.ts +6 -0
  21. package/dist/scripts/utils/__tests__/project-meta.test.d.ts.map +1 -0
  22. package/dist/scripts/utils/__tests__/project-meta.test.js +154 -0
  23. package/dist/scripts/utils/__tests__/project-meta.test.js.map +1 -0
  24. package/dist/scripts/utils/__tests__/security-validator.test.d.ts +6 -0
  25. package/dist/scripts/utils/__tests__/security-validator.test.d.ts.map +1 -0
  26. package/dist/scripts/utils/__tests__/security-validator.test.js +219 -0
  27. package/dist/scripts/utils/__tests__/security-validator.test.js.map +1 -0
  28. package/dist/scripts/utils/config-loader.d.ts +10 -4
  29. package/dist/scripts/utils/config-loader.d.ts.map +1 -1
  30. package/dist/scripts/utils/config-loader.js +214 -47
  31. package/dist/scripts/utils/config-loader.js.map +1 -1
  32. package/dist/scripts/utils/env-config.d.ts +1 -1
  33. package/dist/scripts/utils/env-config.d.ts.map +1 -1
  34. package/dist/scripts/utils/env-config.js +2 -14
  35. package/dist/scripts/utils/env-config.js.map +1 -1
  36. package/dist/scripts/utils/project-meta.d.ts +9 -0
  37. package/dist/scripts/utils/project-meta.d.ts.map +1 -1
  38. package/dist/scripts/utils/project-meta.js +22 -0
  39. package/dist/scripts/utils/project-meta.js.map +1 -1
  40. package/dist/scripts/utils/security-validator.d.ts +55 -0
  41. package/dist/scripts/utils/security-validator.d.ts.map +1 -0
  42. package/dist/scripts/utils/security-validator.js +232 -0
  43. package/dist/scripts/utils/security-validator.js.map +1 -0
  44. package/dist/src/cli.d.ts.map +1 -1
  45. package/dist/src/cli.js +41 -3
  46. package/dist/src/cli.js.map +1 -1
  47. package/dist/src/commands/__tests__/init.test.d.ts +5 -0
  48. package/dist/src/commands/__tests__/init.test.d.ts.map +1 -0
  49. package/dist/src/commands/__tests__/init.test.js +255 -0
  50. package/dist/src/commands/__tests__/init.test.js.map +1 -0
  51. package/dist/src/commands/__tests__/migrate.test.d.ts +5 -0
  52. package/dist/src/commands/__tests__/migrate.test.d.ts.map +1 -0
  53. package/dist/src/commands/__tests__/migrate.test.js +216 -0
  54. package/dist/src/commands/__tests__/migrate.test.js.map +1 -0
  55. package/dist/src/commands/config-validate.d.ts +9 -0
  56. package/dist/src/commands/config-validate.d.ts.map +1 -0
  57. package/dist/src/commands/config-validate.js +90 -0
  58. package/dist/src/commands/config-validate.js.map +1 -0
  59. package/dist/src/commands/init.d.ts +1 -0
  60. package/dist/src/commands/init.d.ts.map +1 -1
  61. package/dist/src/commands/init.js +29 -6
  62. package/dist/src/commands/init.js.map +1 -1
  63. package/dist/src/commands/migrate.d.ts +25 -0
  64. package/dist/src/commands/migrate.d.ts.map +1 -0
  65. package/dist/src/commands/migrate.js +341 -0
  66. package/dist/src/commands/migrate.js.map +1 -0
  67. package/dist/src/commands/setup-existing.d.ts.map +1 -1
  68. package/dist/src/commands/setup-existing.js +0 -1
  69. package/dist/src/commands/setup-existing.js.map +1 -1
  70. package/dist/vitest.config.d.ts.map +1 -1
  71. package/dist/vitest.config.js +32 -8
  72. package/dist/vitest.config.js.map +1 -1
  73. package/docs/michi-development/design/config-unification.md +4789 -0
  74. package/docs/user-guide/getting-started/github-token-setup.md +2 -1
  75. package/docs/user-guide/getting-started/new-repository-setup.md +1 -1
  76. package/docs/user-guide/getting-started/quick-start.md +1 -1
  77. package/docs/user-guide/getting-started/setup.md +4 -11
  78. package/docs/user-guide/hands-on/claude-agent-setup.md +2 -2
  79. package/docs/user-guide/hands-on/claude-setup.md +2 -2
  80. package/docs/user-guide/hands-on/cursor-setup.md +2 -2
  81. package/docs/user-guide/hands-on/workflow-walkthrough.md +4 -1
  82. package/env.example +1 -1
  83. package/package.json +2 -2
  84. package/scripts/__tests__/spec-impl-workflow.test.ts +5 -2
  85. package/scripts/config/config-schema.ts +40 -0
  86. package/scripts/pr-automation.ts +15 -5
  87. package/scripts/spec-impl-workflow.ts +22 -6
  88. package/scripts/utils/__tests__/config-loader.test.ts +149 -0
  89. package/scripts/utils/__tests__/config-validator.test.ts +2 -0
  90. package/scripts/utils/__tests__/env-config.test.ts +0 -2
  91. package/scripts/utils/__tests__/project-meta.test.ts +192 -0
  92. package/scripts/utils/__tests__/security-validator.test.ts +272 -0
  93. package/scripts/utils/config-loader.ts +232 -53
  94. package/scripts/utils/env-config.ts +2 -14
  95. package/scripts/utils/project-meta.ts +27 -0
  96. package/scripts/utils/security-validator.ts +286 -0
  97. package/templates/claude/commands/kiro/kiro-spec-impl.md +1 -1
  98. package/templates/claude-agent/commands/kiro/kiro-spec-impl.md +1 -1
  99. package/templates/cursor/commands/kiro/kiro-spec-impl.md +1 -1
@@ -230,9 +230,10 @@ nano .env
230
230
  # GitHub設定
231
231
  GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
232
232
  GITHUB_ORG=your-organization # または your-username
233
- GITHUB_REPO=your-org/your-repo
234
233
  ```
235
234
 
235
+ > **Note (v0.5.0以降)**: `GITHUB_REPO` 環境変数は廃止されました。リポジトリ情報は `.kiro/project.json` の `repository` フィールドから自動的に取得されます。
236
+
236
237
  **セキュリティ**:
237
238
  ```bash
238
239
  # .env ファイルのパーミッションを600に設定
@@ -316,7 +316,7 @@ ATLASSIAN_API_TOKEN=your-token-here
316
316
  # GitHub設定
317
317
  GITHUB_ORG=your-org
318
318
  GITHUB_TOKEN=ghp_xxx
319
- GITHUB_REPO=your-org/20240115-payment-api
319
+ # Note: リポジトリ情報は .kiro/project.json の repository フィールドで管理されます
320
320
 
321
321
  # Confluence共有スペース
322
322
  CONFLUENCE_PRD_SPACE=PRD
@@ -76,7 +76,7 @@ cat > .env <<EOF
76
76
  # GitHub設定(必須)
77
77
  GITHUB_TOKEN=your-github-token
78
78
  GITHUB_ORG=your-org
79
- GITHUB_REPO=your-org/your-repo
79
+ # Note: リポジトリ情報は .kiro/project.json の repository フィールドで管理されます
80
80
 
81
81
  # JIRA設定(オプション)
82
82
  ATLASSIAN_URL=https://your-domain.atlassian.net
@@ -230,8 +230,7 @@ ATLASSIAN_API_TOKEN=<ATLASSIANトークン>
230
230
  # GitHub設定
231
231
  GITHUB_ORG=your-org
232
232
  GITHUB_TOKEN=<GitHubトークン>
233
- # 開発したいリポジトリ
234
- GITHUB_REPO=your-org/user-auth
233
+ # Note: リポジトリ情報は .kiro/project.json の repository フィールドで管理されます
235
234
 
236
235
  # Confluence設定
237
236
  CONFLUENCE_PRD_SPACE=PRD
@@ -285,15 +284,9 @@ SLACK_WEBHOOK_URL=<SlackWebhook URL>
285
284
  - **確認方法**: 3-3セクション「GitHub Token」を参照
286
285
  - **使用機能**: すべてのGitHub連携機能で認証に使用(API呼び出し時の認証トークン)
287
286
 
288
- **`GITHUB_REPO`**
289
- - **確認方法**: GitHubリポジトリのURLから取得
290
- - **確認手順**:
291
- 1. リポジトリのページにアクセス(例: `https://github.com/org/repo`)
292
- 2. URLの `/org/repo` 部分がリポジトリ名
293
- - **形式**: `組織名/リポジトリ名`
294
- - **例**: `sk8metalme/michi`
295
- - **使用機能**:
296
- - PR自動作成(`michi github:create-pr`): 指定されたリポジトリにPull Requestを作成(ワークフロー自動化で使用)
287
+ > **Note**: リポジトリ情報(以前の `GITHUB_REPO` 環境変数)は `.kiro/project.json` の `repository` フィールドで管理されるようになりました。
288
+ > 形式: `https://github.com/org/repo.git` または `git@github.com:org/repo.git`
289
+ > 例: `.kiro/project.json` に `"repository": "https://github.com/sk8metalme/michi.git"` と設定
297
290
 
298
291
  ##### Confluence設定
299
292
 
@@ -187,9 +187,10 @@ vim .env
187
187
  # GitHub設定(必須)
188
188
  GITHUB_TOKEN=ghp_your_token_here
189
189
  GITHUB_ORG=your-org
190
- GITHUB_REPO=your-org/your-repo
191
190
  ```
192
191
 
192
+ > **Note (v0.5.0以降)**: `GITHUB_REPO` 環境変数は廃止されました。リポジトリ情報は `.kiro/project.json` の `repository` フィールドから自動的に取得されます。
193
+
193
194
  **完全な設定(Confluence/JIRA連携も使用)**:
194
195
 
195
196
  ```bash
@@ -201,7 +202,6 @@ ATLASSIAN_API_TOKEN=your-token-here
201
202
  # GitHub設定
202
203
  GITHUB_ORG=your-org
203
204
  GITHUB_TOKEN=ghp_xxx
204
- GITHUB_REPO=your-org/your-repo
205
205
 
206
206
  # Confluence共有スペース
207
207
  CONFLUENCE_PRD_SPACE=PRD
@@ -173,9 +173,10 @@ vim .env
173
173
  # GitHub設定(必須)
174
174
  GITHUB_TOKEN=ghp_your_token_here
175
175
  GITHUB_ORG=your-org
176
- GITHUB_REPO=your-org/your-repo
177
176
  ```
178
177
 
178
+ > **Note (v0.5.0以降)**: `GITHUB_REPO` 環境変数は廃止されました。リポジトリ情報は `.kiro/project.json` の `repository` フィールドから自動的に取得されます。
179
+
179
180
  **完全な設定(Confluence/JIRA連携も使用)**:
180
181
 
181
182
  ```bash
@@ -187,7 +188,6 @@ ATLASSIAN_API_TOKEN=your-token-here
187
188
  # GitHub設定
188
189
  GITHUB_ORG=your-org
189
190
  GITHUB_TOKEN=ghp_xxx
190
- GITHUB_REPO=your-org/your-repo
191
191
 
192
192
  # Confluence共有スペース
193
193
  CONFLUENCE_PRD_SPACE=PRD
@@ -140,9 +140,10 @@ vim .env
140
140
  # GitHub設定(必須)
141
141
  GITHUB_TOKEN=ghp_your_token_here
142
142
  GITHUB_ORG=your-org
143
- GITHUB_REPO=your-org/your-repo
144
143
  ```
145
144
 
145
+ > **Note (v0.5.0以降)**: `GITHUB_REPO` 環境変数は廃止されました。リポジトリ情報は `.kiro/project.json` の `repository` フィールドから自動的に取得されます。
146
+
146
147
  **完全な設定(Confluence/JIRA連携も使用)**:
147
148
 
148
149
  ```bash
@@ -154,7 +155,6 @@ ATLASSIAN_API_TOKEN=your-token-here
154
155
  # GitHub設定
155
156
  GITHUB_ORG=your-org
156
157
  GITHUB_TOKEN=ghp_xxx
157
- GITHUB_REPO=your-org/your-repo
158
158
 
159
159
  # Confluence共有スペース
160
160
  CONFLUENCE_PRD_SPACE=PRD
@@ -182,7 +182,10 @@ vim .env
182
182
  # 最低限、以下を設定:
183
183
  # GITHUB_TOKEN=your-token
184
184
  # GITHUB_ORG=your-org
185
- # GITHUB_REPO=your-org/your-repo
185
+ ```
186
+
187
+ > **Note (v0.5.0以降)**: `GITHUB_REPO` 環境変数は廃止されました。リポジトリ情報は `.kiro/project.json` の `repository` フィールドから自動的に取得されます。
188
+
186
189
  ```
187
190
 
188
191
  詳細: [Cursor IDEセットアップガイド](./cursor-setup.md)
package/env.example CHANGED
@@ -6,7 +6,7 @@ ATLASSIAN_API_TOKEN=your-atlassian-api-token-here
6
6
  # GitHub設定
7
7
  GITHUB_ORG=your-github-org
8
8
  GITHUB_TOKEN=your-github-token-here
9
- GITHUB_REPO=your-org/your-repo
9
+ # Note: GITHUB_REPO is deprecated. Use .kiro/project.json's repository field instead.
10
10
 
11
11
  # Confluence設定
12
12
  CONFLUENCE_PRD_SPACE=PRD
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sk8metal/michi-cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Managed Intelligent Comprehensive Hub for Integration - AI-driven development workflow automation",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -72,7 +72,7 @@
72
72
  "test:ui": "vitest --ui",
73
73
  "test:coverage": "vitest --run --coverage",
74
74
  "test:integration:setup": "vitest --run src/__tests__/integration/setup",
75
- "test:coverage:setup": "vitest --run --coverage src/__tests__/integration/setup",
75
+ "test:coverage:setup": "vitest --run --coverage --coverage.thresholds.lines=0 --coverage.thresholds.functions=0 --coverage.thresholds.branches=0 --coverage.thresholds.statements=0 src/__tests__/integration/setup",
76
76
  "lint": "eslint .",
77
77
  "lint:fix": "eslint . --fix",
78
78
  "format": "prettier --write .",
@@ -32,6 +32,11 @@ vi.mock('../utils/config-loader.js', () => ({
32
32
  })),
33
33
  }));
34
34
 
35
+ // project-metaをモック
36
+ vi.mock('../utils/project-meta.js', () => ({
37
+ getRepositoryInfo: vi.fn(() => 'owner/repo'),
38
+ }));
39
+
35
40
  // spec-loaderをモック
36
41
  const mockGetJiraInfoFromSpec = vi.fn();
37
42
  const mockCheckJiraInfoStatus = vi.fn();
@@ -62,7 +67,6 @@ describe('spec-impl-workflow', () => {
62
67
  process.env.ATLASSIAN_EMAIL = 'test@example.com';
63
68
  process.env.ATLASSIAN_API_TOKEN = 'test-token';
64
69
  process.env.GITHUB_TOKEN = 'github-token';
65
- process.env.GITHUB_REPO = 'owner/repo';
66
70
  });
67
71
 
68
72
  afterEach(() => {
@@ -71,7 +75,6 @@ describe('spec-impl-workflow', () => {
71
75
  delete process.env.ATLASSIAN_EMAIL;
72
76
  delete process.env.ATLASSIAN_API_TOKEN;
73
77
  delete process.env.GITHUB_TOKEN;
74
- delete process.env.GITHUB_REPO;
75
78
  });
76
79
 
77
80
  // ==========================================================================
@@ -146,6 +146,31 @@ export const ValidationConfigSchema = z.object({
146
146
  weekendExclusion: z.boolean().default(true),
147
147
  });
148
148
 
149
+ /**
150
+ * Atlassian設定スキーマ
151
+ */
152
+ export const AtlassianConfigSchema = z.object({
153
+ url: z.string().optional(),
154
+ email: z.string().optional(),
155
+ apiToken: z.string().optional(),
156
+ });
157
+
158
+ /**
159
+ * プロジェクトメタデータスキーマ
160
+ */
161
+ export const ProjectMetaSchema = z.object({
162
+ projectId: z.string().min(1),
163
+ projectName: z.string().min(1),
164
+ language: z.enum(['ja', 'en']).optional(),
165
+ jiraProjectKey: z.string().optional(),
166
+ confluenceLabels: z.array(z.string()).optional(),
167
+ status: z.string().optional(),
168
+ team: z.array(z.string()).optional(),
169
+ stakeholders: z.array(z.string()).optional(),
170
+ repository: z.string().optional(),
171
+ description: z.string().optional(),
172
+ });
173
+
149
174
  /**
150
175
  * 全体設定スキーマ
151
176
  */
@@ -154,6 +179,8 @@ export const AppConfigSchema = z.object({
154
179
  jira: JiraConfigSchema.optional(),
155
180
  workflow: WorkflowConfigSchema.optional(),
156
181
  validation: ValidationConfigSchema.optional(),
182
+ atlassian: AtlassianConfigSchema.optional(),
183
+ project: ProjectMetaSchema.optional(),
157
184
  });
158
185
 
159
186
  /**
@@ -177,4 +204,17 @@ export type JiraStatusMapping = z.infer<typeof JiraStatusMappingSchema>;
177
204
  export type JiraConfig = z.infer<typeof JiraConfigSchema>;
178
205
  export type WorkflowConfig = z.infer<typeof WorkflowConfigSchema>;
179
206
  export type ValidationConfig = z.infer<typeof ValidationConfigSchema>;
207
+ export type AtlassianConfig = z.infer<typeof AtlassianConfigSchema>;
208
+ export type ProjectMeta = z.infer<typeof ProjectMetaSchema>;
180
209
  export type AppConfig = z.infer<typeof AppConfigSchema>;
210
+
211
+ /**
212
+ * 設定の読み込み元
213
+ */
214
+ export type ConfigSource =
215
+ | 'default' // default-config.json
216
+ | 'global-env' // ~/.michi/.env
217
+ | 'global-config' // ~/.michi/config.json
218
+ | 'project-meta' // .kiro/project.json
219
+ | 'project-config' // .michi/config.json
220
+ | 'project-env'; // .env
@@ -15,13 +15,23 @@ interface PROptions {
15
15
  }
16
16
 
17
17
  async function createPR(options: PROptions): Promise<void> {
18
+ const { getRepositoryInfo } = await import('./utils/project-meta.js');
18
19
  const token = process.env.GITHUB_TOKEN;
19
- const repo = process.env.GITHUB_REPO;
20
-
21
- if (!token || !repo) {
22
- throw new Error('Missing GitHub credentials');
20
+
21
+ if (!token) {
22
+ throw new Error('Missing GitHub credentials. Required: GITHUB_TOKEN');
23
23
  }
24
-
24
+
25
+ // .kiro/project.json から repository 情報を取得
26
+ let repo: string;
27
+ try {
28
+ repo = getRepositoryInfo();
29
+ } catch (error) {
30
+ throw new Error(
31
+ `Failed to get repository info from .kiro/project.json: ${error instanceof Error ? error.message : error}`,
32
+ );
33
+ }
34
+
25
35
  const [owner, repoName] = repo.split('/');
26
36
  const octokit = new Octokit({ auth: token });
27
37
 
@@ -258,12 +258,20 @@ ${jiraLink}
258
258
  *この PR は spec-impl ワークフローで自動作成されました*`;
259
259
 
260
260
  const { Octokit } = await import('@octokit/rest');
261
+ const { getRepositoryInfo } = await import('./utils/project-meta.js');
261
262
  const token = process.env.GITHUB_TOKEN;
262
- const repo = process.env.GITHUB_REPO;
263
263
 
264
- if (!token || !repo) {
264
+ if (!token) {
265
+ throw new Error('Missing GitHub credentials. Required: GITHUB_TOKEN');
266
+ }
267
+
268
+ // .kiro/project.json から repository 情報を取得
269
+ let repo: string;
270
+ try {
271
+ repo = getRepositoryInfo();
272
+ } catch (error) {
265
273
  throw new Error(
266
- 'Missing GitHub credentials. Required: GITHUB_TOKEN, GITHUB_REPO',
274
+ `Failed to get repository info from .kiro/project.json: ${error instanceof Error ? error.message : error}`,
267
275
  );
268
276
  }
269
277
 
@@ -393,12 +401,20 @@ export async function onSpecImplEnd(
393
401
 
394
402
  // PR 作成
395
403
  const { Octokit } = await import('@octokit/rest');
404
+ const { getRepositoryInfo } = await import('./utils/project-meta.js');
396
405
  const token = process.env.GITHUB_TOKEN;
397
- const repo = process.env.GITHUB_REPO;
398
406
 
399
- if (!token || !repo) {
407
+ if (!token) {
408
+ throw new Error('Missing GitHub credentials. Required: GITHUB_TOKEN');
409
+ }
410
+
411
+ // .kiro/project.json から repository 情報を取得
412
+ let repo: string;
413
+ try {
414
+ repo = getRepositoryInfo();
415
+ } catch (error) {
400
416
  throw new Error(
401
- 'Missing GitHub credentials. Required: GITHUB_TOKEN, GITHUB_REPO',
417
+ `Failed to get repository info from .kiro/project.json: ${error instanceof Error ? error.message : error}`,
402
418
  );
403
419
  }
404
420
 
@@ -10,6 +10,7 @@ import {
10
10
  loadConfig,
11
11
  getConfig,
12
12
  getConfigPath,
13
+ getGlobalEnvPath,
13
14
  clearConfigCache
14
15
  } from '../config-loader.js';
15
16
 
@@ -32,6 +33,9 @@ describe('config-loader', () => {
32
33
  // 環境変数をバックアップ
33
34
  originalEnv = { ...process.env };
34
35
 
36
+ // HOMEディレクトリをテスト用に変更(グローバル設定の影響を排除)
37
+ process.env.HOME = testProjectRoot;
38
+
35
39
  // キャッシュをクリア(クリーンな状態から開始)
36
40
  clearConfigCache();
37
41
  });
@@ -250,5 +254,150 @@ describe('config-loader', () => {
250
254
  consoleWarnSpy.mockRestore();
251
255
  });
252
256
  });
257
+
258
+ describe('5層階層対応', () => {
259
+ describe('getGlobalEnvPath', () => {
260
+ it('~/.michi/.envのパスを返す', () => {
261
+ const envPath = getGlobalEnvPath();
262
+ expect(envPath).toBe(join(process.env.HOME as string, '.michi', '.env'));
263
+ });
264
+ });
265
+
266
+ describe('グローバル.envからの設定読み込み', () => {
267
+ it('グローバル.envからAtlassian設定を読み込む', () => {
268
+ clearConfigCache();
269
+
270
+ // ~/.michi/.env を作成
271
+ const globalEnvPath = join(testProjectRoot, '.michi', '.env');
272
+ writeFileSync(globalEnvPath, 'ATLASSIAN_URL=https://test.atlassian.net\n');
273
+
274
+ const config = loadConfig(testProjectRoot);
275
+
276
+ // グローバル.envの値が読み込まれることを確認
277
+ expect(config).toHaveProperty('atlassian');
278
+ // 注: 実装後に具体的なアサーションを追加
279
+ });
280
+
281
+ it('グローバル.envが存在しない場合でもエラーにならない', () => {
282
+ clearConfigCache();
283
+
284
+ // ~/.michi/.env を削除
285
+ const globalEnvPath = join(testProjectRoot, '.michi', '.env');
286
+ if (existsSync(globalEnvPath)) {
287
+ unlinkSync(globalEnvPath);
288
+ }
289
+
290
+ expect(() => {
291
+ loadConfig(testProjectRoot);
292
+ }).not.toThrow();
293
+ });
294
+ });
295
+
296
+ describe('project.jsonからの設定読み込み', () => {
297
+ it('project.jsonからプロジェクトメタデータを読み込む', () => {
298
+ clearConfigCache();
299
+
300
+ // .kiro/project.json を作成
301
+ const projectJsonPath = join(testProjectRoot, '.kiro', 'project.json');
302
+ mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
303
+ writeFileSync(projectJsonPath, JSON.stringify({
304
+ projectId: 'test-project',
305
+ projectName: 'Test Project',
306
+ jiraProjectKey: 'TP'
307
+ }));
308
+
309
+ const config = loadConfig(testProjectRoot);
310
+
311
+ // project.jsonの値が読み込まれることを確認
312
+ expect(config).toHaveProperty('project');
313
+ // 注: 実装後に具体的なアサーションを追加
314
+ });
315
+
316
+ it('project.jsonが存在しない場合でもエラーにならない', () => {
317
+ clearConfigCache();
318
+
319
+ // .kiro/project.json を削除
320
+ const projectJsonPath = join(testProjectRoot, '.kiro', 'project.json');
321
+ if (existsSync(projectJsonPath)) {
322
+ unlinkSync(projectJsonPath);
323
+ }
324
+
325
+ expect(() => {
326
+ loadConfig(testProjectRoot);
327
+ }).not.toThrow();
328
+ });
329
+ });
330
+
331
+ describe('優先順位の検証', () => {
332
+ it('プロジェクト.envがグローバル.envより優先される', () => {
333
+ clearConfigCache();
334
+
335
+ // グローバル.env
336
+ const globalEnvPath = join(testProjectRoot, '.michi', '.env');
337
+ writeFileSync(globalEnvPath, 'CONFLUENCE_PRD_SPACE=GLOBAL\n');
338
+
339
+ // プロジェクト.env
340
+ const projectEnvPath = join(testProjectRoot, '.env');
341
+ writeFileSync(projectEnvPath, 'CONFLUENCE_PRD_SPACE=PROJECT\n');
342
+
343
+ const config = loadConfig(testProjectRoot);
344
+
345
+ // プロジェクト.envの値が優先されることを確認
346
+ expect(config.confluence?.spaces?.requirements).toBe('PROJECT');
347
+ });
348
+ });
349
+
350
+ describe('キャッシュ無効化', () => {
351
+ it('グローバル.envを変更するとキャッシュが無効化される', async () => {
352
+ clearConfigCache();
353
+
354
+ // 最初の設定
355
+ const globalEnvPath = join(testProjectRoot, '.michi', '.env');
356
+ writeFileSync(globalEnvPath, 'CONFLUENCE_PRD_SPACE=INITIAL\n');
357
+
358
+ const config1 = getConfig(testProjectRoot);
359
+
360
+ // ファイルシステムのmtime精度を考慮して少し待つ
361
+ await new Promise(resolve => setTimeout(resolve, 10));
362
+
363
+ // 設定を更新
364
+ writeFileSync(globalEnvPath, 'CONFLUENCE_PRD_SPACE=UPDATED\n');
365
+
366
+ const config2 = getConfig(testProjectRoot);
367
+
368
+ // 異なる値が返されることを確認(キャッシュが無効化された)
369
+ expect(config1.confluence?.spaces?.requirements).toBe('INITIAL');
370
+ expect(config2.confluence?.spaces?.requirements).toBe('UPDATED');
371
+ });
372
+
373
+ it('project.jsonを変更するとキャッシュが無効化される', async () => {
374
+ clearConfigCache();
375
+
376
+ // 最初の設定
377
+ const projectJsonPath = join(testProjectRoot, '.kiro', 'project.json');
378
+ mkdirSync(join(testProjectRoot, '.kiro'), { recursive: true });
379
+ writeFileSync(projectJsonPath, JSON.stringify({
380
+ projectId: 'initial-id',
381
+ projectName: 'Initial Name'
382
+ }));
383
+
384
+ const config1 = getConfig(testProjectRoot);
385
+
386
+ // ファイルシステムのmtime精度を考慮して少し待つ
387
+ await new Promise(resolve => setTimeout(resolve, 10));
388
+
389
+ // 設定を更新
390
+ writeFileSync(projectJsonPath, JSON.stringify({
391
+ projectId: 'updated-id',
392
+ projectName: 'Updated Name'
393
+ }));
394
+
395
+ const config2 = getConfig(testProjectRoot);
396
+
397
+ // 異なるオブジェクトが返されることを確認(キャッシュが無効化された)
398
+ expect(config1).not.toBe(config2);
399
+ });
400
+ });
401
+ });
253
402
  });
254
403
 
@@ -393,6 +393,8 @@ describe('config-validator', () => {
393
393
  writeFileSync(
394
394
  projectJsonPath,
395
395
  JSON.stringify({
396
+ projectId: 'test-project',
397
+ projectName: 'Test Project',
396
398
  jiraProjectKey: 'TEST',
397
399
  }),
398
400
  );
@@ -185,7 +185,6 @@ URL_WITH_PARAMS=https://example.com?param1=value1&param2=value2
185
185
  ['ATLASSIAN_API_TOKEN', 'token123'],
186
186
  ['GITHUB_ORG', 'myorg'],
187
187
  ['GITHUB_TOKEN', 'ghp_xxx'],
188
- ['GITHUB_REPO', 'myorg/myrepo'],
189
188
  ['CONFLUENCE_PRD_SPACE', 'PRD'],
190
189
  ['CONFLUENCE_QA_SPACE', 'QA'],
191
190
  ['CONFLUENCE_RELEASE_SPACE', 'RELEASE'],
@@ -217,7 +216,6 @@ ATLASSIAN_API_TOKEN=test_token_123
217
216
  # GitHub設定
218
217
  GITHUB_ORG=testorg
219
218
  GITHUB_TOKEN=ghp_test123
220
- GITHUB_REPO=testorg/testrepo
221
219
 
222
220
  # Confluence共有スペース
223
221
  CONFLUENCE_PRD_SPACE=PRD