coder-config 0.45.12 → 0.45.13

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/lib/constants.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Constants and tool path configurations
3
3
  */
4
4
 
5
- const VERSION = '0.45.12';
5
+ const VERSION = '0.45.13';
6
6
 
7
7
  // Tool-specific path configurations
8
8
  const TOOL_PATHS = {
@@ -717,11 +717,28 @@ async function generateRulesWithClaude(projects) {
717
717
  return 'claude';
718
718
  };
719
719
 
720
- const projectPaths = projects.map(p =>
721
- path.resolve(p.replace(/^~/, process.env.HOME || ''))
722
- );
720
+ // Expand projects to include discovered sub-projects
721
+ const allProjects = [];
722
+ const seen = new Set();
723
+
724
+ for (const projectPath of projects) {
725
+ const absPath = path.resolve(projectPath.replace(/^~/, process.env.HOME || ''));
726
+ if (!seen.has(absPath)) {
727
+ seen.add(absPath);
728
+ allProjects.push(absPath);
729
+ }
723
730
 
724
- const projectList = projectPaths.map(p => `- ${p}`).join('\n');
731
+ // Discover sub-projects (discoverSubProjects defined below)
732
+ const subProjects = discoverSubProjects(absPath);
733
+ for (const subPath of subProjects) {
734
+ if (!seen.has(subPath)) {
735
+ seen.add(subPath);
736
+ allProjects.push(subPath);
737
+ }
738
+ }
739
+ }
740
+
741
+ const projectList = allProjects.map(p => `- ${p}`).join('\n');
725
742
 
726
743
  const prompt = `Analyze these project repositories and generate concise workstream context rules for an AI coding assistant. Focus on:
727
744
  1. What each project does (brief description)
@@ -738,7 +755,7 @@ Output markdown suitable for injecting into an AI assistant's context. Keep it c
738
755
  // Run claude -p with the prompt using execFileSync (safer than exec)
739
756
  const claudePath = getClaudePath();
740
757
  const result = execFileSync(claudePath, ['-p', prompt], {
741
- cwd: projectPaths[0],
758
+ cwd: allProjects[0],
742
759
  encoding: 'utf8',
743
760
  timeout: 60000, // 60 second timeout
744
761
  maxBuffer: 1024 * 1024, // 1MB buffer
@@ -752,23 +769,96 @@ Output markdown suitable for injecting into an AI assistant's context. Keep it c
752
769
  }
753
770
  }
754
771
 
772
+ /**
773
+ * Discover sub-projects within a directory
774
+ * Looks for directories containing project markers (package.json, pyproject.toml, etc.)
775
+ * Returns array of absolute paths to discovered sub-projects
776
+ */
777
+ function discoverSubProjects(rootPath, maxDepth = 2) {
778
+ const subProjects = [];
779
+ const skipDirs = new Set([
780
+ 'node_modules', '.git', '__pycache__', '.venv', 'venv', 'env',
781
+ 'dist', 'build', '.next', '.nuxt', 'target', 'vendor', '.tox',
782
+ 'coverage', '.pytest_cache', '.mypy_cache', '.ruff_cache'
783
+ ]);
784
+ const projectMarkers = [
785
+ 'package.json', 'pyproject.toml', 'Cargo.toml', 'go.mod',
786
+ 'CLAUDE.md', 'setup.py', 'pom.xml', 'build.gradle'
787
+ ];
788
+
789
+ function scan(dir, depth) {
790
+ if (depth > maxDepth) return;
791
+
792
+ let entries;
793
+ try {
794
+ entries = fs.readdirSync(dir, { withFileTypes: true });
795
+ } catch (e) {
796
+ return; // Can't read directory
797
+ }
798
+
799
+ for (const entry of entries) {
800
+ if (!entry.isDirectory()) continue;
801
+ if (skipDirs.has(entry.name)) continue;
802
+ if (entry.name.startsWith('.')) continue;
803
+
804
+ const subPath = path.join(dir, entry.name);
805
+
806
+ // Check if this subdirectory is a project
807
+ const hasMarker = projectMarkers.some(marker =>
808
+ fs.existsSync(path.join(subPath, marker))
809
+ );
810
+
811
+ if (hasMarker) {
812
+ subProjects.push(subPath);
813
+ }
814
+
815
+ // Continue scanning deeper
816
+ scan(subPath, depth + 1);
817
+ }
818
+ }
819
+
820
+ scan(rootPath, 0);
821
+ return subProjects;
822
+ }
823
+
755
824
  /**
756
825
  * Generate rules/context from project repositories
757
826
  * Reads README.md, package.json, CLAUDE.md, etc. to create a summary
827
+ * Automatically discovers sub-projects within each project directory
758
828
  */
759
829
  function generateRulesFromRepos(projects) {
760
830
  if (!projects || projects.length === 0) {
761
831
  return '';
762
832
  }
763
833
 
834
+ // Expand projects to include discovered sub-projects
835
+ const allProjects = [];
836
+ const seen = new Set();
837
+
838
+ for (const projectPath of projects) {
839
+ const absPath = path.resolve(projectPath.replace(/^~/, process.env.HOME || ''));
840
+ if (!seen.has(absPath)) {
841
+ seen.add(absPath);
842
+ allProjects.push(absPath);
843
+ }
844
+
845
+ // Discover sub-projects
846
+ const subProjects = discoverSubProjects(absPath);
847
+ for (const subPath of subProjects) {
848
+ if (!seen.has(subPath)) {
849
+ seen.add(subPath);
850
+ allProjects.push(subPath);
851
+ }
852
+ }
853
+ }
854
+
764
855
  const lines = [];
765
856
  lines.push('# Workstream Context');
766
857
  lines.push('');
767
858
  lines.push('## Repositories');
768
859
  lines.push('');
769
860
 
770
- for (const projectPath of projects) {
771
- const absPath = path.resolve(projectPath.replace(/^~/, process.env.HOME || ''));
861
+ for (const absPath of allProjects) {
772
862
  const name = path.basename(absPath);
773
863
 
774
864
  lines.push(`### ${name}`);
@@ -1367,6 +1457,7 @@ module.exports = {
1367
1457
  workstreamInstallHookCodex,
1368
1458
  workstreamDeactivate,
1369
1459
  workstreamCheckPath,
1460
+ discoverSubProjects,
1370
1461
  generateRulesFromRepos,
1371
1462
  generateRulesWithClaude,
1372
1463
  // New folder auto-activation functions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coder-config",
3
- "version": "0.45.12",
3
+ "version": "0.45.13",
4
4
  "description": "Configuration manager for AI coding tools - Claude Code, Gemini CLI, Codex CLI, Antigravity. Manage MCPs, rules, permissions, memory, and workstreams.",
5
5
  "author": "regression.io",
6
6
  "main": "config-loader.js",