@sk8metal/michi-cli 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +202 -9
- package/dist/scripts/__tests__/setup-existing-project.test.js +67 -5
- package/dist/scripts/__tests__/setup-existing-project.test.js.map +1 -1
- package/dist/scripts/constants/__tests__/environments.test.d.ts +2 -0
- package/dist/scripts/constants/__tests__/environments.test.d.ts.map +1 -0
- package/dist/scripts/constants/__tests__/environments.test.js +91 -0
- package/dist/scripts/constants/__tests__/environments.test.js.map +1 -0
- package/dist/scripts/constants/__tests__/languages.test.d.ts +2 -0
- package/dist/scripts/constants/__tests__/languages.test.d.ts.map +1 -0
- package/dist/scripts/constants/__tests__/languages.test.js +82 -0
- package/dist/scripts/constants/__tests__/languages.test.js.map +1 -0
- package/dist/scripts/constants/environments.d.ts +33 -0
- package/dist/scripts/constants/environments.d.ts.map +1 -0
- package/dist/scripts/constants/environments.js +49 -0
- package/dist/scripts/constants/environments.js.map +1 -0
- package/dist/scripts/constants/languages.d.ts +23 -0
- package/dist/scripts/constants/languages.d.ts.map +1 -0
- package/dist/scripts/constants/languages.js +53 -0
- package/dist/scripts/constants/languages.js.map +1 -0
- package/dist/scripts/create-project.d.ts +4 -0
- package/dist/scripts/create-project.d.ts.map +1 -1
- package/dist/scripts/create-project.js +51 -22
- package/dist/scripts/create-project.js.map +1 -1
- package/dist/scripts/setup-existing-project.d.ts +3 -1
- package/dist/scripts/setup-existing-project.d.ts.map +1 -1
- package/dist/scripts/setup-existing-project.js +110 -55
- package/dist/scripts/setup-existing-project.js.map +1 -1
- package/dist/scripts/template/__tests__/renderer.test.d.ts +2 -0
- package/dist/scripts/template/__tests__/renderer.test.d.ts.map +1 -0
- package/dist/scripts/template/__tests__/renderer.test.js +165 -0
- package/dist/scripts/template/__tests__/renderer.test.js.map +1 -0
- package/dist/scripts/template/renderer.d.ts +70 -0
- package/dist/scripts/template/renderer.d.ts.map +1 -0
- package/dist/scripts/template/renderer.js +99 -0
- package/dist/scripts/template/renderer.js.map +1 -0
- package/dist/scripts/utils/template-finder.d.ts +37 -0
- package/dist/scripts/utils/template-finder.d.ts.map +1 -0
- package/dist/scripts/utils/template-finder.js +63 -0
- package/dist/scripts/utils/template-finder.js.map +1 -0
- package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts +5 -0
- package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts.map +1 -0
- package/dist/src/__tests__/integration/setup/claude-agent.test.js +125 -0
- package/dist/src/__tests__/integration/setup/claude-agent.test.js.map +1 -0
- package/dist/src/__tests__/integration/setup/claude.test.d.ts +5 -0
- package/dist/src/__tests__/integration/setup/claude.test.d.ts.map +1 -0
- package/dist/src/__tests__/integration/setup/claude.test.js +111 -0
- package/dist/src/__tests__/integration/setup/claude.test.js.map +1 -0
- package/dist/src/__tests__/integration/setup/cursor.test.d.ts +5 -0
- package/dist/src/__tests__/integration/setup/cursor.test.d.ts.map +1 -0
- package/dist/src/__tests__/integration/setup/cursor.test.js +162 -0
- package/dist/src/__tests__/integration/setup/cursor.test.js.map +1 -0
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts +32 -0
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts.map +1 -0
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js +72 -0
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js.map +1 -0
- package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts +38 -0
- package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts.map +1 -0
- package/dist/src/__tests__/integration/setup/helpers/test-project.js +83 -0
- package/dist/src/__tests__/integration/setup/helpers/test-project.js.map +1 -0
- package/dist/src/__tests__/integration/setup/validation.test.d.ts +5 -0
- package/dist/src/__tests__/integration/setup/validation.test.d.ts.map +1 -0
- package/dist/src/__tests__/integration/setup/validation.test.js +318 -0
- package/dist/src/__tests__/integration/setup/validation.test.js.map +1 -0
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +20 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/setup-existing.d.ts +22 -0
- package/dist/src/commands/setup-existing.d.ts.map +1 -0
- package/dist/src/commands/setup-existing.js +408 -0
- package/dist/src/commands/setup-existing.js.map +1 -0
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +4 -3
- package/dist/vitest.config.js.map +1 -1
- package/docs/getting-started/new-repository-setup.md +108 -28
- package/docs/getting-started/quick-start.md +57 -6
- package/docs/getting-started/setup.md +250 -2
- package/docs/guides/customization.md +3 -3
- package/docs/guides/multi-project.md +1 -1
- package/docs/reference/quick-reference.md +25 -16
- package/docs/testing/integration-tests.md +297 -0
- package/package.json +7 -2
- package/scripts/__tests__/setup-existing-project.test.ts +73 -5
- package/scripts/constants/__tests__/environments.test.ts +110 -0
- package/scripts/constants/__tests__/languages.test.ts +100 -0
- package/scripts/constants/environments.ts +61 -0
- package/scripts/constants/languages.ts +70 -0
- package/scripts/create-project.ts +52 -22
- package/scripts/setup-existing-project.ts +136 -57
- package/scripts/setup-existing.sh +130 -3
- package/scripts/template/__tests__/renderer.test.ts +207 -0
- package/scripts/template/renderer.ts +133 -0
- package/scripts/utils/template-finder.ts +75 -0
- package/templates/claude/commands/michi/confluence-sync.md +38 -0
- package/templates/claude/commands/michi/project-switch.md +36 -0
- package/templates/claude/rules/atlassian-integration.md +35 -0
- package/templates/claude/rules/michi-core.md +54 -0
- package/templates/claude-agent/README.md +25 -0
- package/templates/cursor/commands/michi/confluence-sync.md +76 -0
- package/templates/cursor/commands/michi/project-switch.md +69 -0
- package/templates/cursor/rules/atlassian-mcp.mdc +188 -0
- package/templates/cursor/rules/github-ssot.mdc +151 -0
- package/templates/cursor/rules/multi-project.mdc +81 -0
- package/scripts/setup-env.sh +0 -52
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
supportedLanguages,
|
|
4
|
+
DEV_GUIDELINES_MAP,
|
|
5
|
+
getDevGuidelines,
|
|
6
|
+
isSupportedLanguage,
|
|
7
|
+
type SupportedLanguage
|
|
8
|
+
} from '../languages.js';
|
|
9
|
+
|
|
10
|
+
describe('languages', () => {
|
|
11
|
+
describe('supportedLanguages', () => {
|
|
12
|
+
it('should contain 12 languages', () => {
|
|
13
|
+
expect(supportedLanguages).toHaveLength(12);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should include expected languages', () => {
|
|
17
|
+
expect(supportedLanguages).toContain('ja');
|
|
18
|
+
expect(supportedLanguages).toContain('en');
|
|
19
|
+
expect(supportedLanguages).toContain('zh-TW');
|
|
20
|
+
expect(supportedLanguages).toContain('zh');
|
|
21
|
+
expect(supportedLanguages).toContain('es');
|
|
22
|
+
expect(supportedLanguages).toContain('pt');
|
|
23
|
+
expect(supportedLanguages).toContain('de');
|
|
24
|
+
expect(supportedLanguages).toContain('fr');
|
|
25
|
+
expect(supportedLanguages).toContain('ru');
|
|
26
|
+
expect(supportedLanguages).toContain('it');
|
|
27
|
+
expect(supportedLanguages).toContain('ko');
|
|
28
|
+
expect(supportedLanguages).toContain('ar');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('DEV_GUIDELINES_MAP', () => {
|
|
33
|
+
it('should have entries for all supported languages', () => {
|
|
34
|
+
for (const lang of supportedLanguages) {
|
|
35
|
+
expect(DEV_GUIDELINES_MAP[lang]).toBeDefined();
|
|
36
|
+
expect(DEV_GUIDELINES_MAP[lang]).not.toBe('');
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should have English guideline', () => {
|
|
41
|
+
expect(DEV_GUIDELINES_MAP.en).toBe('- Think in English, generate responses in English');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should have Japanese guideline with bilingual instruction', () => {
|
|
45
|
+
expect(DEV_GUIDELINES_MAP.ja).toContain('Think in English');
|
|
46
|
+
expect(DEV_GUIDELINES_MAP.ja).toContain('日本語');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should contain bilingual instructions', () => {
|
|
50
|
+
// Most languages should mention "Think in English" in some form
|
|
51
|
+
const languagesWithEnglishInstruction = ['ja', 'en', 'es', 'pt', 'de', 'fr', 'ru', 'it', 'ko', 'ar'];
|
|
52
|
+
for (const lang of languagesWithEnglishInstruction) {
|
|
53
|
+
expect(DEV_GUIDELINES_MAP[lang as SupportedLanguage]).toContain('Think in English');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Chinese languages have their own format
|
|
57
|
+
expect(DEV_GUIDELINES_MAP['zh-TW']).toContain('以英文思考');
|
|
58
|
+
expect(DEV_GUIDELINES_MAP.zh).toContain('以英文思考');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('getDevGuidelines', () => {
|
|
63
|
+
it('should return guidelines for valid language', () => {
|
|
64
|
+
const guidelines = getDevGuidelines('ja');
|
|
65
|
+
expect(guidelines).toBe(DEV_GUIDELINES_MAP.ja);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should return guidelines for all supported languages', () => {
|
|
69
|
+
for (const lang of supportedLanguages) {
|
|
70
|
+
const guidelines = getDevGuidelines(lang);
|
|
71
|
+
expect(guidelines).toBeDefined();
|
|
72
|
+
expect(guidelines).toBe(DEV_GUIDELINES_MAP[lang]);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('isSupportedLanguage', () => {
|
|
78
|
+
it('should return true for supported languages', () => {
|
|
79
|
+
expect(isSupportedLanguage('ja')).toBe(true);
|
|
80
|
+
expect(isSupportedLanguage('en')).toBe(true);
|
|
81
|
+
expect(isSupportedLanguage('zh-TW')).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return false for unsupported languages', () => {
|
|
85
|
+
expect(isSupportedLanguage('xx')).toBe(false);
|
|
86
|
+
expect(isSupportedLanguage('invalid')).toBe(false);
|
|
87
|
+
expect(isSupportedLanguage('')).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should work as type guard', () => {
|
|
91
|
+
const lang: string = 'ja';
|
|
92
|
+
if (isSupportedLanguage(lang)) {
|
|
93
|
+
// TypeScript should recognize lang as SupportedLanguage here
|
|
94
|
+
const guidelines: string = DEV_GUIDELINES_MAP[lang];
|
|
95
|
+
expect(guidelines).toBeDefined();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment configuration mapping for cc-sdd environments
|
|
3
|
+
*
|
|
4
|
+
* Issue #37: 環境別コピー実装
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface EnvironmentConfig {
|
|
8
|
+
rulesDir: string;
|
|
9
|
+
commandsDir: string;
|
|
10
|
+
templateSource: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type Environment = 'claude' | 'claude-agent' | 'cursor';
|
|
14
|
+
|
|
15
|
+
export const ENV_CONFIG: Record<Environment, EnvironmentConfig> = {
|
|
16
|
+
'claude': {
|
|
17
|
+
rulesDir: '.claude/rules',
|
|
18
|
+
commandsDir: '.claude/commands/kiro',
|
|
19
|
+
templateSource: 'claude'
|
|
20
|
+
},
|
|
21
|
+
'claude-agent': {
|
|
22
|
+
rulesDir: '.claude/rules',
|
|
23
|
+
commandsDir: '.claude/commands/kiro',
|
|
24
|
+
templateSource: 'claude-agent'
|
|
25
|
+
},
|
|
26
|
+
'cursor': {
|
|
27
|
+
rulesDir: '.cursor/rules',
|
|
28
|
+
commandsDir: '.cursor/commands/kiro',
|
|
29
|
+
templateSource: 'cursor'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get environment configuration
|
|
35
|
+
*
|
|
36
|
+
* @param env - Environment name
|
|
37
|
+
* @returns Environment configuration
|
|
38
|
+
*/
|
|
39
|
+
export const getEnvironmentConfig = (env: Environment): EnvironmentConfig => {
|
|
40
|
+
return ENV_CONFIG[env];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Validate if an environment is supported
|
|
45
|
+
*
|
|
46
|
+
* @param env - Environment name to validate
|
|
47
|
+
* @returns True if supported, false otherwise
|
|
48
|
+
*/
|
|
49
|
+
export const isSupportedEnvironment = (env: string): env is Environment => {
|
|
50
|
+
return env in ENV_CONFIG;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get all supported environments
|
|
55
|
+
*
|
|
56
|
+
* @returns Array of supported environment names
|
|
57
|
+
*/
|
|
58
|
+
export const getSupportedEnvironments = (): Environment[] => {
|
|
59
|
+
return Object.keys(ENV_CONFIG) as Environment[];
|
|
60
|
+
};
|
|
61
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported languages and development guidelines map
|
|
3
|
+
*
|
|
4
|
+
* Issue #37: 環境別コピー実装
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const supportedLanguages = [
|
|
8
|
+
'ja', 'en', 'zh-TW', 'zh', 'es', 'pt',
|
|
9
|
+
'de', 'fr', 'ru', 'it', 'ko', 'ar'
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export type SupportedLanguage = typeof supportedLanguages[number];
|
|
13
|
+
|
|
14
|
+
export const DEV_GUIDELINES_MAP: Record<SupportedLanguage, string> = {
|
|
15
|
+
en: '- Think in English, generate responses in English',
|
|
16
|
+
|
|
17
|
+
ja: '- Think in English, but generate responses in Japanese ' +
|
|
18
|
+
'(思考は英語、回答の生成は日本語で行うように)',
|
|
19
|
+
|
|
20
|
+
'zh-TW': '- 以英文思考,但以繁體中文生成回應' +
|
|
21
|
+
'(Think in English, generate in Traditional Chinese)',
|
|
22
|
+
|
|
23
|
+
zh: '- 以英文思考,但以简体中文生成回复' +
|
|
24
|
+
'(Think in English, generate in Simplified Chinese)',
|
|
25
|
+
|
|
26
|
+
es: '- Think in English, generate responses in Spanish ' +
|
|
27
|
+
'(Piensa en inglés, genera respuestas en español)',
|
|
28
|
+
|
|
29
|
+
pt: '- Think in English, generate responses in Portuguese ' +
|
|
30
|
+
'(Pense em inglês, gere respostas em português)',
|
|
31
|
+
|
|
32
|
+
de: '- Think in English, generate responses in German ' +
|
|
33
|
+
'(Denke auf Englisch, formuliere Antworten auf Deutsch)',
|
|
34
|
+
|
|
35
|
+
fr: '- Think in English, generate responses in French ' +
|
|
36
|
+
'(Pensez en anglais, générez des réponses en français)',
|
|
37
|
+
|
|
38
|
+
ru: '- Think in English, generate responses in Russian ' +
|
|
39
|
+
'(Думай по-английски, отвечай по-русски)',
|
|
40
|
+
|
|
41
|
+
it: '- Think in English, generate responses in Italian ' +
|
|
42
|
+
'(Pensa in inglese, genera risposte in italiano)',
|
|
43
|
+
|
|
44
|
+
ko: '- Think in English, generate responses in Korean ' +
|
|
45
|
+
'(영어로 사고하고, 한국어로 응답을 생성하세요)',
|
|
46
|
+
|
|
47
|
+
ar: '- Think in English, generate responses in Arabic ' +
|
|
48
|
+
'(فكر بالإنجليزية وأجب بالعربية)',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get development guidelines for a specific language
|
|
53
|
+
*
|
|
54
|
+
* @param lang - Language code
|
|
55
|
+
* @returns Development guidelines string
|
|
56
|
+
*/
|
|
57
|
+
export const getDevGuidelines = (lang: SupportedLanguage): string => {
|
|
58
|
+
return DEV_GUIDELINES_MAP[lang];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Validate if a language code is supported
|
|
63
|
+
*
|
|
64
|
+
* @param lang - Language code to validate
|
|
65
|
+
* @returns True if supported, false otherwise
|
|
66
|
+
*/
|
|
67
|
+
export const isSupportedLanguage = (lang: string): lang is SupportedLanguage => {
|
|
68
|
+
return (supportedLanguages as readonly string[]).includes(lang);
|
|
69
|
+
};
|
|
70
|
+
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* 新規プロジェクト自動セットアップスクリプト
|
|
4
4
|
*
|
|
5
|
+
* Issue #35: cc-sdd準拠の多環境対応基盤
|
|
6
|
+
* - templates/ディレクトリから読み込み
|
|
7
|
+
* - プレースホルダーはそのまま(実行時にAIが解釈)
|
|
8
|
+
*
|
|
5
9
|
* 使い方:
|
|
6
10
|
* npm run create-project -- \
|
|
7
11
|
* --name "20240115-payment-api" \
|
|
@@ -11,9 +15,10 @@
|
|
|
11
15
|
|
|
12
16
|
import { execSync } from 'child_process';
|
|
13
17
|
import { writeFileSync, mkdirSync, cpSync, existsSync } from 'fs';
|
|
14
|
-
import { resolve, join, dirname } from 'path';
|
|
18
|
+
import { resolve, join, dirname, basename } from 'path';
|
|
15
19
|
import { fileURLToPath } from 'url';
|
|
16
20
|
import { config as loadDotenv } from 'dotenv';
|
|
21
|
+
import { findTemplateFile, validateRequiredTemplates } from './utils/template-finder.js';
|
|
17
22
|
|
|
18
23
|
// ESモジュール対応: __dirnameの代替
|
|
19
24
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -203,46 +208,71 @@ async function createProject(config: ProjectConfig): Promise<void> {
|
|
|
203
208
|
writeFileSync('.kiro/project.json', JSON.stringify(projectJson, null, 2));
|
|
204
209
|
console.log(' ✅ project.json created');
|
|
205
210
|
|
|
206
|
-
// Step 8: Michi
|
|
207
|
-
console.log('\n📋 Step 8: Copying common files from Michi...');
|
|
211
|
+
// Step 8: Michiから共通ファイルをコピー(templates/から)
|
|
212
|
+
console.log('\n📋 Step 8: Copying common files from Michi templates...');
|
|
213
|
+
console.log(' ℹ️ Issue #35: cc-sdd compliant approach (placeholders preserved)');
|
|
208
214
|
const michiPath = resolve(__dirname, '..');
|
|
209
215
|
|
|
216
|
+
// 必須テンプレートのバリデーション
|
|
217
|
+
const requiredTemplates = [
|
|
218
|
+
'rules/github-ssot.mdc',
|
|
219
|
+
'rules/multi-project.mdc',
|
|
220
|
+
'commands/michi/confluence-sync.md',
|
|
221
|
+
'commands/michi/project-switch.md'
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
validateRequiredTemplates(michiPath, requiredTemplates);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error('\n❌ Template validation failed:');
|
|
228
|
+
console.error(` ${error instanceof Error ? error.message : String(error)}`);
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
210
232
|
// コピー先ディレクトリを事前に作成(actualProjectDir 配下に作成)
|
|
211
233
|
console.log(` 📂 Copying to: ${actualProjectDir}`);
|
|
212
234
|
mkdirSync(join(actualProjectDir, '.cursor/rules'), { recursive: true });
|
|
213
|
-
mkdirSync(join(actualProjectDir, '.cursor/commands/
|
|
235
|
+
mkdirSync(join(actualProjectDir, '.cursor/commands/michi'), { recursive: true });
|
|
214
236
|
mkdirSync(join(actualProjectDir, '.kiro/steering'), { recursive: true });
|
|
215
237
|
mkdirSync(join(actualProjectDir, '.kiro/settings/templates'), { recursive: true });
|
|
216
238
|
mkdirSync(join(actualProjectDir, 'scripts/utils'), { recursive: true });
|
|
217
239
|
|
|
218
|
-
//
|
|
240
|
+
// ルールファイル(templates/から)
|
|
219
241
|
const rulesToCopy = [
|
|
220
|
-
'multi-project.mdc',
|
|
221
|
-
'github-ssot.mdc',
|
|
222
|
-
'atlassian-mcp.mdc'
|
|
242
|
+
'rules/multi-project.mdc',
|
|
243
|
+
'rules/github-ssot.mdc',
|
|
244
|
+
'rules/atlassian-mcp.mdc'
|
|
223
245
|
];
|
|
224
246
|
|
|
225
|
-
for (const
|
|
226
|
-
const src =
|
|
227
|
-
const
|
|
228
|
-
|
|
247
|
+
for (const rulePath of rulesToCopy) {
|
|
248
|
+
const src = findTemplateFile(michiPath, rulePath);
|
|
249
|
+
const fileName = basename(rulePath);
|
|
250
|
+
const dest = join(actualProjectDir, '.cursor/rules', fileName);
|
|
251
|
+
|
|
252
|
+
if (src) {
|
|
229
253
|
cpSync(src, dest);
|
|
230
|
-
console.log(` ✅ Copied: .cursor/rules/${
|
|
254
|
+
console.log(` ✅ Copied: .cursor/rules/${fileName} (from templates/)`);
|
|
255
|
+
} else {
|
|
256
|
+
console.log(` ⚠️ ${fileName} not found in templates/`);
|
|
231
257
|
}
|
|
232
258
|
}
|
|
233
259
|
|
|
234
|
-
//
|
|
260
|
+
// カスタムコマンド(templates/から)
|
|
235
261
|
const commandsToCopy = [
|
|
236
|
-
'confluence-sync.md',
|
|
237
|
-
'project-switch.md'
|
|
262
|
+
'commands/michi/confluence-sync.md',
|
|
263
|
+
'commands/michi/project-switch.md'
|
|
238
264
|
];
|
|
239
265
|
|
|
240
|
-
for (const
|
|
241
|
-
const src =
|
|
242
|
-
const
|
|
243
|
-
|
|
266
|
+
for (const cmdPath of commandsToCopy) {
|
|
267
|
+
const src = findTemplateFile(michiPath, cmdPath);
|
|
268
|
+
const fileName = basename(cmdPath);
|
|
269
|
+
const dest = join(actualProjectDir, '.cursor/commands/michi', fileName);
|
|
270
|
+
|
|
271
|
+
if (src) {
|
|
244
272
|
cpSync(src, dest);
|
|
245
|
-
console.log(` ✅ Copied: .cursor/commands/
|
|
273
|
+
console.log(` ✅ Copied: .cursor/commands/michi/${fileName} (from templates/)`);
|
|
274
|
+
} else {
|
|
275
|
+
console.log(` ⚠️ ${fileName} not found in templates/`);
|
|
246
276
|
}
|
|
247
277
|
}
|
|
248
278
|
|
|
@@ -339,7 +369,7 @@ async function createProject(config: ProjectConfig): Promise<void> {
|
|
|
339
369
|
console.log(' 4. Cursor で開く: cursor .');
|
|
340
370
|
console.log(' 5. /kiro:spec-init <機能説明> で開発開始');
|
|
341
371
|
console.log('');
|
|
342
|
-
console.log('詳細: docs/new-repository-setup.md');
|
|
372
|
+
console.log('詳細: docs/getting-started/new-repository-setup.md');
|
|
343
373
|
|
|
344
374
|
} finally {
|
|
345
375
|
// 元の作業ディレクトリに戻る
|
|
@@ -7,19 +7,41 @@
|
|
|
7
7
|
* npx tsx /path/to/michi/scripts/setup-existing-project.ts \
|
|
8
8
|
* --michi-path /path/to/michi \
|
|
9
9
|
* --project-name "既存プロジェクト" \
|
|
10
|
-
* --jira-key "EXIST"
|
|
10
|
+
* --jira-key "EXIST" \
|
|
11
|
+
* --environment cursor \
|
|
12
|
+
* --lang ja
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
|
-
import { cpSync, existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
14
|
-
import { resolve, join, basename } from 'path';
|
|
15
|
+
import { cpSync, existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
16
|
+
import { resolve, join, basename, dirname } from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
15
18
|
import { execSync } from 'child_process';
|
|
16
19
|
import { findRepositoryRoot } from './utils/project-finder.js';
|
|
20
|
+
import {
|
|
21
|
+
type Environment,
|
|
22
|
+
getEnvironmentConfig,
|
|
23
|
+
isSupportedEnvironment
|
|
24
|
+
} from './constants/environments.js';
|
|
25
|
+
import {
|
|
26
|
+
type SupportedLanguage,
|
|
27
|
+
isSupportedLanguage
|
|
28
|
+
} from './constants/languages.js';
|
|
29
|
+
import {
|
|
30
|
+
createTemplateContext,
|
|
31
|
+
renderTemplate
|
|
32
|
+
} from './template/renderer.js';
|
|
33
|
+
|
|
34
|
+
// ES module で __dirname を取得
|
|
35
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
36
|
+
const __dirname = dirname(__filename);
|
|
17
37
|
|
|
18
38
|
interface SetupConfig {
|
|
19
39
|
michiPath: string; // Michiリポジトリのパス
|
|
20
40
|
projectName: string; // プロジェクト表示名
|
|
21
41
|
jiraKey: string; // JIRAプロジェクトキー
|
|
22
42
|
labels?: string[]; // Confluenceラベル(オプション)
|
|
43
|
+
environment: Environment; // cc-sdd環境: 'claude' | 'claude-agent' | 'cursor'
|
|
44
|
+
langCode: SupportedLanguage; // 言語コード: 'ja'
|
|
23
45
|
}
|
|
24
46
|
|
|
25
47
|
function parseArgs(): SetupConfig {
|
|
@@ -40,6 +62,12 @@ function parseArgs(): SetupConfig {
|
|
|
40
62
|
case 'jira-key':
|
|
41
63
|
config.jiraKey = value;
|
|
42
64
|
break;
|
|
65
|
+
case 'environment':
|
|
66
|
+
config.environment = value as Environment;
|
|
67
|
+
break;
|
|
68
|
+
case 'lang':
|
|
69
|
+
config.langCode = value as SupportedLanguage;
|
|
70
|
+
break;
|
|
43
71
|
}
|
|
44
72
|
}
|
|
45
73
|
|
|
@@ -47,17 +75,68 @@ function parseArgs(): SetupConfig {
|
|
|
47
75
|
if (!config.michiPath) {
|
|
48
76
|
config.michiPath = resolve(__dirname, '..');
|
|
49
77
|
}
|
|
78
|
+
if (!config.environment) {
|
|
79
|
+
config.environment = 'claude';
|
|
80
|
+
}
|
|
81
|
+
if (!config.langCode) {
|
|
82
|
+
config.langCode = 'ja';
|
|
83
|
+
}
|
|
50
84
|
|
|
51
85
|
// 必須フィールドチェック
|
|
52
86
|
if (!config.projectName || !config.jiraKey) {
|
|
53
87
|
console.error('Missing required parameters');
|
|
54
|
-
console.error('Usage: tsx setup-existing-project.ts --project-name <name> --jira-key <key> [--michi-path <path>]');
|
|
88
|
+
console.error('Usage: tsx setup-existing-project.ts --project-name <name> --jira-key <key> [--michi-path <path>] [--environment <env>] [--lang <code>]');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 環境バリデーション
|
|
93
|
+
if (!isSupportedEnvironment(config.environment)) {
|
|
94
|
+
console.error(`Unsupported environment: ${config.environment}`);
|
|
95
|
+
console.error('Supported environments: claude, claude-agent, cursor');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 言語バリデーション
|
|
100
|
+
if (!isSupportedLanguage(config.langCode)) {
|
|
101
|
+
console.error(`Unsupported language: ${config.langCode}`);
|
|
102
|
+
console.error('Supported languages: ja, en, zh-TW, zh, es, pt, de, fr, ru, it, ko, ar');
|
|
55
103
|
process.exit(1);
|
|
56
104
|
}
|
|
57
105
|
|
|
58
106
|
return config as SetupConfig;
|
|
59
107
|
}
|
|
60
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Copy and render templates recursively
|
|
111
|
+
*
|
|
112
|
+
* @param sourceDir - Source directory containing templates
|
|
113
|
+
* @param destDir - Destination directory for rendered files
|
|
114
|
+
* @param context - Template context for rendering
|
|
115
|
+
*/
|
|
116
|
+
function copyAndRenderTemplates(
|
|
117
|
+
sourceDir: string,
|
|
118
|
+
destDir: string,
|
|
119
|
+
context: ReturnType<typeof createTemplateContext>
|
|
120
|
+
): void {
|
|
121
|
+
const entries = readdirSync(sourceDir, { withFileTypes: true });
|
|
122
|
+
|
|
123
|
+
for (const entry of entries) {
|
|
124
|
+
const sourcePath = join(sourceDir, entry.name);
|
|
125
|
+
const destPath = join(destDir, entry.name);
|
|
126
|
+
|
|
127
|
+
if (entry.isDirectory()) {
|
|
128
|
+
// ディレクトリは再帰的にコピー
|
|
129
|
+
mkdirSync(destPath, { recursive: true });
|
|
130
|
+
copyAndRenderTemplates(sourcePath, destPath, context);
|
|
131
|
+
} else if (entry.isFile()) {
|
|
132
|
+
// ファイルはレンダリングしてコピー
|
|
133
|
+
const content = readFileSync(sourcePath, 'utf-8');
|
|
134
|
+
const rendered = renderTemplate(content, context);
|
|
135
|
+
writeFileSync(destPath, rendered, 'utf-8');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
61
140
|
async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
62
141
|
const currentDir = process.cwd();
|
|
63
142
|
const projectId = basename(currentDir);
|
|
@@ -66,6 +145,8 @@ async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
|
66
145
|
console.log(` プロジェクト: ${config.projectName}`);
|
|
67
146
|
console.log(` ディレクトリ: ${currentDir}`);
|
|
68
147
|
console.log(` Michiパス: ${config.michiPath}`);
|
|
148
|
+
console.log(` 環境: ${config.environment}`);
|
|
149
|
+
console.log(` 言語: ${config.langCode}`);
|
|
69
150
|
console.log('');
|
|
70
151
|
|
|
71
152
|
// リポジトリルートを検出
|
|
@@ -151,6 +232,7 @@ async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
|
151
232
|
const projectJson = {
|
|
152
233
|
projectId,
|
|
153
234
|
projectName: config.projectName,
|
|
235
|
+
language: config.langCode,
|
|
154
236
|
jiraProjectKey: config.jiraKey,
|
|
155
237
|
confluenceLabels: labels,
|
|
156
238
|
status: 'active',
|
|
@@ -163,49 +245,46 @@ async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
|
163
245
|
writeFileSync('.kiro/project.json', JSON.stringify(projectJson, null, 2));
|
|
164
246
|
console.log(' ✅ project.json created');
|
|
165
247
|
|
|
166
|
-
// Step 4:
|
|
167
|
-
console.log('\n📋 Step 4: Copying
|
|
248
|
+
// Step 4: 環境別テンプレートのコピーとレンダリング
|
|
249
|
+
console.log('\n📋 Step 4: Copying and rendering templates from Michi...');
|
|
168
250
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
251
|
+
const envConfig = getEnvironmentConfig(config.environment);
|
|
252
|
+
const templateContext = createTemplateContext(
|
|
253
|
+
config.langCode,
|
|
254
|
+
'.kiro',
|
|
255
|
+
envConfig.rulesDir.startsWith('.') ? envConfig.rulesDir.substring(1, envConfig.rulesDir.indexOf('/', 1)) : envConfig.rulesDir.split('/')[0]
|
|
256
|
+
);
|
|
172
257
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
'github-ssot.mdc',
|
|
176
|
-
'atlassian-mcp.mdc'
|
|
177
|
-
];
|
|
258
|
+
// テンプレートソースディレクトリ
|
|
259
|
+
const templateSourceDir = join(config.michiPath, 'templates', envConfig.templateSource);
|
|
178
260
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
261
|
+
if (!existsSync(templateSourceDir)) {
|
|
262
|
+
console.log(` ⚠️ Template source not found: ${templateSourceDir}`);
|
|
263
|
+
console.log(' Skipping template copy');
|
|
264
|
+
} else {
|
|
265
|
+
// rulesディレクトリのコピーとレンダリング
|
|
266
|
+
const rulesTemplateDir = join(templateSourceDir, 'rules');
|
|
267
|
+
const rulesDestDir = join(projectDir, envConfig.rulesDir);
|
|
268
|
+
|
|
269
|
+
if (existsSync(rulesTemplateDir)) {
|
|
270
|
+
mkdirSync(rulesDestDir, { recursive: true });
|
|
271
|
+
copyAndRenderTemplates(rulesTemplateDir, rulesDestDir, templateContext);
|
|
272
|
+
console.log(` ✅ Rules copied and rendered to ${envConfig.rulesDir}`);
|
|
187
273
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Step 5: カスタムコマンドをコピー
|
|
191
|
-
console.log('\n🔧 Step 5: Copying custom commands...');
|
|
192
|
-
|
|
193
|
-
const commandsToCopy = [
|
|
194
|
-
'confluence-sync.md',
|
|
195
|
-
'project-switch.md'
|
|
196
|
-
];
|
|
197
274
|
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
275
|
+
// commandsディレクトリのコピーとレンダリング
|
|
276
|
+
const commandsTemplateDir = join(templateSourceDir, 'commands');
|
|
277
|
+
const commandsDestDir = join(projectDir, envConfig.commandsDir);
|
|
278
|
+
|
|
279
|
+
if (existsSync(commandsTemplateDir)) {
|
|
280
|
+
mkdirSync(commandsDestDir, { recursive: true });
|
|
281
|
+
copyAndRenderTemplates(commandsTemplateDir, commandsDestDir, templateContext);
|
|
282
|
+
console.log(` ✅ Commands copied and rendered to ${envConfig.commandsDir}`);
|
|
204
283
|
}
|
|
205
284
|
}
|
|
206
285
|
|
|
207
|
-
// Step
|
|
208
|
-
console.log('\n📚 Step
|
|
286
|
+
// Step 5: Steeringテンプレートをコピー
|
|
287
|
+
console.log('\n📚 Step 5: Copying steering templates...');
|
|
209
288
|
|
|
210
289
|
const steeringDir = join(config.michiPath, '.kiro/steering');
|
|
211
290
|
if (existsSync(steeringDir)) {
|
|
@@ -213,8 +292,8 @@ async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
|
213
292
|
console.log(' ✅ product.md, tech.md, structure.md');
|
|
214
293
|
}
|
|
215
294
|
|
|
216
|
-
// Step
|
|
217
|
-
console.log('\n📄 Step
|
|
295
|
+
// Step 6: テンプレートをコピー
|
|
296
|
+
console.log('\n📄 Step 6: Copying spec templates...');
|
|
218
297
|
|
|
219
298
|
const templatesDir = join(config.michiPath, '.kiro/settings/templates');
|
|
220
299
|
if (existsSync(templatesDir)) {
|
|
@@ -222,8 +301,8 @@ async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
|
222
301
|
console.log(' ✅ requirements.md, design.md, tasks.md');
|
|
223
302
|
}
|
|
224
303
|
|
|
225
|
-
// Step
|
|
226
|
-
console.log('\n⚙️ Step
|
|
304
|
+
// Step 7: CLIツールのセットアップ案内
|
|
305
|
+
console.log('\n⚙️ Step 7: Setting up Michi CLI...');
|
|
227
306
|
console.log(' ✅ Michi CLI setup complete!');
|
|
228
307
|
console.log('');
|
|
229
308
|
console.log(' 📋 使用方法:');
|
|
@@ -235,8 +314,8 @@ async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
|
235
314
|
console.log(' npm install -g @sk8metal/michi-cli');
|
|
236
315
|
console.log(' michi jira:sync <feature>');
|
|
237
316
|
|
|
238
|
-
// Step
|
|
239
|
-
console.log('\n📦 Step
|
|
317
|
+
// Step 8: package.json と tsconfig.json をリポジトリルートにコピー
|
|
318
|
+
console.log('\n📦 Step 8: Setting up package.json and TypeScript...');
|
|
240
319
|
|
|
241
320
|
// 既存の package.json があるかチェック(リポジトリルート)
|
|
242
321
|
const hasPackageJson = existsSync(join(repoRoot, 'package.json'));
|
|
@@ -279,8 +358,8 @@ async function setupExistingProject(config: SetupConfig): Promise<void> {
|
|
|
279
358
|
console.log(' ℹ️ Existing tsconfig.json found (kept)');
|
|
280
359
|
}
|
|
281
360
|
|
|
282
|
-
// Step
|
|
283
|
-
console.log('\n🔐 Step
|
|
361
|
+
// Step 9: .env テンプレート作成(プロジェクトディレクトリに)
|
|
362
|
+
console.log('\n🔐 Step 9: Creating .env template...');
|
|
284
363
|
|
|
285
364
|
const envTemplate = `# Atlassian設定(MCP + REST API共通)
|
|
286
365
|
ATLASSIAN_URL=https://your-domain.atlassian.net
|
|
@@ -308,8 +387,8 @@ JIRA_PROJECT_KEYS=${config.jiraKey}
|
|
|
308
387
|
console.log(' ℹ️ .env already exists (kept)');
|
|
309
388
|
}
|
|
310
389
|
|
|
311
|
-
// Step
|
|
312
|
-
console.log('\n📖 Step
|
|
390
|
+
// Step 10: README.md を更新(オプション、プロジェクトディレクトリに)
|
|
391
|
+
console.log('\n📖 Step 10: Updating documentation...');
|
|
313
392
|
|
|
314
393
|
const readmePath = join(projectDir, 'README.md');
|
|
315
394
|
if (existsSync(readmePath)) {
|
|
@@ -351,8 +430,8 @@ npm run github:create-pr <branch> # PR作成
|
|
|
351
430
|
}
|
|
352
431
|
}
|
|
353
432
|
|
|
354
|
-
// Step
|
|
355
|
-
console.log('\n🚫 Step
|
|
433
|
+
// Step 11: .gitignore 更新(リポジトリルートに)
|
|
434
|
+
console.log('\n🚫 Step 11: Updating .gitignore...');
|
|
356
435
|
|
|
357
436
|
const gitignoreEntries = [
|
|
358
437
|
'# AI Development Workflow',
|
|
@@ -393,14 +472,15 @@ npm run github:create-pr <branch> # PR作成
|
|
|
393
472
|
console.log(' 2. .env ファイルを編集して認証情報を設定');
|
|
394
473
|
console.log(' 3. package.json が既存の場合、スクリプトを手動追加');
|
|
395
474
|
console.log(' 4. npm install で依存関係をインストール(リポジトリルートで実行)');
|
|
396
|
-
console.log(
|
|
397
|
-
console.log(' 6.
|
|
398
|
-
console.log(' 7.
|
|
475
|
+
console.log(` 5. cc-sddを導入: npx cc-sdd@latest --lang ${config.langCode} --${config.environment}`);
|
|
476
|
+
console.log(' 6. jj commit でセットアップをコミット');
|
|
477
|
+
console.log(' 7. Cursor で開く: cursor .');
|
|
478
|
+
console.log(' 8. /kiro:spec-init <機能説明> で開発開始');
|
|
399
479
|
console.log('');
|
|
400
480
|
console.log('作成されたファイル:');
|
|
401
481
|
console.log(` - ${projectDir}/.kiro/project.json`);
|
|
402
|
-
console.log(` - ${projectDir}
|
|
403
|
-
console.log(` - ${projectDir}
|
|
482
|
+
console.log(` - ${projectDir}/${envConfig.rulesDir}/`);
|
|
483
|
+
console.log(` - ${projectDir}/${envConfig.commandsDir}/`);
|
|
404
484
|
console.log(` - ${projectDir}/.kiro/steering/ (3ファイル)`);
|
|
405
485
|
console.log(` - ${projectDir}/.kiro/settings/templates/ (3ファイル)`);
|
|
406
486
|
console.log(` - ${repoRoot}/package.json (新規の場合)`);
|
|
@@ -419,4 +499,3 @@ setupExistingProject(config).catch(error => {
|
|
|
419
499
|
console.error('❌ Error:', error.message);
|
|
420
500
|
process.exit(1);
|
|
421
501
|
});
|
|
422
|
-
|