@sk8metal/michi-cli 0.0.1 → 0.0.3

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 (57) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +60 -24
  3. package/dist/scripts/__tests__/validate-phase.test.d.ts +5 -0
  4. package/dist/scripts/__tests__/validate-phase.test.d.ts.map +1 -0
  5. package/dist/scripts/__tests__/validate-phase.test.js +162 -0
  6. package/dist/scripts/__tests__/validate-phase.test.js.map +1 -0
  7. package/dist/scripts/utils/__tests__/config-validator.test.d.ts +5 -0
  8. package/dist/scripts/utils/__tests__/config-validator.test.d.ts.map +1 -0
  9. package/dist/scripts/utils/__tests__/config-validator.test.js +247 -0
  10. package/dist/scripts/utils/__tests__/config-validator.test.js.map +1 -0
  11. package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts +5 -0
  12. package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts.map +1 -0
  13. package/dist/scripts/utils/__tests__/feature-name-validator.test.js +106 -0
  14. package/dist/scripts/utils/__tests__/feature-name-validator.test.js.map +1 -0
  15. package/dist/scripts/utils/config-loader.js +1 -1
  16. package/dist/scripts/utils/config-loader.js.map +1 -1
  17. package/dist/scripts/utils/confluence-hierarchy.d.ts.map +1 -1
  18. package/dist/scripts/utils/confluence-hierarchy.js +2 -1
  19. package/dist/scripts/utils/confluence-hierarchy.js.map +1 -1
  20. package/dist/src/__tests__/cli.test.d.ts +5 -0
  21. package/dist/src/__tests__/cli.test.d.ts.map +1 -0
  22. package/dist/src/__tests__/cli.test.js +58 -0
  23. package/dist/src/__tests__/cli.test.js.map +1 -0
  24. package/dist/src/cli.js +0 -0
  25. package/dist/vitest.config.d.ts +3 -0
  26. package/dist/vitest.config.d.ts.map +1 -0
  27. package/dist/vitest.config.js +29 -0
  28. package/dist/vitest.config.js.map +1 -0
  29. package/docs/setup.md +1 -1
  30. package/package.json +8 -4
  31. package/scripts/__tests__/README.md +101 -0
  32. package/scripts/__tests__/validate-phase.test.ts +185 -0
  33. package/scripts/config/config-schema.ts +130 -0
  34. package/scripts/config/default-config.json +57 -0
  35. package/scripts/config-interactive.ts +494 -0
  36. package/scripts/confluence-sync.ts +503 -0
  37. package/scripts/create-project.ts +293 -0
  38. package/scripts/jira-sync.ts +644 -0
  39. package/scripts/list-projects.ts +85 -0
  40. package/scripts/markdown-to-confluence.ts +161 -0
  41. package/scripts/multi-project-estimate.ts +255 -0
  42. package/scripts/phase-runner.ts +303 -0
  43. package/scripts/pr-automation.ts +67 -0
  44. package/scripts/pre-flight-check.ts +285 -0
  45. package/scripts/resource-dashboard.ts +124 -0
  46. package/scripts/setup-env.sh +52 -0
  47. package/scripts/setup-existing-project.ts +381 -0
  48. package/scripts/setup-existing.sh +145 -0
  49. package/scripts/utils/__tests__/config-validator.test.ts +302 -0
  50. package/scripts/utils/__tests__/feature-name-validator.test.ts +129 -0
  51. package/scripts/utils/config-loader.ts +326 -0
  52. package/scripts/utils/config-validator.ts +347 -0
  53. package/scripts/utils/confluence-hierarchy.ts +855 -0
  54. package/scripts/utils/feature-name-validator.ts +135 -0
  55. package/scripts/utils/project-meta.ts +69 -0
  56. package/scripts/validate-phase.ts +279 -0
  57. package/scripts/workflow-orchestrator.ts +178 -0
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * 新規プロジェクト自動セットアップスクリプト
4
+ *
5
+ * 使い方:
6
+ * npm run create-project -- \
7
+ * --name "customer-a-service-1" \
8
+ * --project-name "A社 サービス1" \
9
+ * --jira-key "PRJA"
10
+ */
11
+
12
+ import { execSync } from 'child_process';
13
+ import { writeFileSync, mkdirSync, cpSync, existsSync } from 'fs';
14
+ import { resolve, join, dirname } from 'path';
15
+ import { fileURLToPath } from 'url';
16
+ import { config as loadDotenv } from 'dotenv';
17
+
18
+ // ESモジュール対応: __dirnameの代替
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = dirname(__filename);
21
+
22
+ loadDotenv();
23
+
24
+ interface ProjectConfig {
25
+ name: string; // リポジトリ名: customer-a-service-1
26
+ projectName: string; // 表示名: A社 サービス1
27
+ jiraKey: string; // JIRAキー: PRJA
28
+ org?: string; // GitHub組織名(デフォルト: .envから)
29
+ labels?: string[]; // Confluenceラベル(デフォルト: 自動生成)
30
+ }
31
+
32
+ function parseArgs(): ProjectConfig {
33
+ const args = process.argv.slice(2);
34
+ const config: Partial<ProjectConfig> = {};
35
+
36
+ for (let i = 0; i < args.length; i += 2) {
37
+ const key = args[i].replace(/^--/, '');
38
+ const value = args[i + 1];
39
+
40
+ switch (key) {
41
+ case 'name':
42
+ config.name = value;
43
+ break;
44
+ case 'project-name':
45
+ config.projectName = value;
46
+ break;
47
+ case 'jira-key':
48
+ config.jiraKey = value;
49
+ break;
50
+ case 'org':
51
+ config.org = value;
52
+ break;
53
+ case 'labels':
54
+ // カンマ区切りでラベル配列に変換
55
+ config.labels = value.split(',').map(l => l.trim());
56
+ break;
57
+ }
58
+ }
59
+
60
+ // 必須フィールドチェック
61
+ if (!config.name || !config.projectName || !config.jiraKey) {
62
+ console.error('Missing required parameters');
63
+ console.error('Usage: npm run create-project -- --name <name> --project-name <display> --jira-key <key>');
64
+ process.exit(1);
65
+ }
66
+
67
+ return config as ProjectConfig;
68
+ }
69
+
70
+ async function createProject(config: ProjectConfig): Promise<void> {
71
+ const org = config.org || process.env.GITHUB_ORG;
72
+
73
+ if (!org) {
74
+ console.error('❌ GitHub organization not specified');
75
+ console.error(' Set GITHUB_ORG in .env or use --org parameter');
76
+ process.exit(1);
77
+ }
78
+
79
+ const repoName = config.name;
80
+ const repoUrl = `https://github.com/${org}/${repoName}`;
81
+ const projectDir = resolve(`../${repoName}`);
82
+
83
+ console.log(`🚀 Creating new project: ${config.projectName}`);
84
+ console.log(` Repository: ${org}/${repoName}`);
85
+ console.log(` JIRA: ${config.jiraKey}`);
86
+ console.log('');
87
+
88
+ // Step 1: GitHubリポジトリ作成
89
+ console.log('📦 Step 1: Creating GitHub repository...');
90
+ try {
91
+ execSync(
92
+ `gh repo create ${org}/${repoName} --private --description "${config.projectName}"`,
93
+ { stdio: 'inherit' }
94
+ );
95
+ console.log(' ✅ Repository created');
96
+ } catch (error) {
97
+ console.log(' ⚠️ Repository may already exist');
98
+ }
99
+
100
+ // Step 2: リポジトリクローン
101
+ console.log('\n📥 Step 2: Cloning repository...');
102
+ try {
103
+ execSync(`jj git clone ${repoUrl} ${projectDir}`, { stdio: 'inherit' });
104
+ console.log(' ✅ Repository cloned');
105
+ } catch (error) {
106
+ console.log(' ⚠️ Clone failed, checking if directory exists...');
107
+ }
108
+
109
+ // Step 3: ディレクトリ存在確認と移動
110
+ if (!existsSync(projectDir)) {
111
+ console.error(' ❌ Project directory does not exist. Clone may have failed.');
112
+ console.error(` Expected directory: ${projectDir}`);
113
+ process.exit(1);
114
+ }
115
+
116
+ process.chdir(projectDir);
117
+ console.log(` 📂 Working directory: ${projectDir}`);
118
+
119
+ // Step 4: cc-sdd導入
120
+ console.log('\n⚙️ Step 4: Installing cc-sdd...');
121
+ execSync('npx cc-sdd@latest --cursor --lang ja --yes', { stdio: 'inherit' });
122
+ console.log(' ✅ cc-sdd installed');
123
+
124
+ // Step 5: .kiro/project.json 作成
125
+ console.log('\n📝 Step 5: Creating project metadata...');
126
+ mkdirSync('.kiro', { recursive: true });
127
+
128
+ // ラベル生成(安全なフォールバック付き)
129
+ const labels = config.labels || (() => {
130
+ // プロジェクトIDからプロジェクトラベル生成
131
+ const projectLabel = repoName.toLowerCase().replace(/[^a-z0-9-]/g, '');
132
+ const labelSet = new Set([`project:${projectLabel}`]);
133
+
134
+ // ハイフンが存在する場合のみサービスラベルを生成
135
+ if (repoName.includes('-')) {
136
+ const parts = repoName.split('-');
137
+ const servicePart = parts[parts.length - 1];
138
+ const serviceLabel = servicePart.toLowerCase().replace(/[^a-z0-9-]/g, '');
139
+
140
+ // サービスラベルがプロジェクトラベルと異なる場合のみ追加
141
+ if (serviceLabel !== projectLabel) {
142
+ labelSet.add(`service:${serviceLabel}`);
143
+ }
144
+ }
145
+
146
+ return Array.from(labelSet);
147
+ })();
148
+
149
+ const projectJson = {
150
+ projectId: repoName,
151
+ projectName: config.projectName,
152
+ jiraProjectKey: config.jiraKey,
153
+ confluenceLabels: labels,
154
+ status: 'active',
155
+ team: [],
156
+ stakeholders: ['@企画', '@部長'],
157
+ repository: repoUrl,
158
+ description: `${config.projectName}の開発`
159
+ };
160
+
161
+ writeFileSync('.kiro/project.json', JSON.stringify(projectJson, null, 2));
162
+ console.log(' ✅ project.json created');
163
+
164
+ // Step 6: Michiから共通ファイルをコピー
165
+ console.log('\n📋 Step 6: Copying common files from Michi...');
166
+ const michiPath = resolve(__dirname, '..');
167
+
168
+ // コピー先ディレクトリを事前に作成
169
+ mkdirSync('.cursor/rules', { recursive: true });
170
+ mkdirSync('.cursor/commands/kiro', { recursive: true });
171
+ mkdirSync('.kiro/steering', { recursive: true });
172
+ mkdirSync('.kiro/settings/templates', { recursive: true });
173
+ mkdirSync('scripts/utils', { recursive: true });
174
+
175
+ // ルールファイル
176
+ const rulesToCopy = [
177
+ 'multi-project.mdc',
178
+ 'github-ssot.mdc',
179
+ 'atlassian-mcp.mdc'
180
+ ];
181
+
182
+ for (const rule of rulesToCopy) {
183
+ const src = join(michiPath, '.cursor/rules', rule);
184
+ const dest = join(projectDir, '.cursor/rules', rule);
185
+ if (existsSync(src)) {
186
+ cpSync(src, dest);
187
+ console.log(` ✅ Copied: .cursor/rules/${rule}`);
188
+ }
189
+ }
190
+
191
+ // カスタムコマンド
192
+ const commandsToCopy = [
193
+ 'confluence-sync.md',
194
+ 'project-switch.md'
195
+ ];
196
+
197
+ for (const cmd of commandsToCopy) {
198
+ const src = join(michiPath, '.cursor/commands/kiro', cmd);
199
+ const dest = join(projectDir, '.cursor/commands/kiro', cmd);
200
+ if (existsSync(src)) {
201
+ cpSync(src, dest);
202
+ console.log(` ✅ Copied: .cursor/commands/kiro/${cmd}`);
203
+ }
204
+ }
205
+
206
+ // Steering
207
+ const steeringDir = join(michiPath, '.kiro/steering');
208
+ if (existsSync(steeringDir)) {
209
+ mkdirSync('.kiro/steering', { recursive: true });
210
+ cpSync(steeringDir, '.kiro/steering', { recursive: true });
211
+ console.log(' ✅ Copied: .kiro/steering/');
212
+ }
213
+
214
+ // Scripts(必要なスクリプトのみコピー)
215
+ const scriptsDir = join(michiPath, 'scripts');
216
+ if (existsSync(scriptsDir)) {
217
+ const scriptsToCopy = [
218
+ 'confluence-sync.ts',
219
+ 'jira-sync.ts',
220
+ 'pr-automation.ts',
221
+ 'markdown-to-confluence.ts',
222
+ 'workflow-orchestrator.ts',
223
+ 'list-projects.ts',
224
+ 'resource-dashboard.ts',
225
+ 'multi-project-estimate.ts',
226
+ 'utils/project-meta.ts'
227
+ ];
228
+
229
+ for (const script of scriptsToCopy) {
230
+ const src = join(scriptsDir, script);
231
+ const dest = join(projectDir, 'scripts', script);
232
+ if (existsSync(src)) {
233
+ // ディレクトリが必要な場合は作成
234
+ const destDir = dirname(dest);
235
+ mkdirSync(destDir, { recursive: true });
236
+ cpSync(src, dest);
237
+ console.log(` ✅ Copied: scripts/${script}`);
238
+ }
239
+ }
240
+ }
241
+
242
+ // package.json, tsconfig.json
243
+ ['package.json', 'tsconfig.json'].forEach(file => {
244
+ const src = join(michiPath, file);
245
+ if (existsSync(src)) {
246
+ cpSync(src, file);
247
+ console.log(` ✅ Copied: ${file}`);
248
+ }
249
+ });
250
+
251
+ // Step 7: .env テンプレート作成
252
+ console.log('\n🔐 Step 7: Creating .env template...');
253
+ execSync('npm run setup:env', { stdio: 'inherit' });
254
+ console.log(' ✅ .env created');
255
+
256
+ // Step 8: npm install
257
+ console.log('\n📦 Step 8: Installing dependencies...');
258
+ execSync('npm install', { stdio: 'inherit' });
259
+ console.log(' ✅ Dependencies installed');
260
+
261
+ // Step 9: 初期コミット
262
+ console.log('\n💾 Step 9: Creating initial commit...');
263
+ execSync(`jj commit -m "chore: プロジェクト初期化
264
+
265
+ - cc-sdd導入
266
+ - プロジェクトメタデータ設定(${config.jiraKey})
267
+ - 自動化スクリプト追加
268
+ - Confluence/JIRA連携設定"`, { stdio: 'inherit' });
269
+
270
+ execSync('jj bookmark create main -r "@-"', { stdio: 'inherit' });
271
+ console.log(' ✅ Initial commit created');
272
+
273
+ // 完了メッセージ
274
+ console.log('\n');
275
+ console.log('🎉 プロジェクトセットアップ完了!');
276
+ console.log('');
277
+ console.log('次のステップ:');
278
+ console.log(` 1. cd ${projectDir}`);
279
+ console.log(' 2. .env ファイルを編集して認証情報を設定');
280
+ console.log(' 3. jj git push --bookmark main --allow-new');
281
+ console.log(' 4. Cursor で開く: cursor .');
282
+ console.log(' 5. /kiro:spec-init <機能説明> で開発開始');
283
+ console.log('');
284
+ console.log('詳細: docs/new-project-setup.md');
285
+ }
286
+
287
+ // 実行
288
+ const config = parseArgs();
289
+ createProject(config).catch(error => {
290
+ console.error('❌ Error:', error.message);
291
+ process.exit(1);
292
+ });
293
+