create-ai-project 1.11.2
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/.claude/agents/acceptance-test-generator.md +316 -0
- package/.claude/agents/code-reviewer.md +193 -0
- package/.claude/agents/document-reviewer.md +182 -0
- package/.claude/agents/prd-creator.md +186 -0
- package/.claude/agents/quality-fixer.md +295 -0
- package/.claude/agents/requirement-analyzer.md +161 -0
- package/.claude/agents/rule-advisor.md +194 -0
- package/.claude/agents/task-decomposer.md +291 -0
- package/.claude/agents/task-executor.md +270 -0
- package/.claude/agents/technical-designer.md +343 -0
- package/.claude/agents/work-planner.md +181 -0
- package/.claude/agents-en/acceptance-test-generator.md +256 -0
- package/.claude/agents-en/code-reviewer.md +195 -0
- package/.claude/agents-en/design-sync.md +225 -0
- package/.claude/agents-en/document-reviewer.md +190 -0
- package/.claude/agents-en/integration-test-reviewer.md +195 -0
- package/.claude/agents-en/prd-creator.md +196 -0
- package/.claude/agents-en/quality-fixer-frontend.md +334 -0
- package/.claude/agents-en/quality-fixer.md +291 -0
- package/.claude/agents-en/requirement-analyzer.md +165 -0
- package/.claude/agents-en/rule-advisor.md +194 -0
- package/.claude/agents-en/task-decomposer.md +291 -0
- package/.claude/agents-en/task-executor-frontend.md +276 -0
- package/.claude/agents-en/task-executor.md +272 -0
- package/.claude/agents-en/technical-designer-frontend.md +441 -0
- package/.claude/agents-en/technical-designer.md +371 -0
- package/.claude/agents-en/work-planner.md +216 -0
- package/.claude/agents-ja/acceptance-test-generator.md +256 -0
- package/.claude/agents-ja/code-reviewer.md +195 -0
- package/.claude/agents-ja/design-sync.md +225 -0
- package/.claude/agents-ja/document-reviewer.md +192 -0
- package/.claude/agents-ja/integration-test-reviewer.md +195 -0
- package/.claude/agents-ja/prd-creator.md +194 -0
- package/.claude/agents-ja/quality-fixer-frontend.md +335 -0
- package/.claude/agents-ja/quality-fixer.md +292 -0
- package/.claude/agents-ja/requirement-analyzer.md +164 -0
- package/.claude/agents-ja/rule-advisor.md +194 -0
- package/.claude/agents-ja/task-decomposer.md +291 -0
- package/.claude/agents-ja/task-executor-frontend.md +276 -0
- package/.claude/agents-ja/task-executor.md +272 -0
- package/.claude/agents-ja/technical-designer-frontend.md +442 -0
- package/.claude/agents-ja/technical-designer.md +370 -0
- package/.claude/agents-ja/work-planner.md +213 -0
- package/.claude/commands/build.md +78 -0
- package/.claude/commands/design.md +27 -0
- package/.claude/commands/implement.md +79 -0
- package/.claude/commands/plan.md +43 -0
- package/.claude/commands/project-inject.md +76 -0
- package/.claude/commands/refine-rule.md +206 -0
- package/.claude/commands/review.md +78 -0
- package/.claude/commands/sync-rules.md +116 -0
- package/.claude/commands/task.md +13 -0
- package/.claude/commands-en/build.md +77 -0
- package/.claude/commands-en/design.md +39 -0
- package/.claude/commands-en/front-build.md +103 -0
- package/.claude/commands-en/front-design.md +42 -0
- package/.claude/commands-en/front-plan.md +40 -0
- package/.claude/commands-en/implement.md +75 -0
- package/.claude/commands-en/plan.md +45 -0
- package/.claude/commands-en/project-inject.md +76 -0
- package/.claude/commands-en/refine-rule.md +208 -0
- package/.claude/commands-en/review.md +78 -0
- package/.claude/commands-en/sync-rules.md +116 -0
- package/.claude/commands-en/task.md +13 -0
- package/.claude/commands-ja/build.md +75 -0
- package/.claude/commands-ja/design.md +37 -0
- package/.claude/commands-ja/front-build.md +103 -0
- package/.claude/commands-ja/front-design.md +42 -0
- package/.claude/commands-ja/front-plan.md +40 -0
- package/.claude/commands-ja/implement.md +73 -0
- package/.claude/commands-ja/plan.md +43 -0
- package/.claude/commands-ja/project-inject.md +76 -0
- package/.claude/commands-ja/refine-rule.md +206 -0
- package/.claude/commands-ja/review.md +78 -0
- package/.claude/commands-ja/sync-rules.md +116 -0
- package/.claude/commands-ja/task.md +13 -0
- package/.claude/settings.local.json +74 -0
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +3 -0
- package/.madgerc +14 -0
- package/.tsprunerc +11 -0
- package/CLAUDE.en.md +102 -0
- package/CLAUDE.ja.md +102 -0
- package/CLAUDE.md +111 -0
- package/LICENSE +21 -0
- package/README.ja.md +233 -0
- package/README.md +243 -0
- package/bin/create-project.js +87 -0
- package/biome.json +51 -0
- package/docs/adr/template-en.md +64 -0
- package/docs/adr/template-ja.md +64 -0
- package/docs/design/template-en.md +281 -0
- package/docs/design/template-ja.md +285 -0
- package/docs/guides/en/quickstart.md +111 -0
- package/docs/guides/en/rule-editing-guide.md +266 -0
- package/docs/guides/en/sub-agents.md +343 -0
- package/docs/guides/en/use-cases.md +308 -0
- package/docs/guides/ja/quickstart.md +112 -0
- package/docs/guides/ja/rule-editing-guide.md +266 -0
- package/docs/guides/ja/sub-agents.md +343 -0
- package/docs/guides/ja/use-cases.md +290 -0
- package/docs/guides/sub-agents.md +306 -0
- package/docs/plans/20250123-integration-test-improvement.md +993 -0
- package/docs/plans/template-en.md +130 -0
- package/docs/plans/template-ja.md +130 -0
- package/docs/prd/template-en.md +109 -0
- package/docs/prd/template-ja.md +109 -0
- package/docs/rules/ai-development-guide.md +260 -0
- package/docs/rules/architecture/implementation-approach.md +136 -0
- package/docs/rules/documentation-criteria.md +180 -0
- package/docs/rules/project-context.md +38 -0
- package/docs/rules/rules-index.yaml +137 -0
- package/docs/rules/technical-spec.md +47 -0
- package/docs/rules/typescript-testing.md +188 -0
- package/docs/rules/typescript.md +166 -0
- package/docs/rules-en/architecture/implementation-approach.md +136 -0
- package/docs/rules-en/coding-standards.md +333 -0
- package/docs/rules-en/documentation-criteria.md +184 -0
- package/docs/rules-en/frontend/technical-spec.md +143 -0
- package/docs/rules-en/frontend/typescript-testing.md +124 -0
- package/docs/rules-en/frontend/typescript.md +131 -0
- package/docs/rules-en/integration-e2e-testing.md +149 -0
- package/docs/rules-en/project-context.md +38 -0
- package/docs/rules-en/rules-index.yaml +211 -0
- package/docs/rules-en/technical-spec.md +86 -0
- package/docs/rules-en/typescript-testing.md +149 -0
- package/docs/rules-en/typescript.md +116 -0
- package/docs/rules-ja/architecture/implementation-approach.md +136 -0
- package/docs/rules-ja/coding-standards.md +333 -0
- package/docs/rules-ja/documentation-criteria.md +180 -0
- package/docs/rules-ja/frontend/technical-spec.md +143 -0
- package/docs/rules-ja/frontend/typescript-testing.md +124 -0
- package/docs/rules-ja/frontend/typescript.md +131 -0
- package/docs/rules-ja/integration-e2e-testing.md +149 -0
- package/docs/rules-ja/project-context.md +38 -0
- package/docs/rules-ja/rules-index.yaml +196 -0
- package/docs/rules-ja/technical-spec.md +86 -0
- package/docs/rules-ja/typescript-testing.md +149 -0
- package/docs/rules-ja/typescript.md +116 -0
- package/package.json +98 -0
- package/scripts/check-unused-exports.js +69 -0
- package/scripts/cleanup-test-processes.sh +32 -0
- package/scripts/post-setup.js +110 -0
- package/scripts/set-language.js +310 -0
- package/scripts/setup-project.js +199 -0
- package/scripts/show-coverage.js +74 -0
- package/src/index.ts +11 -0
- package/templates/.gitignore.template +52 -0
- package/tsconfig.json +50 -0
- package/vitest.config.mjs +47 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const SUPPORTED_LANGUAGES = ['ja', 'en'];
|
|
7
|
+
const CONFIG_FILE = '.claudelang';
|
|
8
|
+
|
|
9
|
+
// Language configuration file path definitions
|
|
10
|
+
const LANGUAGE_PATHS = {
|
|
11
|
+
claude: {
|
|
12
|
+
source: (lang) => `CLAUDE.${lang}.md`,
|
|
13
|
+
target: 'CLAUDE.md'
|
|
14
|
+
},
|
|
15
|
+
rules: {
|
|
16
|
+
source: (lang) => `docs/rules-${lang}`,
|
|
17
|
+
target: 'docs/rules'
|
|
18
|
+
},
|
|
19
|
+
guides: {
|
|
20
|
+
source: (lang) => `docs/guides/${lang}`,
|
|
21
|
+
target: 'docs/guides/sub-agents.md',
|
|
22
|
+
sourceFile: (lang) => `docs/guides/${lang}/sub-agents.md`
|
|
23
|
+
},
|
|
24
|
+
commands: {
|
|
25
|
+
source: (lang) => `.claude/commands-${lang}`,
|
|
26
|
+
target: '.claude/commands'
|
|
27
|
+
},
|
|
28
|
+
agents: {
|
|
29
|
+
source: (lang) => `.claude/agents-${lang}`,
|
|
30
|
+
target: '.claude/agents'
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Load configuration file
|
|
36
|
+
*/
|
|
37
|
+
function loadConfig() {
|
|
38
|
+
try {
|
|
39
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
40
|
+
return JSON.parse(content);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
// Default configuration if config file doesn't exist
|
|
43
|
+
return {
|
|
44
|
+
current: 'ja',
|
|
45
|
+
method: 'copy',
|
|
46
|
+
lastUpdated: null
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Save configuration file
|
|
53
|
+
*/
|
|
54
|
+
function saveConfig(config) {
|
|
55
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Recursively copy directory
|
|
60
|
+
*/
|
|
61
|
+
function copyDirectory(source, target) {
|
|
62
|
+
if (!fs.existsSync(source)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Create target directory
|
|
67
|
+
if (!fs.existsSync(target)) {
|
|
68
|
+
fs.mkdirSync(target, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const entries = fs.readdirSync(source, { withFileTypes: true });
|
|
72
|
+
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
const sourcePath = path.join(source, entry.name);
|
|
75
|
+
const targetPath = path.join(target, entry.name);
|
|
76
|
+
|
|
77
|
+
if (entry.isDirectory()) {
|
|
78
|
+
copyDirectory(sourcePath, targetPath);
|
|
79
|
+
} else {
|
|
80
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Remove directory
|
|
89
|
+
*/
|
|
90
|
+
function removeDirectory(dirPath) {
|
|
91
|
+
if (fs.existsSync(dirPath)) {
|
|
92
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Copy file
|
|
98
|
+
*/
|
|
99
|
+
function copyFile(source, target) {
|
|
100
|
+
if (!fs.existsSync(source)) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Create target directory
|
|
105
|
+
const targetDir = path.dirname(target);
|
|
106
|
+
if (!fs.existsSync(targetDir)) {
|
|
107
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fs.copyFileSync(source, target);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Detect current language
|
|
116
|
+
*/
|
|
117
|
+
function detectCurrentLanguage() {
|
|
118
|
+
const config = loadConfig();
|
|
119
|
+
return config.current;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Switch language
|
|
124
|
+
*/
|
|
125
|
+
function switchLanguage(targetLang) {
|
|
126
|
+
if (!SUPPORTED_LANGUAGES.includes(targetLang)) {
|
|
127
|
+
console.error(`ā Unsupported language: ${targetLang}`);
|
|
128
|
+
console.error(` Supported languages: ${SUPPORTED_LANGUAGES.join(', ')}`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`š Switching language to ${targetLang}...`);
|
|
133
|
+
|
|
134
|
+
let hasErrors = false;
|
|
135
|
+
|
|
136
|
+
// 1. Switch CLAUDE.md
|
|
137
|
+
const claudeSource = LANGUAGE_PATHS.claude.source(targetLang);
|
|
138
|
+
const claudeTarget = LANGUAGE_PATHS.claude.target;
|
|
139
|
+
|
|
140
|
+
if (fs.existsSync(claudeSource)) {
|
|
141
|
+
if (fs.existsSync(claudeTarget)) {
|
|
142
|
+
fs.unlinkSync(claudeTarget);
|
|
143
|
+
}
|
|
144
|
+
copyFile(claudeSource, claudeTarget);
|
|
145
|
+
console.log(`ā
Updated ${claudeTarget}`);
|
|
146
|
+
} else {
|
|
147
|
+
console.warn(`ā ļø ${claudeSource} does not exist`);
|
|
148
|
+
hasErrors = true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 2. Switch docs/rules
|
|
152
|
+
const rulesSource = LANGUAGE_PATHS.rules.source(targetLang);
|
|
153
|
+
const rulesTarget = LANGUAGE_PATHS.rules.target;
|
|
154
|
+
|
|
155
|
+
if (fs.existsSync(rulesSource)) {
|
|
156
|
+
removeDirectory(rulesTarget);
|
|
157
|
+
copyDirectory(rulesSource, rulesTarget);
|
|
158
|
+
console.log(`ā
Updated ${rulesTarget}`);
|
|
159
|
+
} else {
|
|
160
|
+
console.warn(`ā ļø ${rulesSource} does not exist`);
|
|
161
|
+
hasErrors = true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
// 3. Switch docs/guides/sub-agents.md
|
|
166
|
+
const guideSource = LANGUAGE_PATHS.guides.sourceFile(targetLang);
|
|
167
|
+
const guideTarget = LANGUAGE_PATHS.guides.target;
|
|
168
|
+
|
|
169
|
+
if (fs.existsSync(guideSource)) {
|
|
170
|
+
if (fs.existsSync(guideTarget)) {
|
|
171
|
+
fs.unlinkSync(guideTarget);
|
|
172
|
+
}
|
|
173
|
+
copyFile(guideSource, guideTarget);
|
|
174
|
+
console.log(`ā
Updated ${guideTarget}`);
|
|
175
|
+
} else {
|
|
176
|
+
console.warn(`ā ļø ${guideSource} does not exist`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 4. Switch .claude/commands (only if exists)
|
|
180
|
+
const commandsSource = LANGUAGE_PATHS.commands.source(targetLang);
|
|
181
|
+
const commandsTarget = LANGUAGE_PATHS.commands.target;
|
|
182
|
+
|
|
183
|
+
if (fs.existsSync(commandsSource)) {
|
|
184
|
+
removeDirectory(commandsTarget);
|
|
185
|
+
copyDirectory(commandsSource, commandsTarget);
|
|
186
|
+
console.log(`ā
Updated ${commandsTarget}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 5. Switch .claude/agents (only if exists)
|
|
190
|
+
const agentsSource = LANGUAGE_PATHS.agents.source(targetLang);
|
|
191
|
+
const agentsTarget = LANGUAGE_PATHS.agents.target;
|
|
192
|
+
|
|
193
|
+
if (fs.existsSync(agentsSource)) {
|
|
194
|
+
removeDirectory(agentsTarget);
|
|
195
|
+
copyDirectory(agentsSource, agentsTarget);
|
|
196
|
+
console.log(`ā
Updated ${agentsTarget}`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Save configuration
|
|
200
|
+
const config = {
|
|
201
|
+
current: targetLang,
|
|
202
|
+
method: 'copy',
|
|
203
|
+
lastUpdated: new Date().toISOString()
|
|
204
|
+
};
|
|
205
|
+
saveConfig(config);
|
|
206
|
+
|
|
207
|
+
if (hasErrors) {
|
|
208
|
+
console.log(`ā ļø Language switched to ${targetLang}, but some files are missing`);
|
|
209
|
+
} else {
|
|
210
|
+
console.log(`š Successfully switched language to ${targetLang}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Show current status
|
|
216
|
+
*/
|
|
217
|
+
function showStatus() {
|
|
218
|
+
const config = loadConfig();
|
|
219
|
+
|
|
220
|
+
console.log('š Multi-language configuration status:');
|
|
221
|
+
console.log(` Current language: ${config.current}`);
|
|
222
|
+
console.log(` Switch method: ${config.method}`);
|
|
223
|
+
console.log(` Last updated: ${config.lastUpdated || 'Not set'}`);
|
|
224
|
+
console.log();
|
|
225
|
+
|
|
226
|
+
console.log('š File existence check:');
|
|
227
|
+
for (const lang of SUPPORTED_LANGUAGES) {
|
|
228
|
+
console.log(`\n ${lang.toUpperCase()} language files:`);
|
|
229
|
+
|
|
230
|
+
// CLAUDE.md
|
|
231
|
+
const claudeFile = LANGUAGE_PATHS.claude.source(lang);
|
|
232
|
+
console.log(` ${claudeFile}: ${fs.existsSync(claudeFile) ? 'ā
' : 'ā'}`);
|
|
233
|
+
|
|
234
|
+
// docs/rules
|
|
235
|
+
const rulesDir = LANGUAGE_PATHS.rules.source(lang);
|
|
236
|
+
console.log(` ${rulesDir}: ${fs.existsSync(rulesDir) ? 'ā
' : 'ā'}`);
|
|
237
|
+
|
|
238
|
+
// docs/guides
|
|
239
|
+
const guideFile = LANGUAGE_PATHS.guides.sourceFile(lang);
|
|
240
|
+
console.log(` ${guideFile}: ${fs.existsSync(guideFile) ? 'ā
' : 'ā'}`);
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
console.log('\nš Currently active files:');
|
|
245
|
+
console.log(` CLAUDE.md: ${fs.existsSync('CLAUDE.md') ? 'ā
' : 'ā'}`);
|
|
246
|
+
console.log(` docs/rules: ${fs.existsSync('docs/rules') ? 'ā
' : 'ā'}`);
|
|
247
|
+
console.log(` docs/guides/sub-agents.md: ${fs.existsSync('docs/guides/sub-agents.md') ? 'ā
' : 'ā'}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Show help
|
|
252
|
+
*/
|
|
253
|
+
function showHelp() {
|
|
254
|
+
console.log('š Multi-language script');
|
|
255
|
+
console.log();
|
|
256
|
+
console.log('Usage:');
|
|
257
|
+
console.log(' node scripts/set-language.js <language>');
|
|
258
|
+
console.log(' node scripts/set-language.js --status');
|
|
259
|
+
console.log(' node scripts/set-language.js --help');
|
|
260
|
+
console.log();
|
|
261
|
+
console.log('Available languages:');
|
|
262
|
+
console.log(` ${SUPPORTED_LANGUAGES.join(', ')}`);
|
|
263
|
+
console.log();
|
|
264
|
+
console.log('Examples:');
|
|
265
|
+
console.log(' node scripts/set-language.js ja # Switch to Japanese');
|
|
266
|
+
console.log(' node scripts/set-language.js en # Switch to English');
|
|
267
|
+
console.log(' node scripts/set-language.js --status # Check current status');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Main processing
|
|
271
|
+
function main() {
|
|
272
|
+
const args = process.argv.slice(2);
|
|
273
|
+
|
|
274
|
+
if (args.length === 0) {
|
|
275
|
+
showHelp();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const command = args[0];
|
|
280
|
+
|
|
281
|
+
switch (command) {
|
|
282
|
+
case '--status':
|
|
283
|
+
showStatus();
|
|
284
|
+
break;
|
|
285
|
+
case '--help':
|
|
286
|
+
case '-h':
|
|
287
|
+
showHelp();
|
|
288
|
+
break;
|
|
289
|
+
default:
|
|
290
|
+
if (SUPPORTED_LANGUAGES.includes(command)) {
|
|
291
|
+
switchLanguage(command);
|
|
292
|
+
} else {
|
|
293
|
+
console.error(`ā Unknown command or language: ${command}`);
|
|
294
|
+
showHelp();
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (require.main === module) {
|
|
302
|
+
main();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
module.exports = {
|
|
306
|
+
switchLanguage,
|
|
307
|
+
detectCurrentLanguage,
|
|
308
|
+
showStatus,
|
|
309
|
+
SUPPORTED_LANGUAGES
|
|
310
|
+
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
// Get command line arguments
|
|
8
|
+
const projectName = process.argv[2];
|
|
9
|
+
const language = process.argv[3] || 'en';
|
|
10
|
+
|
|
11
|
+
if (!projectName) {
|
|
12
|
+
console.error('ā Project name is required');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const sourceRoot = path.join(__dirname, '..');
|
|
17
|
+
const targetRoot = path.resolve(process.cwd(), projectName);
|
|
18
|
+
|
|
19
|
+
// Files and directories to exclude from copying
|
|
20
|
+
const excludeList = [
|
|
21
|
+
'node_modules',
|
|
22
|
+
'.git',
|
|
23
|
+
'dist',
|
|
24
|
+
'coverage',
|
|
25
|
+
'.vitest-cache',
|
|
26
|
+
'tmp',
|
|
27
|
+
'.claudelang',
|
|
28
|
+
'CLAUDE.md',
|
|
29
|
+
'docs/rules',
|
|
30
|
+
'docs/guides/sub-agents.md',
|
|
31
|
+
'.claude/commands',
|
|
32
|
+
'.claude/agents',
|
|
33
|
+
'bin', // Exclude bin directory for production use
|
|
34
|
+
'templates' // Exclude templates directory for production use
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
// Files to process with template replacements
|
|
38
|
+
const templateFiles = [
|
|
39
|
+
'package.json',
|
|
40
|
+
'README.md',
|
|
41
|
+
'README.ja.md'
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Recursively copy directory with exclusions
|
|
46
|
+
*/
|
|
47
|
+
function copyDirectory(source, target, projectName, rootSource = source) {
|
|
48
|
+
if (!fs.existsSync(source)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Create target directory
|
|
53
|
+
if (!fs.existsSync(target)) {
|
|
54
|
+
fs.mkdirSync(target, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const entries = fs.readdirSync(source, { withFileTypes: true });
|
|
58
|
+
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const sourcePath = path.join(source, entry.name);
|
|
61
|
+
const targetPath = path.join(target, entry.name);
|
|
62
|
+
const relativePath = path.relative(rootSource, sourcePath);
|
|
63
|
+
|
|
64
|
+
// Check if should exclude
|
|
65
|
+
const shouldExclude = excludeList.some(exclude => {
|
|
66
|
+
const excludePath = path.normalize(exclude);
|
|
67
|
+
const relativeNormalized = path.normalize(relativePath);
|
|
68
|
+
return relativeNormalized === excludePath || relativeNormalized.startsWith(excludePath + path.sep);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (shouldExclude) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (entry.isDirectory()) {
|
|
76
|
+
copyDirectory(sourcePath, targetPath, projectName, rootSource);
|
|
77
|
+
} else {
|
|
78
|
+
// Check if it's a template file that needs processing
|
|
79
|
+
if (templateFiles.includes(entry.name)) {
|
|
80
|
+
processTemplateFile(sourcePath, targetPath, projectName);
|
|
81
|
+
} else {
|
|
82
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Process template files with replacements
|
|
90
|
+
*/
|
|
91
|
+
function processTemplateFile(source, target, projectName) {
|
|
92
|
+
let content = fs.readFileSync(source, 'utf8');
|
|
93
|
+
|
|
94
|
+
// Replace placeholders based on file
|
|
95
|
+
const fileName = path.basename(source);
|
|
96
|
+
|
|
97
|
+
if (fileName === 'package.json') {
|
|
98
|
+
const packageJson = JSON.parse(content);
|
|
99
|
+
packageJson.name = projectName;
|
|
100
|
+
packageJson.version = '0.1.0';
|
|
101
|
+
packageJson.description = `${projectName} - AI-powered TypeScript project`;
|
|
102
|
+
|
|
103
|
+
// Remove bin field for user projects
|
|
104
|
+
delete packageJson.bin;
|
|
105
|
+
|
|
106
|
+
// Remove scripts related to package maintenance
|
|
107
|
+
delete packageJson.scripts['lang:status'];
|
|
108
|
+
delete packageJson.scripts.postinstall;
|
|
109
|
+
|
|
110
|
+
content = JSON.stringify(packageJson, null, 2);
|
|
111
|
+
} else if (fileName === 'README.md' || fileName === 'README.ja.md') {
|
|
112
|
+
// Replace project name in README
|
|
113
|
+
content = content.replace(/ai-coding-project-boilerplate/g, projectName);
|
|
114
|
+
content = content.replace(/AI Coding Project Boilerplate/g, projectName);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
fs.writeFileSync(target, content);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Create .gitignore with language-specific exclusions
|
|
122
|
+
*/
|
|
123
|
+
function createGitignore(projectPath) {
|
|
124
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
125
|
+
const templatePath = path.join(sourceRoot, 'templates', '.gitignore.template');
|
|
126
|
+
|
|
127
|
+
// Use template if exists, otherwise use current .gitignore
|
|
128
|
+
const sourcePath = fs.existsSync(templatePath) ? templatePath : path.join(sourceRoot, '.gitignore');
|
|
129
|
+
let content = fs.readFileSync(sourcePath, 'utf8');
|
|
130
|
+
|
|
131
|
+
// Add language-specific exclusions
|
|
132
|
+
const languageExclusions = `
|
|
133
|
+
# Language-specific files (excluded from version control)
|
|
134
|
+
CLAUDE.*.md
|
|
135
|
+
docs/rules-*/
|
|
136
|
+
docs/guides/ja/
|
|
137
|
+
docs/guides/en/
|
|
138
|
+
.claude/commands-*/
|
|
139
|
+
.claude/agents-*/
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
// Remove current language-related exclusions and add new ones
|
|
143
|
+
const lines = content.split('\n');
|
|
144
|
+
const filteredLines = lines.filter(line => {
|
|
145
|
+
const trimmed = line.trim();
|
|
146
|
+
return !trimmed.startsWith('CLAUDE.md') &&
|
|
147
|
+
!trimmed.startsWith('docs/rules/') &&
|
|
148
|
+
!trimmed.startsWith('docs/guides/sub-agents.md') &&
|
|
149
|
+
!trimmed.startsWith('.claude/commands/') &&
|
|
150
|
+
!trimmed.startsWith('.claude/agents/');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
content = filteredLines.join('\n') + languageExclusions;
|
|
154
|
+
fs.writeFileSync(gitignorePath, content);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Main setup process
|
|
159
|
+
*/
|
|
160
|
+
async function setupProject() {
|
|
161
|
+
try {
|
|
162
|
+
console.log('š Creating project directory...');
|
|
163
|
+
fs.mkdirSync(targetRoot, { recursive: true });
|
|
164
|
+
|
|
165
|
+
console.log('š Copying project files...');
|
|
166
|
+
copyDirectory(sourceRoot, targetRoot, projectName);
|
|
167
|
+
|
|
168
|
+
console.log('š§ Setting up language configuration...');
|
|
169
|
+
// Change to project directory and run language setup
|
|
170
|
+
process.chdir(targetRoot);
|
|
171
|
+
|
|
172
|
+
// Run language setup
|
|
173
|
+
execSync(`node scripts/set-language.js ${language}`, { stdio: 'inherit' });
|
|
174
|
+
|
|
175
|
+
console.log('š Creating .gitignore with language-specific exclusions...');
|
|
176
|
+
createGitignore(targetRoot);
|
|
177
|
+
|
|
178
|
+
console.log('š§ Running post-setup tasks...');
|
|
179
|
+
const postSetupScript = path.join(sourceRoot, 'scripts', 'post-setup.js');
|
|
180
|
+
if (fs.existsSync(postSetupScript)) {
|
|
181
|
+
execSync(`node ${postSetupScript}`, { stdio: 'inherit', cwd: targetRoot });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log('ā
Project setup completed!');
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error(`ā Setup failed: ${error.message}`);
|
|
187
|
+
|
|
188
|
+
// Cleanup on failure
|
|
189
|
+
if (fs.existsSync(targetRoot)) {
|
|
190
|
+
console.log('š§¹ Cleaning up...');
|
|
191
|
+
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Run setup
|
|
199
|
+
setupProject();
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
const coverageFile = path.join(__dirname, '..', 'coverage', 'coverage-final.json')
|
|
7
|
+
|
|
8
|
+
if (!fs.existsSync(coverageFile)) {
|
|
9
|
+
console.error('ā Coverage report not found.')
|
|
10
|
+
console.error(' Please run npm run test:coverage first.')
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const coverage = JSON.parse(fs.readFileSync(coverageFile, 'utf8'))
|
|
16
|
+
|
|
17
|
+
let totalStatements = 0
|
|
18
|
+
let coveredStatements = 0
|
|
19
|
+
let totalBranches = 0
|
|
20
|
+
let coveredBranches = 0
|
|
21
|
+
let totalFunctions = 0
|
|
22
|
+
let coveredFunctions = 0
|
|
23
|
+
let totalLines = 0
|
|
24
|
+
let coveredLines = 0
|
|
25
|
+
|
|
26
|
+
Object.values(coverage).forEach(file => {
|
|
27
|
+
totalStatements += file.s ? Object.keys(file.s).length : 0
|
|
28
|
+
coveredStatements += file.s ? Object.values(file.s).filter(count => count > 0).length : 0
|
|
29
|
+
|
|
30
|
+
totalBranches += file.b ? Object.values(file.b).flat().length : 0
|
|
31
|
+
coveredBranches += file.b ? Object.values(file.b).flat().filter(count => count > 0).length : 0
|
|
32
|
+
|
|
33
|
+
totalFunctions += file.f ? Object.keys(file.f).length : 0
|
|
34
|
+
coveredFunctions += file.f ? Object.values(file.f).filter(count => count > 0).length : 0
|
|
35
|
+
|
|
36
|
+
totalLines += file.l ? Object.keys(file.l).length : 0
|
|
37
|
+
coveredLines += file.l ? Object.values(file.l).filter(count => count > 0).length : 0
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const statementsCoverage = totalStatements > 0 ? ((coveredStatements / totalStatements) * 100).toFixed(2) : '0.00'
|
|
41
|
+
const branchesCoverage = totalBranches > 0 ? ((coveredBranches / totalBranches) * 100).toFixed(2) : '0.00'
|
|
42
|
+
const functionsCoverage = totalFunctions > 0 ? ((coveredFunctions / totalFunctions) * 100).toFixed(2) : '0.00'
|
|
43
|
+
const linesCoverage = totalLines > 0 ? ((coveredLines / totalLines) * 100).toFixed(2) : '0.00'
|
|
44
|
+
|
|
45
|
+
console.log('\nš Test Coverage Summary')
|
|
46
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā')
|
|
47
|
+
console.log(` Statements : ${statementsCoverage.padStart(6)}% (${coveredStatements}/${totalStatements})`)
|
|
48
|
+
console.log(` Branches : ${branchesCoverage.padStart(6)}% (${coveredBranches}/${totalBranches})`)
|
|
49
|
+
console.log(` Functions : ${functionsCoverage.padStart(6)}% (${coveredFunctions}/${totalFunctions})`)
|
|
50
|
+
console.log(` Lines : ${linesCoverage.padStart(6)}% (${coveredLines}/${totalLines})`)
|
|
51
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā')
|
|
52
|
+
|
|
53
|
+
// Assessment against 80% target
|
|
54
|
+
const allMetrics = [
|
|
55
|
+
parseFloat(statementsCoverage),
|
|
56
|
+
parseFloat(branchesCoverage),
|
|
57
|
+
parseFloat(functionsCoverage),
|
|
58
|
+
parseFloat(linesCoverage)
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
const failedMetrics = allMetrics.filter(metric => metric < 80).length
|
|
62
|
+
|
|
63
|
+
if (failedMetrics === 0) {
|
|
64
|
+
console.log('\nā
All metrics achieved the 80% target!')
|
|
65
|
+
} else {
|
|
66
|
+
console.log('\nā ļø Some metrics have not reached the 80% target.')
|
|
67
|
+
console.log(' Please check coverage/index.html for details.')
|
|
68
|
+
}
|
|
69
|
+
console.log()
|
|
70
|
+
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('ā Failed to read coverage report:', error.message)
|
|
73
|
+
process.exit(1)
|
|
74
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application entry point
|
|
3
|
+
*
|
|
4
|
+
* This file serves as a usage example for the boilerplate.
|
|
5
|
+
* In actual projects, implement your application-specific logic here.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
console.log('Hello from TypeScript boilerplate!')
|
|
9
|
+
|
|
10
|
+
// Add your project-specific implementation here
|
|
11
|
+
export {}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
npm-debug.log*
|
|
4
|
+
yarn-debug.log*
|
|
5
|
+
yarn-error.log*
|
|
6
|
+
|
|
7
|
+
# Build artifacts
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.tsbuildinfo
|
|
11
|
+
|
|
12
|
+
# Environment variables
|
|
13
|
+
.env
|
|
14
|
+
.env.local
|
|
15
|
+
.env.development.local
|
|
16
|
+
.env.test.local
|
|
17
|
+
.env.production.local
|
|
18
|
+
|
|
19
|
+
# Log files
|
|
20
|
+
logs
|
|
21
|
+
*.log
|
|
22
|
+
|
|
23
|
+
# Runtime data
|
|
24
|
+
.nyc_output
|
|
25
|
+
coverage
|
|
26
|
+
test-output.json
|
|
27
|
+
|
|
28
|
+
# IDE and editor specific files
|
|
29
|
+
.vscode/
|
|
30
|
+
.idea/
|
|
31
|
+
*.swp
|
|
32
|
+
*.swo
|
|
33
|
+
*~
|
|
34
|
+
|
|
35
|
+
# OS specific files
|
|
36
|
+
.DS_Store
|
|
37
|
+
Thumbs.db
|
|
38
|
+
|
|
39
|
+
# Temporary files
|
|
40
|
+
*.tmp
|
|
41
|
+
*.temp
|
|
42
|
+
tmp/
|
|
43
|
+
|
|
44
|
+
# Work plans (excluded from commits)
|
|
45
|
+
docs/plans/*
|
|
46
|
+
!docs/plans/template-*.md
|
|
47
|
+
|
|
48
|
+
# Work plan tasks (auto-generated)
|
|
49
|
+
docs/plans/tasks/
|
|
50
|
+
|
|
51
|
+
# Multi-language related (dynamically generated by npm scripts)
|
|
52
|
+
.claudelang
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Basic configuration
|
|
4
|
+
"target": "ES2020",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"lib": ["ES2020"],
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"baseUrl": ".", // Use project root as reference
|
|
9
|
+
"paths": {
|
|
10
|
+
"src/*": ["src/*"]
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
// Output configuration
|
|
14
|
+
"outDir": "./dist",
|
|
15
|
+
"rootDir": "./src",
|
|
16
|
+
"sourceMap": true,
|
|
17
|
+
"declaration": true,
|
|
18
|
+
"declarationMap": true,
|
|
19
|
+
|
|
20
|
+
// Strict type checking (this is important!)
|
|
21
|
+
"strict": true, // Enable all strict checks
|
|
22
|
+
"noImplicitAny": true, // Prohibit implicit any
|
|
23
|
+
"strictNullChecks": true, // Strict null/undefined checks
|
|
24
|
+
"strictFunctionTypes": true, // Strict function type checks
|
|
25
|
+
"strictBindCallApply": true, // Strict bind/call/apply checks
|
|
26
|
+
"strictPropertyInitialization": true, // Strict property initialization checks
|
|
27
|
+
"noImplicitThis": true, // Prohibit implicit this
|
|
28
|
+
"alwaysStrict": true, // Always enable strict mode
|
|
29
|
+
|
|
30
|
+
// Additional safety checks (currently disabled in this PR)
|
|
31
|
+
"noUncheckedIndexedAccess": true, // Safety checks for index access
|
|
32
|
+
"exactOptionalPropertyTypes": true, // Strict type checking for optional properties
|
|
33
|
+
"noPropertyAccessFromIndexSignature": true, // Prohibit property access from index signature
|
|
34
|
+
|
|
35
|
+
// Error detection
|
|
36
|
+
"noFallthroughCasesInSwitch": true, // Prohibit fallthrough in switch statements
|
|
37
|
+
"noImplicitReturns": true, // Prohibit implicit returns
|
|
38
|
+
"noImplicitOverride": true, // Require override keyword
|
|
39
|
+
"noUnusedLocals": true, // Detect unused local variables
|
|
40
|
+
"noUnusedParameters": true, // Detect unused parameters
|
|
41
|
+
|
|
42
|
+
// Module resolution
|
|
43
|
+
"esModuleInterop": true,
|
|
44
|
+
"skipLibCheck": true, // Skip type checking of declaration files (build optimization)
|
|
45
|
+
"forceConsistentCasingInFileNames": true,
|
|
46
|
+
"resolveJsonModule": true
|
|
47
|
+
},
|
|
48
|
+
"include": ["src/**/*"],
|
|
49
|
+
"exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
|
|
50
|
+
}
|