@qazuor/claude-code-config 0.6.1 → 0.6.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.
- package/dist/bin.cjs +319 -216
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +319 -216
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -5523,12 +5523,13 @@ var DEFAULT_DENY_RULES = [
|
|
|
5523
5523
|
"Write(/sbin/**)",
|
|
5524
5524
|
"Write(/var/**)",
|
|
5525
5525
|
"Write(/tmp/**)",
|
|
5526
|
-
// Dangerous commands
|
|
5526
|
+
// Dangerous commands - use exact matches or :* prefix
|
|
5527
5527
|
"Bash(rm -rf /)",
|
|
5528
|
-
"Bash(sudo
|
|
5529
|
-
"Bash(chmod 777
|
|
5530
|
-
"
|
|
5531
|
-
"Bash(
|
|
5528
|
+
"Bash(sudo:*)",
|
|
5529
|
+
"Bash(chmod 777:*)",
|
|
5530
|
+
// Note: Can't deny "curl * | bash" pattern - use specific denies instead
|
|
5531
|
+
"Bash(curl:*)",
|
|
5532
|
+
"Bash(wget:*)",
|
|
5532
5533
|
// Sensitive files
|
|
5533
5534
|
"Write(.env)",
|
|
5534
5535
|
"Write(.env.*)",
|
|
@@ -5594,64 +5595,69 @@ function generateAllowRules(config) {
|
|
|
5594
5595
|
}
|
|
5595
5596
|
if (config.git.readOnly) {
|
|
5596
5597
|
rules.push(
|
|
5597
|
-
"Bash(git status
|
|
5598
|
-
"Bash(git diff
|
|
5599
|
-
"Bash(git log
|
|
5600
|
-
"Bash(git show
|
|
5601
|
-
"Bash(git branch
|
|
5598
|
+
"Bash(git status:*)",
|
|
5599
|
+
"Bash(git diff:*)",
|
|
5600
|
+
"Bash(git log:*)",
|
|
5601
|
+
"Bash(git show:*)",
|
|
5602
|
+
"Bash(git branch:*)"
|
|
5602
5603
|
);
|
|
5603
5604
|
}
|
|
5604
5605
|
if (config.git.staging) {
|
|
5605
|
-
rules.push("Bash(git add
|
|
5606
|
+
rules.push("Bash(git add:*)");
|
|
5606
5607
|
}
|
|
5607
5608
|
if (config.git.commit) {
|
|
5608
|
-
rules.push("Bash(git commit
|
|
5609
|
+
rules.push("Bash(git commit:*)");
|
|
5609
5610
|
}
|
|
5610
5611
|
if (config.git.push) {
|
|
5611
|
-
rules.push("Bash(git push
|
|
5612
|
+
rules.push("Bash(git push:*)");
|
|
5612
5613
|
}
|
|
5613
5614
|
if (config.git.branching) {
|
|
5614
|
-
rules.push(
|
|
5615
|
+
rules.push(
|
|
5616
|
+
"Bash(git checkout:*)",
|
|
5617
|
+
"Bash(git branch:*)",
|
|
5618
|
+
"Bash(git merge:*)",
|
|
5619
|
+
"Bash(git rebase:*)"
|
|
5620
|
+
);
|
|
5615
5621
|
}
|
|
5616
5622
|
if (config.bash.packageManager) {
|
|
5617
5623
|
rules.push(
|
|
5618
|
-
"Bash(pnpm
|
|
5619
|
-
"Bash(npm
|
|
5620
|
-
"Bash(yarn
|
|
5621
|
-
"Bash(bun
|
|
5622
|
-
"Bash(npx
|
|
5623
|
-
"Bash(bunx
|
|
5624
|
+
"Bash(pnpm:*)",
|
|
5625
|
+
"Bash(npm:*)",
|
|
5626
|
+
"Bash(yarn:*)",
|
|
5627
|
+
"Bash(bun:*)",
|
|
5628
|
+
"Bash(npx:*)",
|
|
5629
|
+
"Bash(bunx:*)"
|
|
5624
5630
|
);
|
|
5625
5631
|
}
|
|
5626
5632
|
if (config.bash.testing) {
|
|
5627
5633
|
rules.push(
|
|
5628
|
-
"Bash(vitest
|
|
5629
|
-
"Bash(jest
|
|
5630
|
-
"Bash(playwright
|
|
5631
|
-
"Bash(cypress
|
|
5632
|
-
"Bash(pnpm test
|
|
5633
|
-
"Bash(npm test
|
|
5634
|
-
"Bash(pnpm run test
|
|
5635
|
-
"Bash(npm run test
|
|
5634
|
+
"Bash(vitest:*)",
|
|
5635
|
+
"Bash(jest:*)",
|
|
5636
|
+
"Bash(playwright:*)",
|
|
5637
|
+
"Bash(cypress:*)",
|
|
5638
|
+
"Bash(pnpm test:*)",
|
|
5639
|
+
"Bash(npm test:*)",
|
|
5640
|
+
"Bash(pnpm run test:*)",
|
|
5641
|
+
"Bash(npm run test:*)"
|
|
5636
5642
|
);
|
|
5637
5643
|
}
|
|
5638
5644
|
if (config.bash.building) {
|
|
5639
5645
|
rules.push(
|
|
5640
|
-
"Bash(pnpm build
|
|
5641
|
-
"Bash(npm run build
|
|
5642
|
-
"Bash(pnpm run build
|
|
5643
|
-
"Bash(tsc
|
|
5644
|
-
"Bash(tsup
|
|
5645
|
-
"Bash(vite build
|
|
5646
|
-
"Bash(next build
|
|
5647
|
-
"Bash(astro build
|
|
5646
|
+
"Bash(pnpm build:*)",
|
|
5647
|
+
"Bash(npm run build:*)",
|
|
5648
|
+
"Bash(pnpm run build:*)",
|
|
5649
|
+
"Bash(tsc:*)",
|
|
5650
|
+
"Bash(tsup:*)",
|
|
5651
|
+
"Bash(vite build:*)",
|
|
5652
|
+
"Bash(next build:*)",
|
|
5653
|
+
"Bash(astro build:*)"
|
|
5648
5654
|
);
|
|
5649
5655
|
}
|
|
5650
5656
|
if (config.bash.docker) {
|
|
5651
|
-
rules.push("Bash(docker
|
|
5657
|
+
rules.push("Bash(docker:*)", "Bash(docker-compose:*)");
|
|
5652
5658
|
}
|
|
5653
5659
|
if (config.bash.arbitrary) {
|
|
5654
|
-
rules.push("Bash
|
|
5660
|
+
rules.push("Bash");
|
|
5655
5661
|
}
|
|
5656
5662
|
if (config.web.fetch) {
|
|
5657
5663
|
rules.push("WebFetch");
|
|
@@ -6065,29 +6071,6 @@ function showReplacementReport(report) {
|
|
|
6065
6071
|
// src/lib/scaffold/claude-md-generator.ts
|
|
6066
6072
|
init_cjs_shims();
|
|
6067
6073
|
init_fs();
|
|
6068
|
-
|
|
6069
|
-
// src/lib/utils/paths.ts
|
|
6070
|
-
init_cjs_shims();
|
|
6071
|
-
var import_node_fs = __toESM(require("fs"), 1);
|
|
6072
|
-
var import_node_path3 = __toESM(require("path"), 1);
|
|
6073
|
-
var import_node_url = require("url");
|
|
6074
|
-
function getPackageRoot() {
|
|
6075
|
-
const currentFilePath = (0, import_node_url.fileURLToPath)(importMetaUrl);
|
|
6076
|
-
let currentDir = import_node_path3.default.dirname(currentFilePath);
|
|
6077
|
-
while (currentDir !== import_node_path3.default.dirname(currentDir)) {
|
|
6078
|
-
const packageJsonPath = import_node_path3.default.join(currentDir, "package.json");
|
|
6079
|
-
if (import_node_fs.default.existsSync(packageJsonPath)) {
|
|
6080
|
-
return currentDir;
|
|
6081
|
-
}
|
|
6082
|
-
currentDir = import_node_path3.default.dirname(currentDir);
|
|
6083
|
-
}
|
|
6084
|
-
throw new Error("Could not find package root (no package.json found in parent directories)");
|
|
6085
|
-
}
|
|
6086
|
-
function getTemplatesPath() {
|
|
6087
|
-
return import_node_path3.default.join(getPackageRoot(), "templates");
|
|
6088
|
-
}
|
|
6089
|
-
|
|
6090
|
-
// src/lib/scaffold/claude-md-generator.ts
|
|
6091
6074
|
async function generateClaudeMd(projectPath, projectInfo, options) {
|
|
6092
6075
|
const claudeMdPath = joinPath(projectPath, "CLAUDE.md");
|
|
6093
6076
|
const exists = await pathExists(claudeMdPath);
|
|
@@ -6099,18 +6082,12 @@ async function generateClaudeMd(projectPath, projectInfo, options) {
|
|
|
6099
6082
|
};
|
|
6100
6083
|
}
|
|
6101
6084
|
try {
|
|
6102
|
-
let
|
|
6085
|
+
let content;
|
|
6103
6086
|
if (options?.customTemplate) {
|
|
6104
|
-
|
|
6087
|
+
content = processCustomTemplate(options.customTemplate, projectInfo);
|
|
6105
6088
|
} else {
|
|
6106
|
-
|
|
6107
|
-
if (await pathExists(templatePath)) {
|
|
6108
|
-
template = await readFile(templatePath);
|
|
6109
|
-
} else {
|
|
6110
|
-
template = getMinimalTemplate();
|
|
6111
|
-
}
|
|
6089
|
+
content = generateClaudeMdContent(projectInfo, options);
|
|
6112
6090
|
}
|
|
6113
|
-
const content = processTemplate(template, projectInfo, options);
|
|
6114
6091
|
await writeFile(claudeMdPath, content);
|
|
6115
6092
|
return {
|
|
6116
6093
|
created: true,
|
|
@@ -6135,41 +6112,165 @@ async function generateClaudeMdWithSpinner(projectPath, projectInfo, options) {
|
|
|
6135
6112
|
}
|
|
6136
6113
|
);
|
|
6137
6114
|
}
|
|
6138
|
-
function
|
|
6139
|
-
|
|
6115
|
+
function processCustomTemplate(template, projectInfo) {
|
|
6116
|
+
return template.replace(/\{\{PROJECT_NAME\}\}/g, projectInfo.name).replace(/\{\{PROJECT_DESCRIPTION\}\}/g, projectInfo.description).replace(/\{\{ORG\}\}/g, projectInfo.org).replace(/\{\{REPO\}\}/g, projectInfo.repo).replace(/\{\{ENTITY_TYPE\}\}/g, projectInfo.entityType).replace(/\{\{ENTITY_TYPE_PLURAL\}\}/g, projectInfo.entityTypePlural).replace(/\{\{DOMAIN\}\}/g, projectInfo.domain || "").replace(/\{\{LOCATION\}\}/g, projectInfo.location || "");
|
|
6117
|
+
}
|
|
6118
|
+
function generateClaudeMdContent(projectInfo, options) {
|
|
6140
6119
|
const techStack = options?.templateConfig?.techStack;
|
|
6141
6120
|
const commands = options?.templateConfig?.commands;
|
|
6142
6121
|
const targets = options?.templateConfig?.targets;
|
|
6143
6122
|
const preferences = options?.claudeConfig?.preferences;
|
|
6144
6123
|
const standards = options?.claudeConfig?.extras?.standards;
|
|
6145
|
-
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectInfo.name).replace(/\{\{PROJECT_DESCRIPTION\}\}/g, projectInfo.description).replace(/\{\{ORG\}\}/g, projectInfo.org).replace(/\{\{REPO\}\}/g, projectInfo.repo).replace(/\{\{ENTITY_TYPE\}\}/g, projectInfo.entityType).replace(/\{\{ENTITY_TYPE_PLURAL\}\}/g, projectInfo.entityTypePlural).replace(/\{\{LOCATION\}\}/g, projectInfo.location || "");
|
|
6146
6124
|
const packageManager = preferences?.packageManager || "pnpm";
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6125
|
+
const lines = [];
|
|
6126
|
+
lines.push("# CLAUDE.md");
|
|
6127
|
+
lines.push("");
|
|
6128
|
+
lines.push("## Project Overview");
|
|
6129
|
+
lines.push("");
|
|
6130
|
+
lines.push(`**${projectInfo.name}** - ${projectInfo.description}`);
|
|
6131
|
+
lines.push("");
|
|
6132
|
+
lines.push("## Repository");
|
|
6133
|
+
lines.push("");
|
|
6134
|
+
lines.push(`- **Organization:** ${projectInfo.org}`);
|
|
6135
|
+
lines.push(`- **Repository:** ${projectInfo.repo}`);
|
|
6136
|
+
lines.push(`- **GitHub:** https://github.com/${projectInfo.org}/${projectInfo.repo}`);
|
|
6151
6137
|
if (projectInfo.domain) {
|
|
6152
|
-
|
|
6153
|
-
} else {
|
|
6154
|
-
content = content.replace(/\{\{#if DOMAIN\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6138
|
+
lines.push(`- **Domain:** ${projectInfo.domain}`);
|
|
6155
6139
|
}
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6140
|
+
lines.push("");
|
|
6141
|
+
lines.push("## Tech Stack");
|
|
6142
|
+
lines.push("");
|
|
6143
|
+
lines.push(generateTechStackSection(techStack));
|
|
6144
|
+
lines.push("## Project Structure");
|
|
6145
|
+
lines.push("");
|
|
6146
|
+
lines.push("```text");
|
|
6147
|
+
lines.push(`${projectInfo.name}/`);
|
|
6148
|
+
lines.push("\u251C\u2500\u2500 src/ # Source code");
|
|
6149
|
+
lines.push("\u251C\u2500\u2500 tests/ # Test files");
|
|
6150
|
+
lines.push("\u251C\u2500\u2500 docs/ # Documentation");
|
|
6151
|
+
lines.push("\u2514\u2500\u2500 .claude/ # Claude configuration");
|
|
6152
|
+
lines.push(" \u251C\u2500\u2500 agents/ # AI agent definitions");
|
|
6153
|
+
lines.push(" \u251C\u2500\u2500 commands/ # Custom slash commands");
|
|
6154
|
+
lines.push(" \u251C\u2500\u2500 skills/ # Specialized skills");
|
|
6155
|
+
lines.push(" \u2514\u2500\u2500 docs/ # AI-specific documentation");
|
|
6156
|
+
lines.push("```");
|
|
6157
|
+
lines.push("");
|
|
6158
|
+
lines.push("## Quick Commands");
|
|
6159
|
+
lines.push("");
|
|
6160
|
+
lines.push(generateCommandsSection(commands, packageManager));
|
|
6161
|
+
lines.push("## Development Guidelines");
|
|
6162
|
+
lines.push("");
|
|
6163
|
+
lines.push("### Code Standards");
|
|
6164
|
+
lines.push("");
|
|
6165
|
+
lines.push("- Primary language: TypeScript");
|
|
6166
|
+
lines.push("- Follow TypeScript best practices");
|
|
6167
|
+
if (standards?.code?.namedExportsOnly) {
|
|
6168
|
+
lines.push("- Use named exports only (no default exports)");
|
|
6169
|
+
}
|
|
6170
|
+
const maxLines = standards?.code?.maxFileLines || 500;
|
|
6171
|
+
lines.push(`- Maximum ${maxLines} lines per file`);
|
|
6172
|
+
if (standards?.code?.jsDocRequired) {
|
|
6173
|
+
lines.push("- Document all exports with JSDoc");
|
|
6174
|
+
}
|
|
6175
|
+
if (standards?.code?.roroPattern) {
|
|
6176
|
+
lines.push("- Use RO-RO pattern (Receive Object, Return Object)");
|
|
6161
6177
|
}
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6178
|
+
lines.push("");
|
|
6179
|
+
lines.push("### Testing");
|
|
6180
|
+
lines.push("");
|
|
6181
|
+
if (standards?.testing?.tddRequired) {
|
|
6182
|
+
lines.push("- Methodology: TDD (Test-Driven Development)");
|
|
6183
|
+
lines.push("- Write tests first: Red -> Green -> Refactor");
|
|
6165
6184
|
} else {
|
|
6166
|
-
|
|
6185
|
+
lines.push("- Write comprehensive tests for all features");
|
|
6186
|
+
}
|
|
6187
|
+
const coverageTarget = standards?.testing?.coverageTarget || (targets && "coverage" in targets ? targets.coverage : 90);
|
|
6188
|
+
lines.push(`- Maintain ${coverageTarget}%+ code coverage`);
|
|
6189
|
+
const testPattern = standards?.testing?.testPattern === "gwt" ? "GWT (Given-When-Then)" : "AAA (Arrange, Act, Assert)";
|
|
6190
|
+
lines.push(`- Test pattern: ${testPattern}`);
|
|
6191
|
+
if (standards?.testing?.testLocation) {
|
|
6192
|
+
const testLocationText = standards.testing.testLocation === "colocated" ? "Co-located with source" : "Separate test directory";
|
|
6193
|
+
lines.push(`- Test location: ${testLocationText}`);
|
|
6194
|
+
}
|
|
6195
|
+
lines.push("");
|
|
6196
|
+
lines.push("### Git Workflow");
|
|
6197
|
+
lines.push("");
|
|
6198
|
+
lines.push("- Use conventional commits: `type(scope): description`");
|
|
6199
|
+
lines.push("- Types: feat, fix, docs, style, refactor, test, chore");
|
|
6200
|
+
lines.push("- Keep commits atomic and focused");
|
|
6201
|
+
if (preferences?.includeCoAuthor) {
|
|
6202
|
+
lines.push("");
|
|
6203
|
+
lines.push("#### Commit Attribution");
|
|
6204
|
+
lines.push("");
|
|
6205
|
+
lines.push("Include the following in commit messages:");
|
|
6206
|
+
lines.push("```");
|
|
6207
|
+
lines.push("\u{1F916} Generated with [Claude Code](https://claude.com/claude-code)");
|
|
6208
|
+
lines.push("");
|
|
6209
|
+
lines.push("Co-Authored-By: Claude <noreply@anthropic.com>");
|
|
6210
|
+
lines.push("```");
|
|
6167
6211
|
}
|
|
6168
|
-
|
|
6169
|
-
|
|
6212
|
+
lines.push("");
|
|
6213
|
+
lines.push("## Claude Behavior Guidelines");
|
|
6214
|
+
lines.push("");
|
|
6215
|
+
lines.push("### Critical Thinking");
|
|
6216
|
+
lines.push("");
|
|
6217
|
+
lines.push("- You are an expert who double-checks things, you are skeptical and do research");
|
|
6218
|
+
lines.push("- Neither the user nor you are always right, but both strive for accuracy");
|
|
6219
|
+
lines.push("- When the user asks something, reason with these questions:");
|
|
6220
|
+
lines.push(' - "Why might the user be wrong?"');
|
|
6221
|
+
lines.push(' - "What arguments exist against what the user thinks?"');
|
|
6222
|
+
lines.push(` - "Act as devil's advocate - why might this proposal fail?"`);
|
|
6223
|
+
lines.push(` - "Imagine you're in a debate - how would you refute this?"`);
|
|
6224
|
+
lines.push(
|
|
6225
|
+
"- Always ask to better understand the context of the requested change before implementing"
|
|
6226
|
+
);
|
|
6227
|
+
lines.push("");
|
|
6228
|
+
lines.push("### Communication Style");
|
|
6229
|
+
lines.push("");
|
|
6230
|
+
if (preferences?.responseLanguage) {
|
|
6231
|
+
const langDisplay = preferences.responseLanguage === "es" ? "Spanish" : preferences.responseLanguage === "en" ? "English" : preferences.responseLanguage;
|
|
6232
|
+
lines.push(`- Respond in ${langDisplay}`);
|
|
6233
|
+
}
|
|
6234
|
+
lines.push("- Code and comments should always be in English");
|
|
6235
|
+
lines.push("- Be direct and concise");
|
|
6236
|
+
lines.push('- Explain the "why" behind decisions when relevant');
|
|
6237
|
+
lines.push("");
|
|
6238
|
+
lines.push("### Writing Style");
|
|
6239
|
+
lines.push("");
|
|
6240
|
+
lines.push(
|
|
6241
|
+
'- Systematically replace em-dashes ("\u2014") with a period (".") to start a new sentence, or a comma (",") to continue the sentence'
|
|
6242
|
+
);
|
|
6243
|
+
lines.push("- Avoid unnecessary filler words");
|
|
6244
|
+
lines.push("- Use clear, technical language");
|
|
6245
|
+
lines.push("");
|
|
6246
|
+
lines.push("## Claude Configuration");
|
|
6247
|
+
lines.push("");
|
|
6248
|
+
lines.push("This project uses `@qazuor/claude-code-config` for AI-assisted development.");
|
|
6249
|
+
lines.push("");
|
|
6250
|
+
lines.push("### Available Commands");
|
|
6251
|
+
lines.push("");
|
|
6252
|
+
lines.push("Run `/help` in Claude to see all available commands.");
|
|
6253
|
+
lines.push("");
|
|
6254
|
+
lines.push("### Documentation");
|
|
6255
|
+
lines.push("");
|
|
6256
|
+
lines.push("- Quick Start: `.claude/docs/quick-start.md`");
|
|
6257
|
+
lines.push("- Workflows: `.claude/docs/workflows/README.md`");
|
|
6258
|
+
lines.push("- Standards: `.claude/docs/standards/`");
|
|
6259
|
+
lines.push("");
|
|
6260
|
+
lines.push("---");
|
|
6261
|
+
lines.push("");
|
|
6262
|
+
lines.push(
|
|
6263
|
+
"*Generated by [@qazuor/claude-code-config](https://github.com/qazuor/claude-code-config)*"
|
|
6264
|
+
);
|
|
6265
|
+
lines.push("");
|
|
6266
|
+
return lines.join("\n");
|
|
6170
6267
|
}
|
|
6171
6268
|
function generateTechStackSection(techStack) {
|
|
6269
|
+
if (!techStack) {
|
|
6270
|
+
return getDefaultTechStack();
|
|
6271
|
+
}
|
|
6172
6272
|
const lines = [];
|
|
6273
|
+
let hasContent = false;
|
|
6173
6274
|
if (techStack.frontendFramework && techStack.frontendFramework !== "None") {
|
|
6174
6275
|
lines.push("**Frontend:**");
|
|
6175
6276
|
lines.push(`- Framework: ${techStack.frontendFramework}`);
|
|
@@ -6177,6 +6278,7 @@ function generateTechStackSection(techStack) {
|
|
|
6177
6278
|
lines.push(`- State: ${techStack.stateManagement}`);
|
|
6178
6279
|
}
|
|
6179
6280
|
lines.push("");
|
|
6281
|
+
hasContent = true;
|
|
6180
6282
|
}
|
|
6181
6283
|
if (techStack.apiFramework && techStack.apiFramework !== "None") {
|
|
6182
6284
|
lines.push("**Backend:**");
|
|
@@ -6185,145 +6287,89 @@ function generateTechStackSection(techStack) {
|
|
|
6185
6287
|
lines.push(`- Validation: ${techStack.validationLibrary}`);
|
|
6186
6288
|
}
|
|
6187
6289
|
lines.push("");
|
|
6290
|
+
hasContent = true;
|
|
6188
6291
|
}
|
|
6189
6292
|
if (techStack.databaseOrm && techStack.databaseOrm !== "None") {
|
|
6190
6293
|
lines.push("**Database:**");
|
|
6191
6294
|
lines.push(`- ORM: ${techStack.databaseOrm}`);
|
|
6192
6295
|
lines.push("");
|
|
6296
|
+
hasContent = true;
|
|
6193
6297
|
}
|
|
6194
6298
|
if (techStack.authPattern && techStack.authPattern !== "None") {
|
|
6195
6299
|
lines.push("**Authentication:**");
|
|
6196
6300
|
lines.push(`- Provider: ${techStack.authPattern}`);
|
|
6197
6301
|
lines.push("");
|
|
6302
|
+
hasContent = true;
|
|
6198
6303
|
}
|
|
6199
6304
|
if (techStack.testFramework && techStack.testFramework !== "None") {
|
|
6200
6305
|
lines.push("**Testing:**");
|
|
6201
6306
|
lines.push(`- Framework: ${techStack.testFramework}`);
|
|
6202
6307
|
lines.push("");
|
|
6308
|
+
hasContent = true;
|
|
6203
6309
|
}
|
|
6204
6310
|
if (techStack.bundler && techStack.bundler !== "None") {
|
|
6205
6311
|
lines.push("**Build:**");
|
|
6206
6312
|
lines.push(`- Bundler: ${techStack.bundler}`);
|
|
6207
6313
|
lines.push("");
|
|
6314
|
+
hasContent = true;
|
|
6315
|
+
}
|
|
6316
|
+
if (!hasContent) {
|
|
6317
|
+
return getDefaultTechStack();
|
|
6208
6318
|
}
|
|
6209
6319
|
return lines.join("\n");
|
|
6210
6320
|
}
|
|
6211
|
-
function
|
|
6321
|
+
function getDefaultTechStack() {
|
|
6322
|
+
return `**Frontend:**
|
|
6323
|
+
- Framework: Not configured
|
|
6324
|
+
|
|
6325
|
+
**Backend:**
|
|
6326
|
+
- API: Not configured
|
|
6327
|
+
|
|
6328
|
+
**Database:**
|
|
6329
|
+
- ORM: Not configured
|
|
6330
|
+
|
|
6331
|
+
**Testing:**
|
|
6332
|
+
- Framework: Not configured
|
|
6333
|
+
|
|
6334
|
+
`;
|
|
6335
|
+
}
|
|
6336
|
+
function generateCommandsSection(commands, packageManager = "pnpm") {
|
|
6212
6337
|
const lines = ["```bash"];
|
|
6213
6338
|
lines.push("# Development");
|
|
6214
6339
|
lines.push(`${packageManager} dev # Start development server`);
|
|
6215
6340
|
lines.push("");
|
|
6216
6341
|
lines.push("# Testing");
|
|
6217
|
-
if (commands
|
|
6342
|
+
if (commands?.test) {
|
|
6218
6343
|
lines.push(`${commands.test} # Run tests`);
|
|
6219
6344
|
} else {
|
|
6220
6345
|
lines.push(`${packageManager} test # Run tests`);
|
|
6221
6346
|
}
|
|
6222
|
-
if (commands
|
|
6347
|
+
if (commands?.coverage) {
|
|
6223
6348
|
lines.push(`${commands.coverage} # Run tests with coverage`);
|
|
6224
6349
|
} else {
|
|
6225
6350
|
lines.push(`${packageManager} test:coverage # Run tests with coverage`);
|
|
6226
6351
|
}
|
|
6227
6352
|
lines.push("");
|
|
6228
6353
|
lines.push("# Quality");
|
|
6229
|
-
if (commands
|
|
6354
|
+
if (commands?.lint) {
|
|
6230
6355
|
lines.push(`${commands.lint} # Run linter`);
|
|
6231
6356
|
} else {
|
|
6232
6357
|
lines.push(`${packageManager} lint # Run linter`);
|
|
6233
6358
|
}
|
|
6234
|
-
if (commands
|
|
6359
|
+
if (commands?.typecheck) {
|
|
6235
6360
|
lines.push(`${commands.typecheck} # Type checking`);
|
|
6236
6361
|
} else {
|
|
6237
6362
|
lines.push(`${packageManager} typecheck # Type checking`);
|
|
6238
6363
|
}
|
|
6239
|
-
if (commands
|
|
6364
|
+
if (commands?.build) {
|
|
6240
6365
|
lines.push("");
|
|
6241
6366
|
lines.push("# Build");
|
|
6242
6367
|
lines.push(`${commands.build} # Build for production`);
|
|
6243
6368
|
}
|
|
6244
6369
|
lines.push("```");
|
|
6370
|
+
lines.push("");
|
|
6245
6371
|
return lines.join("\n");
|
|
6246
6372
|
}
|
|
6247
|
-
function processStandardsPlaceholders(content, standards, preferences) {
|
|
6248
|
-
let result = content;
|
|
6249
|
-
const primaryLanguage = "TypeScript";
|
|
6250
|
-
result = result.replace(/\{\{PRIMARY_LANGUAGE\}\}/g, primaryLanguage);
|
|
6251
|
-
const maxFileLines = standards?.code?.maxFileLines?.toString() || "500";
|
|
6252
|
-
result = result.replace(/\{\{MAX_FILE_LINES\}\}/g, maxFileLines);
|
|
6253
|
-
const testPattern = standards?.testing?.testPattern === "gwt" ? "GWT (Given-When-Then)" : "AAA (Arrange, Act, Assert)";
|
|
6254
|
-
result = result.replace(/\{\{TEST_PATTERN\}\}/g, testPattern);
|
|
6255
|
-
const responseLanguage = preferences?.responseLanguage === "es" ? "Spanish" : preferences?.responseLanguage === "en" ? "English" : "Spanish";
|
|
6256
|
-
result = result.replace(/\{\{RESPONSE_LANGUAGE\}\}/g, responseLanguage);
|
|
6257
|
-
if (standards?.code?.namedExportsOnly) {
|
|
6258
|
-
result = result.replace(/\{\{#if NAMED_EXPORTS_ONLY\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
|
|
6259
|
-
} else {
|
|
6260
|
-
result = result.replace(/\{\{#if NAMED_EXPORTS_ONLY\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6261
|
-
}
|
|
6262
|
-
if (standards?.code?.jsDocRequired) {
|
|
6263
|
-
result = result.replace(/\{\{#if JSDOC_REQUIRED\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
|
|
6264
|
-
} else {
|
|
6265
|
-
result = result.replace(/\{\{#if JSDOC_REQUIRED\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6266
|
-
}
|
|
6267
|
-
if (standards?.code?.roroPattern) {
|
|
6268
|
-
result = result.replace(/\{\{#if RORO_PATTERN\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
|
|
6269
|
-
} else {
|
|
6270
|
-
result = result.replace(/\{\{#if RORO_PATTERN\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6271
|
-
}
|
|
6272
|
-
if (standards?.testing?.tddRequired) {
|
|
6273
|
-
result = result.replace(/\{\{#if TDD_REQUIRED\}\}/g, "").replace(/\{\{else\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6274
|
-
} else {
|
|
6275
|
-
result = result.replace(/\{\{#if TDD_REQUIRED\}\}[\s\S]*?\{\{else\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
|
|
6276
|
-
}
|
|
6277
|
-
const testLocation = standards?.testing?.testLocation;
|
|
6278
|
-
if (testLocation) {
|
|
6279
|
-
const testLocationText = testLocation === "colocated" ? "Co-located with source" : "Separate test directory";
|
|
6280
|
-
result = result.replace(/\{\{#if TEST_LOCATION\}\}/g, "").replace(/\{\{\/if\}\}/g, "").replace(/\{\{TEST_LOCATION\}\}/g, testLocationText);
|
|
6281
|
-
} else {
|
|
6282
|
-
result = result.replace(/\{\{#if TEST_LOCATION\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6283
|
-
}
|
|
6284
|
-
if (preferences?.includeCoAuthor) {
|
|
6285
|
-
result = result.replace(/\{\{#if INCLUDE_CO_AUTHOR\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
|
|
6286
|
-
} else {
|
|
6287
|
-
result = result.replace(/\{\{#if INCLUDE_CO_AUTHOR\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6288
|
-
}
|
|
6289
|
-
if (preferences?.responseLanguage) {
|
|
6290
|
-
result = result.replace(/\{\{#if RESPONSE_LANGUAGE\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
|
|
6291
|
-
} else {
|
|
6292
|
-
result = result.replace(/\{\{#if RESPONSE_LANGUAGE\}\}[\s\S]*?\{\{\/if\}\}/g, "");
|
|
6293
|
-
}
|
|
6294
|
-
return result;
|
|
6295
|
-
}
|
|
6296
|
-
function getMinimalTemplate() {
|
|
6297
|
-
return `# CLAUDE.md
|
|
6298
|
-
|
|
6299
|
-
## Project Overview
|
|
6300
|
-
|
|
6301
|
-
**{{PROJECT_NAME}}** - {{PROJECT_DESCRIPTION}}
|
|
6302
|
-
|
|
6303
|
-
## Repository
|
|
6304
|
-
|
|
6305
|
-
- **GitHub:** https://github.com/{{ORG}}/{{REPO}}
|
|
6306
|
-
|
|
6307
|
-
## Quick Commands
|
|
6308
|
-
|
|
6309
|
-
\`\`\`bash
|
|
6310
|
-
{{PACKAGE_MANAGER}} dev # Start development
|
|
6311
|
-
{{PACKAGE_MANAGER}} test # Run tests
|
|
6312
|
-
{{PACKAGE_MANAGER}} lint # Run linter
|
|
6313
|
-
{{PACKAGE_MANAGER}} build # Build project
|
|
6314
|
-
\`\`\`
|
|
6315
|
-
|
|
6316
|
-
## Claude Configuration
|
|
6317
|
-
|
|
6318
|
-
This project uses \`@qazuor/claude-code-config\` for AI-assisted development.
|
|
6319
|
-
|
|
6320
|
-
See \`.claude/docs/quick-start.md\` for getting started.
|
|
6321
|
-
|
|
6322
|
-
---
|
|
6323
|
-
|
|
6324
|
-
*Generated by [@qazuor/claude-code-config](https://github.com/qazuor/claude-code-config)*
|
|
6325
|
-
`;
|
|
6326
|
-
}
|
|
6327
6373
|
|
|
6328
6374
|
// src/lib/scaffold/index.ts
|
|
6329
6375
|
init_cjs_shims();
|
|
@@ -7076,8 +7122,8 @@ function buildSettingsLocalJson(options) {
|
|
|
7076
7122
|
|
|
7077
7123
|
// src/lib/templates/config-replacer.ts
|
|
7078
7124
|
init_cjs_shims();
|
|
7079
|
-
var
|
|
7080
|
-
var
|
|
7125
|
+
var fs3 = __toESM(require("fs/promises"), 1);
|
|
7126
|
+
var path4 = __toESM(require("path"), 1);
|
|
7081
7127
|
var import_ora2 = __toESM(require("ora"), 1);
|
|
7082
7128
|
|
|
7083
7129
|
// src/constants/template-placeholders.ts
|
|
@@ -7985,7 +8031,7 @@ function flattenTemplateConfig(config) {
|
|
|
7985
8031
|
return flattened;
|
|
7986
8032
|
}
|
|
7987
8033
|
function shouldProcessFile(filePath) {
|
|
7988
|
-
const ext =
|
|
8034
|
+
const ext = path4.extname(filePath).toLowerCase();
|
|
7989
8035
|
return PROCESSABLE_EXTENSIONS.includes(ext);
|
|
7990
8036
|
}
|
|
7991
8037
|
function shouldSkipDirectory(dirName) {
|
|
@@ -7994,9 +8040,9 @@ function shouldSkipDirectory(dirName) {
|
|
|
7994
8040
|
async function getAllFiles(dir) {
|
|
7995
8041
|
const files = [];
|
|
7996
8042
|
try {
|
|
7997
|
-
const entries = await
|
|
8043
|
+
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
7998
8044
|
for (const entry of entries) {
|
|
7999
|
-
const fullPath =
|
|
8045
|
+
const fullPath = path4.join(dir, entry.name);
|
|
8000
8046
|
if (entry.isDirectory()) {
|
|
8001
8047
|
if (!shouldSkipDirectory(entry.name)) {
|
|
8002
8048
|
const subFiles = await getAllFiles(fullPath);
|
|
@@ -8013,7 +8059,7 @@ async function getAllFiles(dir) {
|
|
|
8013
8059
|
async function replaceInFile2(filePath, replacements) {
|
|
8014
8060
|
const changes = [];
|
|
8015
8061
|
try {
|
|
8016
|
-
let content = await
|
|
8062
|
+
let content = await fs3.readFile(filePath, "utf-8");
|
|
8017
8063
|
let modified = false;
|
|
8018
8064
|
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
8019
8065
|
if (content.includes(placeholder)) {
|
|
@@ -8023,7 +8069,7 @@ async function replaceInFile2(filePath, replacements) {
|
|
|
8023
8069
|
}
|
|
8024
8070
|
}
|
|
8025
8071
|
if (modified) {
|
|
8026
|
-
await
|
|
8072
|
+
await fs3.writeFile(filePath, content, "utf-8");
|
|
8027
8073
|
}
|
|
8028
8074
|
} catch {
|
|
8029
8075
|
}
|
|
@@ -8044,7 +8090,7 @@ async function replaceTemplatePlaceholders(dir, config) {
|
|
|
8044
8090
|
report.filesModified++;
|
|
8045
8091
|
for (const change of changes) {
|
|
8046
8092
|
report.replacements.push({
|
|
8047
|
-
file:
|
|
8093
|
+
file: path4.relative(dir, file),
|
|
8048
8094
|
placeholder: change.placeholder,
|
|
8049
8095
|
value: change.value
|
|
8050
8096
|
});
|
|
@@ -8115,11 +8161,11 @@ async function previewReplacements(dir, config) {
|
|
|
8115
8161
|
const preview = [];
|
|
8116
8162
|
for (const file of files) {
|
|
8117
8163
|
try {
|
|
8118
|
-
const content = await
|
|
8164
|
+
const content = await fs3.readFile(file, "utf-8");
|
|
8119
8165
|
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
8120
8166
|
if (content.includes(placeholder)) {
|
|
8121
8167
|
preview.push({
|
|
8122
|
-
file:
|
|
8168
|
+
file: path4.relative(dir, file),
|
|
8123
8169
|
placeholder,
|
|
8124
8170
|
value
|
|
8125
8171
|
});
|
|
@@ -8134,6 +8180,27 @@ async function previewReplacements(dir, config) {
|
|
|
8134
8180
|
// src/cli/commands/init.ts
|
|
8135
8181
|
init_fs();
|
|
8136
8182
|
|
|
8183
|
+
// src/lib/utils/paths.ts
|
|
8184
|
+
init_cjs_shims();
|
|
8185
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
8186
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
8187
|
+
var import_node_url = require("url");
|
|
8188
|
+
function getPackageRoot() {
|
|
8189
|
+
const currentFilePath = (0, import_node_url.fileURLToPath)(importMetaUrl);
|
|
8190
|
+
let currentDir = import_node_path3.default.dirname(currentFilePath);
|
|
8191
|
+
while (currentDir !== import_node_path3.default.dirname(currentDir)) {
|
|
8192
|
+
const packageJsonPath = import_node_path3.default.join(currentDir, "package.json");
|
|
8193
|
+
if (import_node_fs.default.existsSync(packageJsonPath)) {
|
|
8194
|
+
return currentDir;
|
|
8195
|
+
}
|
|
8196
|
+
currentDir = import_node_path3.default.dirname(currentDir);
|
|
8197
|
+
}
|
|
8198
|
+
throw new Error("Could not find package root (no package.json found in parent directories)");
|
|
8199
|
+
}
|
|
8200
|
+
function getTemplatesPath() {
|
|
8201
|
+
return import_node_path3.default.join(getPackageRoot(), "templates");
|
|
8202
|
+
}
|
|
8203
|
+
|
|
8137
8204
|
// src/lib/utils/prompt-cancel.ts
|
|
8138
8205
|
init_cjs_shims();
|
|
8139
8206
|
var readline = __toESM(require("readline"), 1);
|
|
@@ -10664,6 +10731,61 @@ async function promptMcpConfig(options) {
|
|
|
10664
10731
|
const installedServers = await getInstalledMcpServers(projectPath);
|
|
10665
10732
|
const userInstalledSet = new Set(installedServers.user);
|
|
10666
10733
|
const projectInstalledSet = new Set(installedServers.project);
|
|
10734
|
+
const availableServers = MCP_SERVERS.filter(
|
|
10735
|
+
(s) => !userInstalledSet.has(s.id) && !projectInstalledSet.has(s.id)
|
|
10736
|
+
);
|
|
10737
|
+
if (availableServers.length === 0) {
|
|
10738
|
+
logger.newline();
|
|
10739
|
+
logger.success("All MCP servers are already installed!");
|
|
10740
|
+
const parts = [];
|
|
10741
|
+
if (userInstalledSet.size > 0) {
|
|
10742
|
+
parts.push(`${userInstalledSet.size} at user level`);
|
|
10743
|
+
}
|
|
10744
|
+
if (projectInstalledSet.size > 0) {
|
|
10745
|
+
parts.push(`${projectInstalledSet.size} at project level`);
|
|
10746
|
+
}
|
|
10747
|
+
logger.info(colors.muted(` (${parts.join(", ")})`));
|
|
10748
|
+
logger.newline();
|
|
10749
|
+
const wantCustom2 = await confirm({
|
|
10750
|
+
message: "Do you want to add a custom MCP server?",
|
|
10751
|
+
default: false
|
|
10752
|
+
});
|
|
10753
|
+
if (wantCustom2) {
|
|
10754
|
+
const level2 = await select({
|
|
10755
|
+
message: "Where should the custom server be configured?",
|
|
10756
|
+
choices: [
|
|
10757
|
+
{
|
|
10758
|
+
name: "Project level (.claude/settings.local.json)",
|
|
10759
|
+
value: "project",
|
|
10760
|
+
description: "Specific to this project"
|
|
10761
|
+
},
|
|
10762
|
+
{
|
|
10763
|
+
name: "User level (~/.claude/settings.json)",
|
|
10764
|
+
value: "user",
|
|
10765
|
+
description: "Available in all projects"
|
|
10766
|
+
}
|
|
10767
|
+
],
|
|
10768
|
+
default: options?.defaults?.level || "project"
|
|
10769
|
+
});
|
|
10770
|
+
const customInstallation = await promptCustomServer(level2);
|
|
10771
|
+
if (customInstallation) {
|
|
10772
|
+
return {
|
|
10773
|
+
config: {
|
|
10774
|
+
level: level2,
|
|
10775
|
+
servers: [customInstallation]
|
|
10776
|
+
},
|
|
10777
|
+
skippedConfigs: []
|
|
10778
|
+
};
|
|
10779
|
+
}
|
|
10780
|
+
}
|
|
10781
|
+
return {
|
|
10782
|
+
config: {
|
|
10783
|
+
level: "project",
|
|
10784
|
+
servers: []
|
|
10785
|
+
},
|
|
10786
|
+
skippedConfigs: []
|
|
10787
|
+
};
|
|
10788
|
+
}
|
|
10667
10789
|
const level = await select({
|
|
10668
10790
|
message: "Where should MCP servers be configured?",
|
|
10669
10791
|
choices: [
|
|
@@ -10697,37 +10819,18 @@ async function promptMcpConfig(options) {
|
|
|
10697
10819
|
}
|
|
10698
10820
|
logger.newline();
|
|
10699
10821
|
for (const [category, servers] of Object.entries(serversByCategory)) {
|
|
10700
|
-
const
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
return {
|
|
10705
|
-
name: `${s.name} - ${s.description} ${colors.muted("(already installed at user level)")}`,
|
|
10706
|
-
value: s.id,
|
|
10707
|
-
checked: false,
|
|
10708
|
-
disabled: "already installed at user level"
|
|
10709
|
-
};
|
|
10710
|
-
}
|
|
10711
|
-
if (isInstalledAtProjectLevel) {
|
|
10712
|
-
return {
|
|
10713
|
-
name: `${s.name} - ${s.description} ${colors.muted("(already installed at project level)")}`,
|
|
10714
|
-
value: s.id,
|
|
10715
|
-
checked: false,
|
|
10716
|
-
disabled: "already installed at project level"
|
|
10717
|
-
};
|
|
10718
|
-
}
|
|
10719
|
-
return {
|
|
10720
|
-
name: `${s.name} - ${s.description}`,
|
|
10721
|
-
value: s.id,
|
|
10722
|
-
checked: options?.defaults?.servers?.some((i) => i.serverId === s.id) ?? false
|
|
10723
|
-
};
|
|
10724
|
-
});
|
|
10725
|
-
const hasEnabledChoices = choices.some((choice) => !choice.disabled);
|
|
10726
|
-
const categoryLabel = formatCategory(category);
|
|
10727
|
-
if (!hasEnabledChoices) {
|
|
10728
|
-
logger.info(colors.muted(`${categoryLabel}: All servers already installed`));
|
|
10822
|
+
const availableInCategory = servers.filter(
|
|
10823
|
+
(s) => !userInstalledSet.has(s.id) && !projectInstalledSet.has(s.id)
|
|
10824
|
+
);
|
|
10825
|
+
if (availableInCategory.length === 0) {
|
|
10729
10826
|
continue;
|
|
10730
10827
|
}
|
|
10828
|
+
const choices = availableInCategory.map((s) => ({
|
|
10829
|
+
name: `${s.name} - ${s.description}`,
|
|
10830
|
+
value: s.id,
|
|
10831
|
+
checked: options?.defaults?.servers?.some((i) => i.serverId === s.id) ?? false
|
|
10832
|
+
}));
|
|
10833
|
+
const categoryLabel = formatCategory(category);
|
|
10731
10834
|
const selected = await checkbox({
|
|
10732
10835
|
message: `${categoryLabel}:`,
|
|
10733
10836
|
choices
|