codexa 1.0.1 → 1.1.1
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/README.md +111 -11
- package/dist/cli.js +24 -2
- package/dist/config/detector.js +339 -0
- package/dist/config/generator.js +381 -0
- package/dist/config.js +23 -1
- package/dist/ingest.js +22 -5
- package/dist/models/index.js +1 -0
- package/dist/utils/file-filter.js +177 -0
- package/package.json +3 -1
- package/scripts/postinstall.js +58 -0
- package/scripts/smoke.js +26 -0
- package/scripts/smoke.ts +21 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h1>
|
|
3
|
-
<img src="https://github.com/
|
|
3
|
+
<img src="https://github.com/user-attachments/assets/8d571bd6-ba2b-469a-8ddc-3f3ded0fd766" alt="Codexa Logo" width="90" align="absmiddle"> Codexa
|
|
4
4
|
</h1>
|
|
5
5
|
|
|
6
6
|
<p>
|
|
@@ -54,6 +54,8 @@
|
|
|
54
54
|
- 🔄 **Session Management**: Maintain conversation context across queries
|
|
55
55
|
- 📊 **Streaming Output**: Real-time response streaming for better UX
|
|
56
56
|
- 🎨 **Multiple File Types**: Supports TypeScript, JavaScript, Python, Go, Rust, Java, and more
|
|
57
|
+
- 🧠 **Smart Configuration**: Automatically detects project languages and optimizes config
|
|
58
|
+
- 🛡️ **Intelligent Filtering**: Automatically excludes binaries, large files, and build artifacts
|
|
57
59
|
- ⚙️ **Highly Configurable**: Fine-tune chunking, retrieval, and model parameters
|
|
58
60
|
- 🚀 **Zero Setup**: Works out of the box with sensible defaults
|
|
59
61
|
|
|
@@ -239,17 +241,41 @@ Once Codexa is installed and your LLM is configured, you're ready to use it:
|
|
|
239
241
|
|
|
240
242
|
### `init`
|
|
241
243
|
|
|
242
|
-
Creates a `.codexarc.json` configuration file
|
|
244
|
+
Creates a `.codexarc.json` configuration file optimized for your codebase.
|
|
243
245
|
|
|
244
246
|
```bash
|
|
245
247
|
codexa init
|
|
246
248
|
```
|
|
247
249
|
|
|
248
250
|
**What it does:**
|
|
249
|
-
-
|
|
250
|
-
-
|
|
251
|
+
- **Analyzes your codebase** to detect languages, package managers, and frameworks
|
|
252
|
+
- **Creates optimized config** with language-specific include/exclude patterns
|
|
253
|
+
- **Generates `.codexarc.json`** in the project root with tailored settings
|
|
251
254
|
- Can be safely run multiple times (won't overwrite existing config)
|
|
252
255
|
|
|
256
|
+
**Detection Capabilities:**
|
|
257
|
+
- **Languages**: TypeScript, JavaScript, Python, Go, Rust, Java, Kotlin, Scala, C/C++, Ruby, PHP, Swift, Dart, and more
|
|
258
|
+
- **Package Managers**: npm, yarn, pnpm, pip, poetry, go, cargo, maven, gradle, sbt, bundler, composer, and more
|
|
259
|
+
- **Frameworks**: Next.js, React, Django, Flask, Rails, Laravel, Spring, Flutter, and more
|
|
260
|
+
|
|
261
|
+
**Example Output:**
|
|
262
|
+
```
|
|
263
|
+
Analyzing codebase...
|
|
264
|
+
✓ Detected: typescript, javascript (npm, yarn)
|
|
265
|
+
|
|
266
|
+
✓ Created .codexarc.json with optimized settings for your codebase!
|
|
267
|
+
|
|
268
|
+
┌ 🚀 Setup Complete ──────────────────────────────────────────┐
|
|
269
|
+
│ │
|
|
270
|
+
│ Next Steps: │
|
|
271
|
+
│ │
|
|
272
|
+
│ 1. Review .codexarc.json - Update provider keys if needed │
|
|
273
|
+
│ 2. Run: codexa ingest - Start indexing your codebase │
|
|
274
|
+
│ 3. Run: codexa ask "your question" - Ask questions │
|
|
275
|
+
│ │
|
|
276
|
+
└─────────────────────────────────────────────────────────────┘
|
|
277
|
+
```
|
|
278
|
+
|
|
253
279
|
---
|
|
254
280
|
|
|
255
281
|
### `ingest`
|
|
@@ -274,9 +300,15 @@ codexa ingest --force
|
|
|
274
300
|
|
|
275
301
|
**What it does:**
|
|
276
302
|
1. Scans your repository based on `includeGlobs` and `excludeGlobs` patterns
|
|
277
|
-
2.
|
|
278
|
-
3.
|
|
279
|
-
4.
|
|
303
|
+
2. **Filters files** - Automatically excludes binaries, large files (>5MB), and build artifacts
|
|
304
|
+
3. Chunks files into manageable segments
|
|
305
|
+
4. Generates vector embeddings for each chunk
|
|
306
|
+
5. Stores everything in `.codexa/index.db` (SQLite database)
|
|
307
|
+
|
|
308
|
+
**Smart Filtering:**
|
|
309
|
+
- Automatically skips binary files (executables, images, archives, etc.)
|
|
310
|
+
- Excludes files larger than the configured size limit (default: 5MB)
|
|
311
|
+
- Filters based on file content analysis (not just extensions)
|
|
280
312
|
|
|
281
313
|
**Note:** First ingestion may take a few minutes depending on your codebase size. Subsequent ingestions are faster as they only process changed files.
|
|
282
314
|
|
|
@@ -332,6 +364,28 @@ Codexa uses a `.codexarc.json` file in your project root for configuration. This
|
|
|
332
364
|
|
|
333
365
|
**Format:** JSON
|
|
334
366
|
|
|
367
|
+
### Dynamic Configuration Generation
|
|
368
|
+
|
|
369
|
+
When you run `codexa init`, Codexa automatically:
|
|
370
|
+
|
|
371
|
+
1. **Analyzes your codebase** structure to detect:
|
|
372
|
+
- Languages present (by file extensions)
|
|
373
|
+
- Package managers used (by config files)
|
|
374
|
+
- Frameworks detected (by dependencies and config files)
|
|
375
|
+
|
|
376
|
+
2. **Generates optimized patterns**:
|
|
377
|
+
- **Include patterns**: Only file extensions relevant to detected languages
|
|
378
|
+
- **Exclude patterns**: Language-specific build artifacts, dependency directories, and cache folders
|
|
379
|
+
- **Smart defaults**: Based on your project type
|
|
380
|
+
|
|
381
|
+
3. **Applies best practices**:
|
|
382
|
+
- Excludes common build outputs (`dist/`, `build/`, `target/`, etc.)
|
|
383
|
+
- Excludes dependency directories (`node_modules/`, `vendor/`, `.venv/`, etc.)
|
|
384
|
+
- Includes important config files and documentation
|
|
385
|
+
- Filters binaries and large files automatically
|
|
386
|
+
|
|
387
|
+
This means your config is tailored to your project from the start, ensuring optimal indexing performance!
|
|
388
|
+
|
|
335
389
|
### Environment Variables
|
|
336
390
|
|
|
337
391
|
Some settings can be configured via environment variables:
|
|
@@ -468,6 +522,49 @@ Controls randomness in LLM responses (0.0 = deterministic, 1.0 = creative).
|
|
|
468
522
|
|
|
469
523
|
Number of code chunks to retrieve and use as context for each question. Higher values provide more context but may include less relevant information.
|
|
470
524
|
|
|
525
|
+
#### `maxFileSize`
|
|
526
|
+
|
|
527
|
+
**Type:** `number`
|
|
528
|
+
**Default:** `5242880` (5MB)
|
|
529
|
+
|
|
530
|
+
Maximum file size in bytes. Files larger than this will be excluded from indexing. Helps avoid processing large binary files or generated artifacts.
|
|
531
|
+
|
|
532
|
+
**Example:**
|
|
533
|
+
```json
|
|
534
|
+
{
|
|
535
|
+
"maxFileSize": 10485760 // 10MB
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
#### `skipBinaryFiles`
|
|
540
|
+
|
|
541
|
+
**Type:** `boolean`
|
|
542
|
+
**Default:** `true`
|
|
543
|
+
|
|
544
|
+
Whether to automatically skip binary files during indexing. Binary detection uses both file extension and content analysis.
|
|
545
|
+
|
|
546
|
+
**Example:**
|
|
547
|
+
```json
|
|
548
|
+
{
|
|
549
|
+
"skipBinaryFiles": true
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
#### `skipLargeFiles`
|
|
554
|
+
|
|
555
|
+
**Type:** `boolean`
|
|
556
|
+
**Default:** `true`
|
|
557
|
+
|
|
558
|
+
Whether to skip files exceeding `maxFileSize` during indexing. Set to `false` if you want to include all files regardless of size.
|
|
559
|
+
|
|
560
|
+
**Example:**
|
|
561
|
+
```json
|
|
562
|
+
{
|
|
563
|
+
"skipLargeFiles": true,
|
|
564
|
+
"maxFileSize": 10485760 // 10MB
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
471
568
|
### Example Configurations
|
|
472
569
|
|
|
473
570
|
#### Groq Cloud Provider (Default)
|
|
@@ -666,10 +763,13 @@ When you run `codexa ask`:
|
|
|
666
763
|
**Problem:** First ingestion takes too long.
|
|
667
764
|
|
|
668
765
|
**Solutions:**
|
|
669
|
-
1.
|
|
670
|
-
2.
|
|
671
|
-
3.
|
|
672
|
-
4.
|
|
766
|
+
1. The dynamic config should already optimize patterns - check your `.codexarc.json` was generated correctly
|
|
767
|
+
2. Reduce `maxFileSize` to exclude more large files
|
|
768
|
+
3. Reduce `maxChunkSize` to create more, smaller chunks
|
|
769
|
+
4. Add more patterns to `excludeGlobs` to skip unnecessary files
|
|
770
|
+
5. Be more specific with `includeGlobs` to focus on important files
|
|
771
|
+
6. Use `--force` only when necessary (incremental updates are faster)
|
|
772
|
+
7. Ensure `skipBinaryFiles` and `skipLargeFiles` are enabled (default)
|
|
673
773
|
|
|
674
774
|
### Poor Quality Answers
|
|
675
775
|
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
8
|
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
10
|
const config_1 = require("./config");
|
|
10
11
|
const ingest_1 = require("./ingest");
|
|
11
12
|
const agent_1 = require("./agent");
|
|
@@ -22,14 +23,35 @@ const program = new commander_1.Command();
|
|
|
22
23
|
program
|
|
23
24
|
.name('codexa')
|
|
24
25
|
.description('Ask questions about any local repository from the command line.')
|
|
25
|
-
.version('
|
|
26
|
+
.version('1.1.1')
|
|
27
|
+
.action(() => {
|
|
28
|
+
console.log('\n');
|
|
29
|
+
logger_1.log.box(`${chalk_1.default.bold('Welcome to Codexa!')}\n\n` +
|
|
30
|
+
`${chalk_1.default.dim('Codexa is a CLI tool that helps you understand your codebase using AI.')}\n\n` +
|
|
31
|
+
`${chalk_1.default.bold('Getting Started:')}\n\n` +
|
|
32
|
+
`${chalk_1.default.dim('1.')} ${chalk_1.default.white('Initialize Codexa in your project:')}\n` +
|
|
33
|
+
` ${chalk_1.default.cyan('codexa init')}\n\n` +
|
|
34
|
+
`${chalk_1.default.dim('2.')} ${chalk_1.default.white('Index your codebase:')}\n` +
|
|
35
|
+
` ${chalk_1.default.cyan('codexa ingest')}\n\n` +
|
|
36
|
+
`${chalk_1.default.dim('3.')} ${chalk_1.default.white('Ask questions:')}\n` +
|
|
37
|
+
` ${chalk_1.default.cyan('codexa ask "your question"')}\n\n` +
|
|
38
|
+
`${chalk_1.default.dim('For more help, run:')} ${chalk_1.default.cyan('codexa --help')}`, '🚀 Codexa');
|
|
39
|
+
console.log('\n');
|
|
40
|
+
});
|
|
26
41
|
program
|
|
27
42
|
.command('init')
|
|
28
43
|
.description('Create a local .codexarc.json with sensible defaults.')
|
|
29
44
|
.action(async () => {
|
|
30
45
|
const cwd = process.cwd();
|
|
31
46
|
await (0, config_1.ensureConfig)(cwd);
|
|
32
|
-
|
|
47
|
+
console.log('\n');
|
|
48
|
+
logger_1.log.success('Created .codexarc.json with optimized settings for your codebase!');
|
|
49
|
+
console.log('\n');
|
|
50
|
+
logger_1.log.box(`${chalk_1.default.bold('Next Steps:')}\n\n` +
|
|
51
|
+
`${chalk_1.default.dim('1.')} ${chalk_1.default.white('Review .codexarc.json')} - Update provider keys if needed\n` +
|
|
52
|
+
`${chalk_1.default.dim('2.')} ${chalk_1.default.white('Run:')} ${chalk_1.default.cyan('codexa ingest')} ${chalk_1.default.dim('- Start indexing your codebase')}\n` +
|
|
53
|
+
`${chalk_1.default.dim('3.')} ${chalk_1.default.white('Run:')} ${chalk_1.default.cyan('codexa ask "your question"')} ${chalk_1.default.dim('- Ask questions about your code')}`, '🚀 Setup Complete');
|
|
54
|
+
console.log('\n');
|
|
33
55
|
});
|
|
34
56
|
program
|
|
35
57
|
.command('ingest')
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.analyzeProject = analyzeProject;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const globby_1 = require("globby");
|
|
10
|
+
const LANGUAGE_DEFINITIONS = [
|
|
11
|
+
{
|
|
12
|
+
name: 'typescript',
|
|
13
|
+
extensions: ['.ts', '.tsx', '.d.ts'],
|
|
14
|
+
packageManagers: ['npm', 'yarn', 'pnpm'],
|
|
15
|
+
frameworks: ['nextjs', 'react', 'angular', 'vue', 'nest', 'express'],
|
|
16
|
+
configFiles: ['tsconfig.json', 'next.config.js', 'next.config.ts'],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'javascript',
|
|
20
|
+
extensions: ['.js', '.jsx', '.mjs', '.cjs'],
|
|
21
|
+
packageManagers: ['npm', 'yarn', 'pnpm'],
|
|
22
|
+
frameworks: ['react', 'vue', 'express', 'nextjs'],
|
|
23
|
+
configFiles: ['package.json', 'webpack.config.js', 'vite.config.js'],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'python',
|
|
27
|
+
extensions: ['.py', '.pyw', '.pyi'],
|
|
28
|
+
packageManagers: ['pip', 'poetry', 'pipenv', 'conda'],
|
|
29
|
+
frameworks: ['django', 'flask', 'fastapi', 'pytest'],
|
|
30
|
+
configFiles: [
|
|
31
|
+
'requirements.txt',
|
|
32
|
+
'setup.py',
|
|
33
|
+
'pyproject.toml',
|
|
34
|
+
'Pipfile',
|
|
35
|
+
'poetry.lock',
|
|
36
|
+
'manage.py',
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'go',
|
|
41
|
+
extensions: ['.go'],
|
|
42
|
+
packageManagers: ['go'],
|
|
43
|
+
frameworks: ['gin', 'echo', 'fiber'],
|
|
44
|
+
configFiles: ['go.mod', 'go.sum', 'Gopkg.toml'],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'rust',
|
|
48
|
+
extensions: ['.rs'],
|
|
49
|
+
packageManagers: ['cargo'],
|
|
50
|
+
frameworks: ['actix', 'rocket', 'axum'],
|
|
51
|
+
configFiles: ['Cargo.toml', 'Cargo.lock'],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'java',
|
|
55
|
+
extensions: ['.java', '.kt', '.scala'],
|
|
56
|
+
packageManagers: ['maven', 'gradle', 'sbt'],
|
|
57
|
+
frameworks: ['spring', 'javafx', 'android'],
|
|
58
|
+
configFiles: ['pom.xml', 'build.gradle', 'build.sbt', 'settings.gradle'],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'cpp',
|
|
62
|
+
extensions: ['.cpp', '.cxx', '.cc', '.c++', '.hpp', '.hxx', '.h++'],
|
|
63
|
+
packageManagers: ['cmake', 'conan'],
|
|
64
|
+
frameworks: ['qt', 'boost'],
|
|
65
|
+
configFiles: ['CMakeLists.txt', 'Makefile', 'conanfile.txt'],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'c',
|
|
69
|
+
extensions: ['.c', '.h'],
|
|
70
|
+
packageManagers: ['cmake', 'make'],
|
|
71
|
+
configFiles: ['CMakeLists.txt', 'Makefile', 'configure'],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'ruby',
|
|
75
|
+
extensions: ['.rb', '.rake'],
|
|
76
|
+
packageManagers: ['bundler', 'gem'],
|
|
77
|
+
frameworks: ['rails', 'sinatra'],
|
|
78
|
+
configFiles: ['Gemfile', 'Gemfile.lock', 'Rakefile'],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'php',
|
|
82
|
+
extensions: ['.php', '.phtml'],
|
|
83
|
+
packageManagers: ['composer'],
|
|
84
|
+
frameworks: ['laravel', 'symfony', 'wordpress'],
|
|
85
|
+
configFiles: ['composer.json', 'composer.lock'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'swift',
|
|
89
|
+
extensions: ['.swift'],
|
|
90
|
+
packageManagers: ['swiftpm', 'cocoapods'],
|
|
91
|
+
frameworks: ['swiftui', 'uikit'],
|
|
92
|
+
configFiles: ['Package.swift', 'Podfile'],
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'kotlin',
|
|
96
|
+
extensions: ['.kt', '.kts'],
|
|
97
|
+
packageManagers: ['gradle', 'maven'],
|
|
98
|
+
frameworks: ['android', 'spring'],
|
|
99
|
+
configFiles: ['build.gradle.kts', 'pom.xml'],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'scala',
|
|
103
|
+
extensions: ['.scala', '.sc'],
|
|
104
|
+
packageManagers: ['sbt', 'maven'],
|
|
105
|
+
frameworks: ['play', 'akka'],
|
|
106
|
+
configFiles: ['build.sbt', 'pom.xml'],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'dart',
|
|
110
|
+
extensions: ['.dart'],
|
|
111
|
+
packageManagers: ['pub'],
|
|
112
|
+
frameworks: ['flutter'],
|
|
113
|
+
configFiles: ['pubspec.yaml', 'pubspec.lock'],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'html',
|
|
117
|
+
extensions: ['.html', '.htm', '.xhtml'],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'css',
|
|
121
|
+
extensions: ['.css', '.scss', '.sass', '.less', '.styl'],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'sql',
|
|
125
|
+
extensions: ['.sql'],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'shell',
|
|
129
|
+
extensions: ['.sh', '.bash', '.zsh', '.fish'],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'yaml',
|
|
133
|
+
extensions: ['.yaml', '.yml'],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: 'toml',
|
|
137
|
+
extensions: ['.toml'],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'json',
|
|
141
|
+
extensions: ['.json'],
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'xml',
|
|
145
|
+
extensions: ['.xml'],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'markdown',
|
|
149
|
+
extensions: ['.md', '.markdown', '.mdx'],
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'docker',
|
|
153
|
+
extensions: ['.dockerfile'],
|
|
154
|
+
configFiles: ['Dockerfile', 'docker-compose.yml', 'docker-compose.yaml'],
|
|
155
|
+
},
|
|
156
|
+
];
|
|
157
|
+
const FRAMEWORK_INDICATORS = {
|
|
158
|
+
nextjs: ['next.config.js', 'next.config.ts', '.next'],
|
|
159
|
+
react: ['package.json'],
|
|
160
|
+
django: ['manage.py', 'settings.py', 'wsgi.py'],
|
|
161
|
+
flask: ['flask', 'app.py'], // Check for flask import
|
|
162
|
+
rails: ['Gemfile', 'config.ru', 'app/models'],
|
|
163
|
+
laravel: ['artisan', 'app/Http'],
|
|
164
|
+
spring: ['pom.xml', 'application.properties'],
|
|
165
|
+
android: ['AndroidManifest.xml', 'build.gradle'],
|
|
166
|
+
flutter: ['pubspec.yaml', 'lib/main.dart'],
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Analyzes codebase to detect languages, package managers, and frameworks
|
|
170
|
+
*/
|
|
171
|
+
async function analyzeProject(cwd) {
|
|
172
|
+
const languages = new Set();
|
|
173
|
+
const packageManagers = new Set();
|
|
174
|
+
const frameworks = new Set();
|
|
175
|
+
const detectedConfigFiles = [];
|
|
176
|
+
let hasLargeFiles = false;
|
|
177
|
+
try {
|
|
178
|
+
const allFiles = await (0, globby_1.globby)(['**/*'], {
|
|
179
|
+
cwd,
|
|
180
|
+
gitignore: true,
|
|
181
|
+
ignore: ['node_modules/**', '.git/**', 'dist/**', 'build/**', '.codexa/**'],
|
|
182
|
+
onlyFiles: true,
|
|
183
|
+
absolute: false,
|
|
184
|
+
});
|
|
185
|
+
const extensionMap = new Map();
|
|
186
|
+
const LARGE_FILE_THRESHOLD = 5 * 1024 * 1024;
|
|
187
|
+
for (const file of allFiles) {
|
|
188
|
+
const ext = node_path_1.default.extname(file).toLowerCase();
|
|
189
|
+
if (ext) {
|
|
190
|
+
extensionMap.set(ext, (extensionMap.get(ext) || 0) + 1);
|
|
191
|
+
}
|
|
192
|
+
// large file check
|
|
193
|
+
try {
|
|
194
|
+
const filePath = node_path_1.default.join(cwd, file);
|
|
195
|
+
const stats = await fs_extra_1.default.stat(filePath);
|
|
196
|
+
if (stats.size > LARGE_FILE_THRESHOLD) {
|
|
197
|
+
hasLargeFiles = true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
// Ignore errors (file might not exist, permission issues, etc.)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (const lang of LANGUAGE_DEFINITIONS) {
|
|
205
|
+
const hasExtension = lang.extensions.some((ext) => extensionMap.has(ext));
|
|
206
|
+
if (hasExtension) {
|
|
207
|
+
languages.add(lang.name);
|
|
208
|
+
if (lang.packageManagers) {
|
|
209
|
+
lang.packageManagers.forEach((pm) => packageManagers.add(pm));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const configFileChecks = [
|
|
214
|
+
'package.json', // npm/yarn/pnpm
|
|
215
|
+
'package-lock.json', // npm
|
|
216
|
+
'yarn.lock', // yarn
|
|
217
|
+
'pnpm-lock.yaml', // pnpm
|
|
218
|
+
'requirements.txt', // pip
|
|
219
|
+
'pyproject.toml', // poetry
|
|
220
|
+
'Pipfile', // pipenv
|
|
221
|
+
'go.mod', // go
|
|
222
|
+
'Cargo.toml', // cargo
|
|
223
|
+
'pom.xml', // maven
|
|
224
|
+
'build.gradle', // gradle
|
|
225
|
+
'build.sbt', // sbt
|
|
226
|
+
'Gemfile', // bundler
|
|
227
|
+
'composer.json', // composer
|
|
228
|
+
'pubspec.yaml', // pub (dart/flutter)
|
|
229
|
+
'CMakeLists.txt', // cmake
|
|
230
|
+
'Makefile', // make
|
|
231
|
+
'Dockerfile', // docker
|
|
232
|
+
'docker-compose.yml',
|
|
233
|
+
'docker-compose.yaml',
|
|
234
|
+
];
|
|
235
|
+
for (const configFile of configFileChecks) {
|
|
236
|
+
const configPath = node_path_1.default.join(cwd, configFile);
|
|
237
|
+
if (await fs_extra_1.default.pathExists(configPath)) {
|
|
238
|
+
detectedConfigFiles.push(configFile);
|
|
239
|
+
if (configFile === 'package.json' || configFile === 'package-lock.json') {
|
|
240
|
+
packageManagers.add('npm');
|
|
241
|
+
}
|
|
242
|
+
else if (configFile === 'yarn.lock') {
|
|
243
|
+
packageManagers.add('yarn');
|
|
244
|
+
}
|
|
245
|
+
else if (configFile === 'pnpm-lock.yaml') {
|
|
246
|
+
packageManagers.add('pnpm');
|
|
247
|
+
}
|
|
248
|
+
else if (configFile === 'requirements.txt' || configFile === 'setup.py') {
|
|
249
|
+
packageManagers.add('pip');
|
|
250
|
+
}
|
|
251
|
+
else if (configFile === 'pyproject.toml' || configFile === 'poetry.lock') {
|
|
252
|
+
packageManagers.add('poetry');
|
|
253
|
+
}
|
|
254
|
+
else if (configFile === 'Pipfile') {
|
|
255
|
+
packageManagers.add('pipenv');
|
|
256
|
+
}
|
|
257
|
+
else if (configFile === 'go.mod') {
|
|
258
|
+
packageManagers.add('go');
|
|
259
|
+
}
|
|
260
|
+
else if (configFile === 'Cargo.toml') {
|
|
261
|
+
packageManagers.add('cargo');
|
|
262
|
+
}
|
|
263
|
+
else if (configFile === 'pom.xml') {
|
|
264
|
+
packageManagers.add('maven');
|
|
265
|
+
}
|
|
266
|
+
else if (configFile === 'build.gradle' || configFile === 'settings.gradle') {
|
|
267
|
+
packageManagers.add('gradle');
|
|
268
|
+
}
|
|
269
|
+
else if (configFile === 'build.sbt') {
|
|
270
|
+
packageManagers.add('sbt');
|
|
271
|
+
}
|
|
272
|
+
else if (configFile === 'Gemfile') {
|
|
273
|
+
packageManagers.add('bundler');
|
|
274
|
+
}
|
|
275
|
+
else if (configFile === 'composer.json') {
|
|
276
|
+
packageManagers.add('composer');
|
|
277
|
+
}
|
|
278
|
+
else if (configFile === 'pubspec.yaml') {
|
|
279
|
+
packageManagers.add('pub');
|
|
280
|
+
}
|
|
281
|
+
else if (configFile === 'CMakeLists.txt') {
|
|
282
|
+
packageManagers.add('cmake');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
for (const [framework, indicators] of Object.entries(FRAMEWORK_INDICATORS)) {
|
|
287
|
+
for (const indicator of indicators) {
|
|
288
|
+
const indicatorPath = node_path_1.default.join(cwd, indicator);
|
|
289
|
+
if (await fs_extra_1.default.pathExists(indicatorPath)) {
|
|
290
|
+
frameworks.add(framework);
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// Special case: Check package.json for framework dependencies
|
|
296
|
+
const packageJsonPath = node_path_1.default.join(cwd, 'package.json');
|
|
297
|
+
if (await fs_extra_1.default.pathExists(packageJsonPath)) {
|
|
298
|
+
try {
|
|
299
|
+
const packageJson = await fs_extra_1.default.readJson(packageJsonPath);
|
|
300
|
+
const deps = {
|
|
301
|
+
...packageJson.dependencies,
|
|
302
|
+
...packageJson.devDependencies,
|
|
303
|
+
};
|
|
304
|
+
const depNames = Object.keys(deps).map((d) => d.toLowerCase());
|
|
305
|
+
if (depNames.some((d) => d.includes('react'))) {
|
|
306
|
+
frameworks.add('react');
|
|
307
|
+
}
|
|
308
|
+
if (depNames.some((d) => d.includes('next'))) {
|
|
309
|
+
frameworks.add('nextjs');
|
|
310
|
+
}
|
|
311
|
+
if (depNames.some((d) => d.includes('angular'))) {
|
|
312
|
+
frameworks.add('angular');
|
|
313
|
+
}
|
|
314
|
+
if (depNames.some((d) => d.includes('vue'))) {
|
|
315
|
+
frameworks.add('vue');
|
|
316
|
+
}
|
|
317
|
+
if (depNames.some((d) => d.includes('nestjs'))) {
|
|
318
|
+
frameworks.add('nest');
|
|
319
|
+
}
|
|
320
|
+
if (depNames.some((d) => d.includes('express'))) {
|
|
321
|
+
frameworks.add('express');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
// Ignore JSON parse err
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
console.warn(`Project analysis warning: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
languages: Array.from(languages).sort(),
|
|
334
|
+
packageManagers: Array.from(packageManagers).sort(),
|
|
335
|
+
frameworks: Array.from(frameworks).sort(),
|
|
336
|
+
hasLargeFiles,
|
|
337
|
+
detectedConfigFiles: detectedConfigFiles.sort(),
|
|
338
|
+
};
|
|
339
|
+
}
|