@qazuor/claude-code-config 0.6.1 → 0.6.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/dist/bin.js CHANGED
@@ -6042,29 +6042,6 @@ function showReplacementReport(report) {
6042
6042
  // src/lib/scaffold/claude-md-generator.ts
6043
6043
  init_esm_shims();
6044
6044
  init_fs();
6045
-
6046
- // src/lib/utils/paths.ts
6047
- init_esm_shims();
6048
- import fs3 from "fs";
6049
- import path5 from "path";
6050
- import { fileURLToPath as fileURLToPath2 } from "url";
6051
- function getPackageRoot() {
6052
- const currentFilePath = fileURLToPath2(import.meta.url);
6053
- let currentDir = path5.dirname(currentFilePath);
6054
- while (currentDir !== path5.dirname(currentDir)) {
6055
- const packageJsonPath = path5.join(currentDir, "package.json");
6056
- if (fs3.existsSync(packageJsonPath)) {
6057
- return currentDir;
6058
- }
6059
- currentDir = path5.dirname(currentDir);
6060
- }
6061
- throw new Error("Could not find package root (no package.json found in parent directories)");
6062
- }
6063
- function getTemplatesPath() {
6064
- return path5.join(getPackageRoot(), "templates");
6065
- }
6066
-
6067
- // src/lib/scaffold/claude-md-generator.ts
6068
6045
  async function generateClaudeMd(projectPath, projectInfo, options) {
6069
6046
  const claudeMdPath = joinPath(projectPath, "CLAUDE.md");
6070
6047
  const exists = await pathExists(claudeMdPath);
@@ -6076,18 +6053,12 @@ async function generateClaudeMd(projectPath, projectInfo, options) {
6076
6053
  };
6077
6054
  }
6078
6055
  try {
6079
- let template;
6056
+ let content;
6080
6057
  if (options?.customTemplate) {
6081
- template = options.customTemplate;
6058
+ content = processCustomTemplate(options.customTemplate, projectInfo);
6082
6059
  } else {
6083
- const templatePath = joinPath(getTemplatesPath(), "CLAUDE.md.template");
6084
- if (await pathExists(templatePath)) {
6085
- template = await readFile(templatePath);
6086
- } else {
6087
- template = getMinimalTemplate();
6088
- }
6060
+ content = generateClaudeMdContent(projectInfo, options);
6089
6061
  }
6090
- const content = processTemplate(template, projectInfo, options);
6091
6062
  await writeFile(claudeMdPath, content);
6092
6063
  return {
6093
6064
  created: true,
@@ -6112,41 +6083,165 @@ async function generateClaudeMdWithSpinner(projectPath, projectInfo, options) {
6112
6083
  }
6113
6084
  );
6114
6085
  }
6115
- function processTemplate(template, projectInfo, options) {
6116
- let content = template;
6086
+ function processCustomTemplate(template, projectInfo) {
6087
+ 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 || "");
6088
+ }
6089
+ function generateClaudeMdContent(projectInfo, options) {
6117
6090
  const techStack = options?.templateConfig?.techStack;
6118
6091
  const commands = options?.templateConfig?.commands;
6119
6092
  const targets = options?.templateConfig?.targets;
6120
6093
  const preferences = options?.claudeConfig?.preferences;
6121
6094
  const standards = options?.claudeConfig?.extras?.standards;
6122
- 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 || "");
6123
6095
  const packageManager = preferences?.packageManager || "pnpm";
6124
- content = content.replace(/\{\{PACKAGE_MANAGER\}\}/g, packageManager);
6125
- const coverageTarget = standards?.testing?.coverageTarget ? String(standards.testing.coverageTarget) : targets && "coverage" in targets ? String(targets.coverage) : "90";
6126
- content = content.replace(/\{\{COVERAGE_TARGET\}\}/g, coverageTarget);
6127
- content = processStandardsPlaceholders(content, standards, preferences);
6096
+ const lines = [];
6097
+ lines.push("# CLAUDE.md");
6098
+ lines.push("");
6099
+ lines.push("## Project Overview");
6100
+ lines.push("");
6101
+ lines.push(`**${projectInfo.name}** - ${projectInfo.description}`);
6102
+ lines.push("");
6103
+ lines.push("## Repository");
6104
+ lines.push("");
6105
+ lines.push(`- **Organization:** ${projectInfo.org}`);
6106
+ lines.push(`- **Repository:** ${projectInfo.repo}`);
6107
+ lines.push(`- **GitHub:** https://github.com/${projectInfo.org}/${projectInfo.repo}`);
6128
6108
  if (projectInfo.domain) {
6129
- content = content.replace(/\{\{#if DOMAIN\}\}/g, "").replace(/\{\{\/if\}\}/g, "").replace(/\{\{DOMAIN\}\}/g, projectInfo.domain);
6130
- } else {
6131
- content = content.replace(/\{\{#if DOMAIN\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6109
+ lines.push(`- **Domain:** ${projectInfo.domain}`);
6132
6110
  }
6133
- if (techStack && Object.keys(techStack).length > 0) {
6134
- const techStackContent = generateTechStackSection(techStack);
6135
- content = content.replace(/\{\{#if TECH_STACK\}\}/g, "").replace(/\{\{TECH_STACK\}\}\n\{\{else\}\}[\s\S]*?\{\{\/if\}\}/g, techStackContent);
6136
- } else {
6137
- content = content.replace(/\{\{#if TECH_STACK\}\}[\s\S]*?\{\{else\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6111
+ lines.push("");
6112
+ lines.push("## Tech Stack");
6113
+ lines.push("");
6114
+ lines.push(generateTechStackSection(techStack));
6115
+ lines.push("## Project Structure");
6116
+ lines.push("");
6117
+ lines.push("```text");
6118
+ lines.push(`${projectInfo.name}/`);
6119
+ lines.push("\u251C\u2500\u2500 src/ # Source code");
6120
+ lines.push("\u251C\u2500\u2500 tests/ # Test files");
6121
+ lines.push("\u251C\u2500\u2500 docs/ # Documentation");
6122
+ lines.push("\u2514\u2500\u2500 .claude/ # Claude configuration");
6123
+ lines.push(" \u251C\u2500\u2500 agents/ # AI agent definitions");
6124
+ lines.push(" \u251C\u2500\u2500 commands/ # Custom slash commands");
6125
+ lines.push(" \u251C\u2500\u2500 skills/ # Specialized skills");
6126
+ lines.push(" \u2514\u2500\u2500 docs/ # AI-specific documentation");
6127
+ lines.push("```");
6128
+ lines.push("");
6129
+ lines.push("## Quick Commands");
6130
+ lines.push("");
6131
+ lines.push(generateCommandsSection(commands, packageManager));
6132
+ lines.push("## Development Guidelines");
6133
+ lines.push("");
6134
+ lines.push("### Code Standards");
6135
+ lines.push("");
6136
+ lines.push("- Primary language: TypeScript");
6137
+ lines.push("- Follow TypeScript best practices");
6138
+ if (standards?.code?.namedExportsOnly) {
6139
+ lines.push("- Use named exports only (no default exports)");
6140
+ }
6141
+ const maxLines = standards?.code?.maxFileLines || 500;
6142
+ lines.push(`- Maximum ${maxLines} lines per file`);
6143
+ if (standards?.code?.jsDocRequired) {
6144
+ lines.push("- Document all exports with JSDoc");
6138
6145
  }
6139
- if (commands && Object.keys(commands).length > 0) {
6140
- const commandsContent = generateCommandsSection(commands, packageManager);
6141
- content = content.replace(/\{\{#if COMMANDS\}\}/g, "").replace(/\{\{COMMANDS\}\}\n\{\{else\}\}[\s\S]*?\{\{\/if\}\}/g, commandsContent);
6146
+ if (standards?.code?.roroPattern) {
6147
+ lines.push("- Use RO-RO pattern (Receive Object, Return Object)");
6148
+ }
6149
+ lines.push("");
6150
+ lines.push("### Testing");
6151
+ lines.push("");
6152
+ if (standards?.testing?.tddRequired) {
6153
+ lines.push("- Methodology: TDD (Test-Driven Development)");
6154
+ lines.push("- Write tests first: Red -> Green -> Refactor");
6142
6155
  } else {
6143
- content = content.replace(/\{\{#if COMMANDS\}\}[\s\S]*?\{\{else\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6156
+ lines.push("- Write comprehensive tests for all features");
6144
6157
  }
6145
- content = content.replace(/\{\{#if PROJECT_STRUCTURE\}\}[\s\S]*?\{\{else\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6146
- return content;
6158
+ const coverageTarget = standards?.testing?.coverageTarget || (targets && "coverage" in targets ? targets.coverage : 90);
6159
+ lines.push(`- Maintain ${coverageTarget}%+ code coverage`);
6160
+ const testPattern = standards?.testing?.testPattern === "gwt" ? "GWT (Given-When-Then)" : "AAA (Arrange, Act, Assert)";
6161
+ lines.push(`- Test pattern: ${testPattern}`);
6162
+ if (standards?.testing?.testLocation) {
6163
+ const testLocationText = standards.testing.testLocation === "colocated" ? "Co-located with source" : "Separate test directory";
6164
+ lines.push(`- Test location: ${testLocationText}`);
6165
+ }
6166
+ lines.push("");
6167
+ lines.push("### Git Workflow");
6168
+ lines.push("");
6169
+ lines.push("- Use conventional commits: `type(scope): description`");
6170
+ lines.push("- Types: feat, fix, docs, style, refactor, test, chore");
6171
+ lines.push("- Keep commits atomic and focused");
6172
+ if (preferences?.includeCoAuthor) {
6173
+ lines.push("");
6174
+ lines.push("#### Commit Attribution");
6175
+ lines.push("");
6176
+ lines.push("Include the following in commit messages:");
6177
+ lines.push("```");
6178
+ lines.push("\u{1F916} Generated with [Claude Code](https://claude.com/claude-code)");
6179
+ lines.push("");
6180
+ lines.push("Co-Authored-By: Claude <noreply@anthropic.com>");
6181
+ lines.push("```");
6182
+ }
6183
+ lines.push("");
6184
+ lines.push("## Claude Behavior Guidelines");
6185
+ lines.push("");
6186
+ lines.push("### Critical Thinking");
6187
+ lines.push("");
6188
+ lines.push("- You are an expert who double-checks things, you are skeptical and do research");
6189
+ lines.push("- Neither the user nor you are always right, but both strive for accuracy");
6190
+ lines.push("- When the user asks something, reason with these questions:");
6191
+ lines.push(' - "Why might the user be wrong?"');
6192
+ lines.push(' - "What arguments exist against what the user thinks?"');
6193
+ lines.push(` - "Act as devil's advocate - why might this proposal fail?"`);
6194
+ lines.push(` - "Imagine you're in a debate - how would you refute this?"`);
6195
+ lines.push(
6196
+ "- Always ask to better understand the context of the requested change before implementing"
6197
+ );
6198
+ lines.push("");
6199
+ lines.push("### Communication Style");
6200
+ lines.push("");
6201
+ if (preferences?.responseLanguage) {
6202
+ const langDisplay = preferences.responseLanguage === "es" ? "Spanish" : preferences.responseLanguage === "en" ? "English" : preferences.responseLanguage;
6203
+ lines.push(`- Respond in ${langDisplay}`);
6204
+ }
6205
+ lines.push("- Code and comments should always be in English");
6206
+ lines.push("- Be direct and concise");
6207
+ lines.push('- Explain the "why" behind decisions when relevant');
6208
+ lines.push("");
6209
+ lines.push("### Writing Style");
6210
+ lines.push("");
6211
+ lines.push(
6212
+ '- Systematically replace em-dashes ("\u2014") with a period (".") to start a new sentence, or a comma (",") to continue the sentence'
6213
+ );
6214
+ lines.push("- Avoid unnecessary filler words");
6215
+ lines.push("- Use clear, technical language");
6216
+ lines.push("");
6217
+ lines.push("## Claude Configuration");
6218
+ lines.push("");
6219
+ lines.push("This project uses `@qazuor/claude-code-config` for AI-assisted development.");
6220
+ lines.push("");
6221
+ lines.push("### Available Commands");
6222
+ lines.push("");
6223
+ lines.push("Run `/help` in Claude to see all available commands.");
6224
+ lines.push("");
6225
+ lines.push("### Documentation");
6226
+ lines.push("");
6227
+ lines.push("- Quick Start: `.claude/docs/quick-start.md`");
6228
+ lines.push("- Workflows: `.claude/docs/workflows/README.md`");
6229
+ lines.push("- Standards: `.claude/docs/standards/`");
6230
+ lines.push("");
6231
+ lines.push("---");
6232
+ lines.push("");
6233
+ lines.push(
6234
+ "*Generated by [@qazuor/claude-code-config](https://github.com/qazuor/claude-code-config)*"
6235
+ );
6236
+ lines.push("");
6237
+ return lines.join("\n");
6147
6238
  }
6148
6239
  function generateTechStackSection(techStack) {
6240
+ if (!techStack) {
6241
+ return getDefaultTechStack();
6242
+ }
6149
6243
  const lines = [];
6244
+ let hasContent = false;
6150
6245
  if (techStack.frontendFramework && techStack.frontendFramework !== "None") {
6151
6246
  lines.push("**Frontend:**");
6152
6247
  lines.push(`- Framework: ${techStack.frontendFramework}`);
@@ -6154,6 +6249,7 @@ function generateTechStackSection(techStack) {
6154
6249
  lines.push(`- State: ${techStack.stateManagement}`);
6155
6250
  }
6156
6251
  lines.push("");
6252
+ hasContent = true;
6157
6253
  }
6158
6254
  if (techStack.apiFramework && techStack.apiFramework !== "None") {
6159
6255
  lines.push("**Backend:**");
@@ -6162,145 +6258,89 @@ function generateTechStackSection(techStack) {
6162
6258
  lines.push(`- Validation: ${techStack.validationLibrary}`);
6163
6259
  }
6164
6260
  lines.push("");
6261
+ hasContent = true;
6165
6262
  }
6166
6263
  if (techStack.databaseOrm && techStack.databaseOrm !== "None") {
6167
6264
  lines.push("**Database:**");
6168
6265
  lines.push(`- ORM: ${techStack.databaseOrm}`);
6169
6266
  lines.push("");
6267
+ hasContent = true;
6170
6268
  }
6171
6269
  if (techStack.authPattern && techStack.authPattern !== "None") {
6172
6270
  lines.push("**Authentication:**");
6173
6271
  lines.push(`- Provider: ${techStack.authPattern}`);
6174
6272
  lines.push("");
6273
+ hasContent = true;
6175
6274
  }
6176
6275
  if (techStack.testFramework && techStack.testFramework !== "None") {
6177
6276
  lines.push("**Testing:**");
6178
6277
  lines.push(`- Framework: ${techStack.testFramework}`);
6179
6278
  lines.push("");
6279
+ hasContent = true;
6180
6280
  }
6181
6281
  if (techStack.bundler && techStack.bundler !== "None") {
6182
6282
  lines.push("**Build:**");
6183
6283
  lines.push(`- Bundler: ${techStack.bundler}`);
6184
6284
  lines.push("");
6285
+ hasContent = true;
6286
+ }
6287
+ if (!hasContent) {
6288
+ return getDefaultTechStack();
6185
6289
  }
6186
6290
  return lines.join("\n");
6187
6291
  }
6188
- function generateCommandsSection(commands, packageManager) {
6292
+ function getDefaultTechStack() {
6293
+ return `**Frontend:**
6294
+ - Framework: Not configured
6295
+
6296
+ **Backend:**
6297
+ - API: Not configured
6298
+
6299
+ **Database:**
6300
+ - ORM: Not configured
6301
+
6302
+ **Testing:**
6303
+ - Framework: Not configured
6304
+
6305
+ `;
6306
+ }
6307
+ function generateCommandsSection(commands, packageManager = "pnpm") {
6189
6308
  const lines = ["```bash"];
6190
6309
  lines.push("# Development");
6191
6310
  lines.push(`${packageManager} dev # Start development server`);
6192
6311
  lines.push("");
6193
6312
  lines.push("# Testing");
6194
- if (commands.test) {
6313
+ if (commands?.test) {
6195
6314
  lines.push(`${commands.test} # Run tests`);
6196
6315
  } else {
6197
6316
  lines.push(`${packageManager} test # Run tests`);
6198
6317
  }
6199
- if (commands.coverage) {
6318
+ if (commands?.coverage) {
6200
6319
  lines.push(`${commands.coverage} # Run tests with coverage`);
6201
6320
  } else {
6202
6321
  lines.push(`${packageManager} test:coverage # Run tests with coverage`);
6203
6322
  }
6204
6323
  lines.push("");
6205
6324
  lines.push("# Quality");
6206
- if (commands.lint) {
6325
+ if (commands?.lint) {
6207
6326
  lines.push(`${commands.lint} # Run linter`);
6208
6327
  } else {
6209
6328
  lines.push(`${packageManager} lint # Run linter`);
6210
6329
  }
6211
- if (commands.typecheck) {
6330
+ if (commands?.typecheck) {
6212
6331
  lines.push(`${commands.typecheck} # Type checking`);
6213
6332
  } else {
6214
6333
  lines.push(`${packageManager} typecheck # Type checking`);
6215
6334
  }
6216
- if (commands.build) {
6335
+ if (commands?.build) {
6217
6336
  lines.push("");
6218
6337
  lines.push("# Build");
6219
6338
  lines.push(`${commands.build} # Build for production`);
6220
6339
  }
6221
6340
  lines.push("```");
6341
+ lines.push("");
6222
6342
  return lines.join("\n");
6223
6343
  }
6224
- function processStandardsPlaceholders(content, standards, preferences) {
6225
- let result = content;
6226
- const primaryLanguage = "TypeScript";
6227
- result = result.replace(/\{\{PRIMARY_LANGUAGE\}\}/g, primaryLanguage);
6228
- const maxFileLines = standards?.code?.maxFileLines?.toString() || "500";
6229
- result = result.replace(/\{\{MAX_FILE_LINES\}\}/g, maxFileLines);
6230
- const testPattern = standards?.testing?.testPattern === "gwt" ? "GWT (Given-When-Then)" : "AAA (Arrange, Act, Assert)";
6231
- result = result.replace(/\{\{TEST_PATTERN\}\}/g, testPattern);
6232
- const responseLanguage = preferences?.responseLanguage === "es" ? "Spanish" : preferences?.responseLanguage === "en" ? "English" : "Spanish";
6233
- result = result.replace(/\{\{RESPONSE_LANGUAGE\}\}/g, responseLanguage);
6234
- if (standards?.code?.namedExportsOnly) {
6235
- result = result.replace(/\{\{#if NAMED_EXPORTS_ONLY\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6236
- } else {
6237
- result = result.replace(/\{\{#if NAMED_EXPORTS_ONLY\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6238
- }
6239
- if (standards?.code?.jsDocRequired) {
6240
- result = result.replace(/\{\{#if JSDOC_REQUIRED\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6241
- } else {
6242
- result = result.replace(/\{\{#if JSDOC_REQUIRED\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6243
- }
6244
- if (standards?.code?.roroPattern) {
6245
- result = result.replace(/\{\{#if RORO_PATTERN\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6246
- } else {
6247
- result = result.replace(/\{\{#if RORO_PATTERN\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6248
- }
6249
- if (standards?.testing?.tddRequired) {
6250
- result = result.replace(/\{\{#if TDD_REQUIRED\}\}/g, "").replace(/\{\{else\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6251
- } else {
6252
- result = result.replace(/\{\{#if TDD_REQUIRED\}\}[\s\S]*?\{\{else\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6253
- }
6254
- const testLocation = standards?.testing?.testLocation;
6255
- if (testLocation) {
6256
- const testLocationText = testLocation === "colocated" ? "Co-located with source" : "Separate test directory";
6257
- result = result.replace(/\{\{#if TEST_LOCATION\}\}/g, "").replace(/\{\{\/if\}\}/g, "").replace(/\{\{TEST_LOCATION\}\}/g, testLocationText);
6258
- } else {
6259
- result = result.replace(/\{\{#if TEST_LOCATION\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6260
- }
6261
- if (preferences?.includeCoAuthor) {
6262
- result = result.replace(/\{\{#if INCLUDE_CO_AUTHOR\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6263
- } else {
6264
- result = result.replace(/\{\{#if INCLUDE_CO_AUTHOR\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6265
- }
6266
- if (preferences?.responseLanguage) {
6267
- result = result.replace(/\{\{#if RESPONSE_LANGUAGE\}\}/g, "").replace(/\{\{\/if\}\}/g, "");
6268
- } else {
6269
- result = result.replace(/\{\{#if RESPONSE_LANGUAGE\}\}[\s\S]*?\{\{\/if\}\}/g, "");
6270
- }
6271
- return result;
6272
- }
6273
- function getMinimalTemplate() {
6274
- return `# CLAUDE.md
6275
-
6276
- ## Project Overview
6277
-
6278
- **{{PROJECT_NAME}}** - {{PROJECT_DESCRIPTION}}
6279
-
6280
- ## Repository
6281
-
6282
- - **GitHub:** https://github.com/{{ORG}}/{{REPO}}
6283
-
6284
- ## Quick Commands
6285
-
6286
- \`\`\`bash
6287
- {{PACKAGE_MANAGER}} dev # Start development
6288
- {{PACKAGE_MANAGER}} test # Run tests
6289
- {{PACKAGE_MANAGER}} lint # Run linter
6290
- {{PACKAGE_MANAGER}} build # Build project
6291
- \`\`\`
6292
-
6293
- ## Claude Configuration
6294
-
6295
- This project uses \`@qazuor/claude-code-config\` for AI-assisted development.
6296
-
6297
- See \`.claude/docs/quick-start.md\` for getting started.
6298
-
6299
- ---
6300
-
6301
- *Generated by [@qazuor/claude-code-config](https://github.com/qazuor/claude-code-config)*
6302
- `;
6303
- }
6304
6344
 
6305
6345
  // src/lib/scaffold/index.ts
6306
6346
  init_esm_shims();
@@ -7053,8 +7093,8 @@ function buildSettingsLocalJson(options) {
7053
7093
 
7054
7094
  // src/lib/templates/config-replacer.ts
7055
7095
  init_esm_shims();
7056
- import * as fs4 from "fs/promises";
7057
- import * as path6 from "path";
7096
+ import * as fs3 from "fs/promises";
7097
+ import * as path5 from "path";
7058
7098
  import ora2 from "ora";
7059
7099
 
7060
7100
  // src/constants/template-placeholders.ts
@@ -7962,7 +8002,7 @@ function flattenTemplateConfig(config) {
7962
8002
  return flattened;
7963
8003
  }
7964
8004
  function shouldProcessFile(filePath) {
7965
- const ext = path6.extname(filePath).toLowerCase();
8005
+ const ext = path5.extname(filePath).toLowerCase();
7966
8006
  return PROCESSABLE_EXTENSIONS.includes(ext);
7967
8007
  }
7968
8008
  function shouldSkipDirectory(dirName) {
@@ -7971,9 +8011,9 @@ function shouldSkipDirectory(dirName) {
7971
8011
  async function getAllFiles(dir) {
7972
8012
  const files = [];
7973
8013
  try {
7974
- const entries = await fs4.readdir(dir, { withFileTypes: true });
8014
+ const entries = await fs3.readdir(dir, { withFileTypes: true });
7975
8015
  for (const entry of entries) {
7976
- const fullPath = path6.join(dir, entry.name);
8016
+ const fullPath = path5.join(dir, entry.name);
7977
8017
  if (entry.isDirectory()) {
7978
8018
  if (!shouldSkipDirectory(entry.name)) {
7979
8019
  const subFiles = await getAllFiles(fullPath);
@@ -7990,7 +8030,7 @@ async function getAllFiles(dir) {
7990
8030
  async function replaceInFile2(filePath, replacements) {
7991
8031
  const changes = [];
7992
8032
  try {
7993
- let content = await fs4.readFile(filePath, "utf-8");
8033
+ let content = await fs3.readFile(filePath, "utf-8");
7994
8034
  let modified = false;
7995
8035
  for (const [placeholder, value] of Object.entries(replacements)) {
7996
8036
  if (content.includes(placeholder)) {
@@ -8000,7 +8040,7 @@ async function replaceInFile2(filePath, replacements) {
8000
8040
  }
8001
8041
  }
8002
8042
  if (modified) {
8003
- await fs4.writeFile(filePath, content, "utf-8");
8043
+ await fs3.writeFile(filePath, content, "utf-8");
8004
8044
  }
8005
8045
  } catch {
8006
8046
  }
@@ -8021,7 +8061,7 @@ async function replaceTemplatePlaceholders(dir, config) {
8021
8061
  report.filesModified++;
8022
8062
  for (const change of changes) {
8023
8063
  report.replacements.push({
8024
- file: path6.relative(dir, file),
8064
+ file: path5.relative(dir, file),
8025
8065
  placeholder: change.placeholder,
8026
8066
  value: change.value
8027
8067
  });
@@ -8092,11 +8132,11 @@ async function previewReplacements(dir, config) {
8092
8132
  const preview = [];
8093
8133
  for (const file of files) {
8094
8134
  try {
8095
- const content = await fs4.readFile(file, "utf-8");
8135
+ const content = await fs3.readFile(file, "utf-8");
8096
8136
  for (const [placeholder, value] of Object.entries(replacements)) {
8097
8137
  if (content.includes(placeholder)) {
8098
8138
  preview.push({
8099
- file: path6.relative(dir, file),
8139
+ file: path5.relative(dir, file),
8100
8140
  placeholder,
8101
8141
  value
8102
8142
  });
@@ -8111,6 +8151,27 @@ async function previewReplacements(dir, config) {
8111
8151
  // src/cli/commands/init.ts
8112
8152
  init_fs();
8113
8153
 
8154
+ // src/lib/utils/paths.ts
8155
+ init_esm_shims();
8156
+ import fs4 from "fs";
8157
+ import path6 from "path";
8158
+ import { fileURLToPath as fileURLToPath2 } from "url";
8159
+ function getPackageRoot() {
8160
+ const currentFilePath = fileURLToPath2(import.meta.url);
8161
+ let currentDir = path6.dirname(currentFilePath);
8162
+ while (currentDir !== path6.dirname(currentDir)) {
8163
+ const packageJsonPath = path6.join(currentDir, "package.json");
8164
+ if (fs4.existsSync(packageJsonPath)) {
8165
+ return currentDir;
8166
+ }
8167
+ currentDir = path6.dirname(currentDir);
8168
+ }
8169
+ throw new Error("Could not find package root (no package.json found in parent directories)");
8170
+ }
8171
+ function getTemplatesPath() {
8172
+ return path6.join(getPackageRoot(), "templates");
8173
+ }
8174
+
8114
8175
  // src/lib/utils/prompt-cancel.ts
8115
8176
  init_esm_shims();
8116
8177
  import * as readline from "readline";
@@ -10647,6 +10708,61 @@ async function promptMcpConfig(options) {
10647
10708
  const installedServers = await getInstalledMcpServers(projectPath);
10648
10709
  const userInstalledSet = new Set(installedServers.user);
10649
10710
  const projectInstalledSet = new Set(installedServers.project);
10711
+ const availableServers = MCP_SERVERS.filter(
10712
+ (s) => !userInstalledSet.has(s.id) && !projectInstalledSet.has(s.id)
10713
+ );
10714
+ if (availableServers.length === 0) {
10715
+ logger.newline();
10716
+ logger.success("All MCP servers are already installed!");
10717
+ const parts = [];
10718
+ if (userInstalledSet.size > 0) {
10719
+ parts.push(`${userInstalledSet.size} at user level`);
10720
+ }
10721
+ if (projectInstalledSet.size > 0) {
10722
+ parts.push(`${projectInstalledSet.size} at project level`);
10723
+ }
10724
+ logger.info(colors.muted(` (${parts.join(", ")})`));
10725
+ logger.newline();
10726
+ const wantCustom2 = await confirm({
10727
+ message: "Do you want to add a custom MCP server?",
10728
+ default: false
10729
+ });
10730
+ if (wantCustom2) {
10731
+ const level2 = await select({
10732
+ message: "Where should the custom server be configured?",
10733
+ choices: [
10734
+ {
10735
+ name: "Project level (.claude/settings.local.json)",
10736
+ value: "project",
10737
+ description: "Specific to this project"
10738
+ },
10739
+ {
10740
+ name: "User level (~/.claude/settings.json)",
10741
+ value: "user",
10742
+ description: "Available in all projects"
10743
+ }
10744
+ ],
10745
+ default: options?.defaults?.level || "project"
10746
+ });
10747
+ const customInstallation = await promptCustomServer(level2);
10748
+ if (customInstallation) {
10749
+ return {
10750
+ config: {
10751
+ level: level2,
10752
+ servers: [customInstallation]
10753
+ },
10754
+ skippedConfigs: []
10755
+ };
10756
+ }
10757
+ }
10758
+ return {
10759
+ config: {
10760
+ level: "project",
10761
+ servers: []
10762
+ },
10763
+ skippedConfigs: []
10764
+ };
10765
+ }
10650
10766
  const level = await select({
10651
10767
  message: "Where should MCP servers be configured?",
10652
10768
  choices: [
@@ -10680,37 +10796,18 @@ async function promptMcpConfig(options) {
10680
10796
  }
10681
10797
  logger.newline();
10682
10798
  for (const [category, servers] of Object.entries(serversByCategory)) {
10683
- const choices = servers.map((s) => {
10684
- const isInstalledAtUserLevel = userInstalledSet.has(s.id);
10685
- const isInstalledAtProjectLevel = projectInstalledSet.has(s.id);
10686
- if (isInstalledAtUserLevel) {
10687
- return {
10688
- name: `${s.name} - ${s.description} ${colors.muted("(already installed at user level)")}`,
10689
- value: s.id,
10690
- checked: false,
10691
- disabled: "already installed at user level"
10692
- };
10693
- }
10694
- if (isInstalledAtProjectLevel) {
10695
- return {
10696
- name: `${s.name} - ${s.description} ${colors.muted("(already installed at project level)")}`,
10697
- value: s.id,
10698
- checked: false,
10699
- disabled: "already installed at project level"
10700
- };
10701
- }
10702
- return {
10703
- name: `${s.name} - ${s.description}`,
10704
- value: s.id,
10705
- checked: options?.defaults?.servers?.some((i) => i.serverId === s.id) ?? false
10706
- };
10707
- });
10708
- const hasEnabledChoices = choices.some((choice) => !choice.disabled);
10709
- const categoryLabel = formatCategory(category);
10710
- if (!hasEnabledChoices) {
10711
- logger.info(colors.muted(`${categoryLabel}: All servers already installed`));
10799
+ const availableInCategory = servers.filter(
10800
+ (s) => !userInstalledSet.has(s.id) && !projectInstalledSet.has(s.id)
10801
+ );
10802
+ if (availableInCategory.length === 0) {
10712
10803
  continue;
10713
10804
  }
10805
+ const choices = availableInCategory.map((s) => ({
10806
+ name: `${s.name} - ${s.description}`,
10807
+ value: s.id,
10808
+ checked: options?.defaults?.servers?.some((i) => i.serverId === s.id) ?? false
10809
+ }));
10810
+ const categoryLabel = formatCategory(category);
10714
10811
  const selected = await checkbox({
10715
10812
  message: `${categoryLabel}:`,
10716
10813
  choices