ai-first-cli 1.3.5 → 1.3.8
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/CHANGELOG.md +186 -0
- package/README.es.md +68 -0
- package/README.md +53 -15
- package/ai/graph/knowledge-graph.json +1 -1
- package/ai-context/index-state.json +86 -2
- package/dist/analyzers/architecture.d.ts.map +1 -1
- package/dist/analyzers/architecture.js +72 -5
- package/dist/analyzers/architecture.js.map +1 -1
- package/dist/analyzers/entrypoints.d.ts.map +1 -1
- package/dist/analyzers/entrypoints.js +253 -0
- package/dist/analyzers/entrypoints.js.map +1 -1
- package/dist/analyzers/symbols.d.ts.map +1 -1
- package/dist/analyzers/symbols.js +47 -2
- package/dist/analyzers/symbols.js.map +1 -1
- package/dist/analyzers/techStack.d.ts.map +1 -1
- package/dist/analyzers/techStack.js +86 -0
- package/dist/analyzers/techStack.js.map +1 -1
- package/dist/commands/ai-first.d.ts.map +1 -1
- package/dist/commands/ai-first.js +78 -4
- package/dist/commands/ai-first.js.map +1 -1
- package/dist/config/configLoader.d.ts +6 -0
- package/dist/config/configLoader.d.ts.map +1 -0
- package/dist/config/configLoader.js +232 -0
- package/dist/config/configLoader.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +101 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/core/content/contentProcessor.d.ts +4 -0
- package/dist/core/content/contentProcessor.d.ts.map +1 -0
- package/dist/core/content/contentProcessor.js +235 -0
- package/dist/core/content/contentProcessor.js.map +1 -0
- package/dist/core/content/index.d.ts +3 -0
- package/dist/core/content/index.d.ts.map +1 -0
- package/dist/core/content/index.js +2 -0
- package/dist/core/content/index.js.map +1 -0
- package/dist/core/content/types.d.ts +32 -0
- package/dist/core/content/types.d.ts.map +1 -0
- package/dist/core/content/types.js +2 -0
- package/dist/core/content/types.js.map +1 -0
- package/dist/core/gitAnalyzer.d.ts +14 -0
- package/dist/core/gitAnalyzer.d.ts.map +1 -1
- package/dist/core/gitAnalyzer.js +98 -0
- package/dist/core/gitAnalyzer.js.map +1 -1
- package/dist/core/multiRepo/index.d.ts +3 -0
- package/dist/core/multiRepo/index.d.ts.map +1 -0
- package/dist/core/multiRepo/index.js +2 -0
- package/dist/core/multiRepo/index.js.map +1 -0
- package/dist/core/multiRepo/multiRepoScanner.d.ts +18 -0
- package/dist/core/multiRepo/multiRepoScanner.d.ts.map +1 -0
- package/dist/core/multiRepo/multiRepoScanner.js +131 -0
- package/dist/core/multiRepo/multiRepoScanner.js.map +1 -0
- package/dist/core/rag/index.d.ts +3 -0
- package/dist/core/rag/index.d.ts.map +1 -0
- package/dist/core/rag/index.js +2 -0
- package/dist/core/rag/index.js.map +1 -0
- package/dist/core/rag/vectorIndex.d.ts +28 -0
- package/dist/core/rag/vectorIndex.d.ts.map +1 -0
- package/dist/core/rag/vectorIndex.js +71 -0
- package/dist/core/rag/vectorIndex.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +154 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/utils/fileUtils.d.ts.map +1 -1
- package/dist/utils/fileUtils.js +5 -0
- package/dist/utils/fileUtils.js.map +1 -1
- package/docs/planning/evaluator-v1.0.0/README.md +112 -0
- package/docs/planning/evaluator-v1.0.0/improvements_plan_2026-03-28.md +237 -0
- package/package.json +13 -3
- package/src/analyzers/architecture.ts +75 -6
- package/src/analyzers/entrypoints.ts +285 -0
- package/src/analyzers/symbols.ts +52 -2
- package/src/analyzers/techStack.ts +90 -0
- package/src/commands/ai-first.ts +83 -4
- package/src/config/configLoader.ts +274 -0
- package/src/config/index.ts +27 -0
- package/src/config/types.ts +117 -0
- package/src/core/content/contentProcessor.ts +292 -0
- package/src/core/content/index.ts +9 -0
- package/src/core/content/types.ts +35 -0
- package/src/core/gitAnalyzer.ts +130 -0
- package/src/core/multiRepo/index.ts +2 -0
- package/src/core/multiRepo/multiRepoScanner.ts +177 -0
- package/src/core/rag/index.ts +2 -0
- package/src/core/rag/vectorIndex.ts +105 -0
- package/src/mcp/index.ts +1 -0
- package/src/mcp/server.ts +179 -0
- package/src/utils/fileUtils.ts +5 -0
- package/tests/entrypoints-languages.test.ts +373 -0
- package/tests/framework-detection.test.ts +296 -0
- package/tests/v1.3.8-integration.test.ts +361 -0
- package/BETA_EVALUATION_REPORT.md +0 -151
- package/ai-context/context/flows/App.json +0 -17
- package/ai-context/context/flows/DashboardPage.json +0 -14
- package/ai-context/context/flows/LoginPage.json +0 -14
- package/ai-context/context/flows/admin.json +0 -10
- package/ai-context/context/flows/androidresources.json +0 -11
- package/ai-context/context/flows/authController.json +0 -14
- package/ai-context/context/flows/entrypoints.json +0 -9
- package/ai-context/context/flows/fastapiAdapter.json +0 -14
- package/ai-context/context/flows/fastapiadapter.json +0 -11
- package/ai-context/context/flows/index.json +0 -19
- package/ai-context/context/flows/indexer.json +0 -9
- package/ai-context/context/flows/indexstate.json +0 -9
- package/ai-context/context/flows/init.json +0 -22
- package/ai-context/context/flows/main.json +0 -18
- package/ai-context/context/flows/mainactivity.json +0 -9
- package/ai-context/context/flows/models.json +0 -15
- package/ai-context/context/flows/posts.json +0 -15
- package/ai-context/context/flows/repoMapper.json +0 -20
- package/ai-context/context/flows/repomapper.json +0 -11
- package/ai-context/context/flows/serializers.json +0 -10
- package/ai-context-evaluation-report-1774223059505.md +0 -206
- package/dist/scripts/ai-context-evaluator.js +0 -367
- package/quick-evaluation-report-1774396002305.md +0 -64
- package/quick-evaluator.ts +0 -200
- package/scripts/ai-context-evaluator.ts +0 -440
package/src/commands/ai-first.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { runIncrementalUpdate, detectChangedFiles } from "../core/incrementalAna
|
|
|
31
31
|
import { generateAllSchema } from "../core/schema.js";
|
|
32
32
|
import { Database } from "sql.js";
|
|
33
33
|
import ora from "ora";
|
|
34
|
+
import { startMCP } from "../mcp/index.js";
|
|
34
35
|
import process from "process";
|
|
35
36
|
|
|
36
37
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -1077,6 +1078,8 @@ Options:
|
|
|
1077
1078
|
} else if (command === 'init' || !command) {
|
|
1078
1079
|
// Init command - generate all context files
|
|
1079
1080
|
if (command === 'init') args.shift();
|
|
1081
|
+
|
|
1082
|
+
let preset: string | undefined;
|
|
1080
1083
|
|
|
1081
1084
|
for (let i = 0; i < args.length; i++) {
|
|
1082
1085
|
const arg = args[i];
|
|
@@ -1089,6 +1092,10 @@ Options:
|
|
|
1089
1092
|
case "-o":
|
|
1090
1093
|
options.outputDir = args[++i];
|
|
1091
1094
|
break;
|
|
1095
|
+
case "--preset":
|
|
1096
|
+
case "-p":
|
|
1097
|
+
preset = args[++i];
|
|
1098
|
+
break;
|
|
1092
1099
|
case "--help":
|
|
1093
1100
|
case "-h":
|
|
1094
1101
|
console.log(`
|
|
@@ -1106,18 +1113,45 @@ Commands:
|
|
|
1106
1113
|
doctor Check repository health and AI readiness
|
|
1107
1114
|
explore <module> Explore module dependencies
|
|
1108
1115
|
map Generate repository map (files, modules, graph)
|
|
1109
|
-
adapters
|
|
1110
|
-
|
|
1111
|
-
|
|
1116
|
+
adapters List available adapters
|
|
1117
|
+
git Show git activity and recent changes
|
|
1118
|
+
graph Build knowledge graph
|
|
1119
|
+
update Update context incrementally
|
|
1120
|
+
mcp Start MCP server for AI agents
|
|
1112
1121
|
|
|
1113
1122
|
Options:
|
|
1114
1123
|
-r, --root <dir> Root directory to scan (default: current directory)
|
|
1115
1124
|
-o, --output <dir> Output directory (default: ./ai-context)
|
|
1125
|
+
-p, --preset <name> Use preset (full, quick, api, docs)
|
|
1116
1126
|
-h, --help Show help message
|
|
1127
|
+
|
|
1128
|
+
Presets:
|
|
1129
|
+
full Complete analysis with all features
|
|
1130
|
+
quick Fast analysis for development iterations
|
|
1131
|
+
api Focus on API endpoints and services
|
|
1132
|
+
docs Documentation files only
|
|
1117
1133
|
`);
|
|
1118
1134
|
process.exit(0);
|
|
1119
1135
|
}
|
|
1120
1136
|
}
|
|
1137
|
+
|
|
1138
|
+
const rootDir = options.rootDir || process.cwd();
|
|
1139
|
+
const configPath = path.join(rootDir, 'ai-first.config.json');
|
|
1140
|
+
if (fs.existsSync(configPath)) {
|
|
1141
|
+
try {
|
|
1142
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
1143
|
+
if (config.output?.directory && !options.outputDir) {
|
|
1144
|
+
options.outputDir = path.join(rootDir, config.output.directory);
|
|
1145
|
+
}
|
|
1146
|
+
if (config.preset && !preset) {
|
|
1147
|
+
preset = config.preset;
|
|
1148
|
+
}
|
|
1149
|
+
} catch {}
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
if (preset) {
|
|
1153
|
+
console.log(`\n🎛️ Using preset: ${preset}\n`);
|
|
1154
|
+
}
|
|
1121
1155
|
|
|
1122
1156
|
runAIFirst(options).then((result) => {
|
|
1123
1157
|
process.exit(result.success ? 0 : 1);
|
|
@@ -1491,7 +1525,52 @@ Examples:
|
|
|
1491
1525
|
}
|
|
1492
1526
|
|
|
1493
1527
|
process.exit(0);
|
|
1494
|
-
|
|
1528
|
+
} else if (command === 'mcp') {
|
|
1529
|
+
// MCP command - start Model Context Protocol server
|
|
1530
|
+
args.shift();
|
|
1531
|
+
|
|
1532
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1533
|
+
console.log(`
|
|
1534
|
+
ai-first mcp - Start Model Context Protocol server
|
|
1535
|
+
|
|
1536
|
+
Usage: ai-first mcp [options]
|
|
1537
|
+
|
|
1538
|
+
Options:
|
|
1539
|
+
-r, --root <dir> Root directory to scan (default: current directory)
|
|
1540
|
+
-h, --help Show help message
|
|
1541
|
+
|
|
1542
|
+
Description:
|
|
1543
|
+
Starts an MCP server that allows AI agents (Claude Desktop, etc.) to
|
|
1544
|
+
query repository context using the Model Context Protocol.
|
|
1545
|
+
|
|
1546
|
+
The server provides these tools:
|
|
1547
|
+
- generate_context: Generate AI context for the repository
|
|
1548
|
+
- index_repo: Create SQLite index for fast queries
|
|
1549
|
+
- query_symbol: Look up symbols by name
|
|
1550
|
+
- get_architecture: Get architecture analysis
|
|
1551
|
+
- get_tech_stack: Get technology stack information
|
|
1552
|
+
|
|
1553
|
+
Examples:
|
|
1554
|
+
ai-first mcp # Start MCP server in current directory
|
|
1555
|
+
ai-first mcp --root ./my-project # Start with specific root directory
|
|
1556
|
+
`);
|
|
1557
|
+
process.exit(0);
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
let rootDir = process.cwd();
|
|
1561
|
+
|
|
1562
|
+
for (let i = 0; i < args.length; i++) {
|
|
1563
|
+
const arg = args[i];
|
|
1564
|
+
if (arg === "--root" || arg === "-r") rootDir = args[++i];
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
console.log("\n🚀 Starting MCP server...\n");
|
|
1568
|
+
console.log(` Root directory: ${rootDir}`);
|
|
1569
|
+
console.log(" Protocol: stdio");
|
|
1570
|
+
console.log("\n The server is now running and ready to accept MCP requests.");
|
|
1571
|
+
console.log(" Use Ctrl+C to stop.\n");
|
|
1572
|
+
|
|
1573
|
+
startMCP({ rootDir });
|
|
1495
1574
|
} else {
|
|
1496
1575
|
console.log(`Unknown command: ${command}`);
|
|
1497
1576
|
console.log(`Use 'ai-first --help' for usage information`);
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import type {
|
|
4
|
+
AIFirstConfig,
|
|
5
|
+
AnalysisPreset,
|
|
6
|
+
ConfigLoadOptions,
|
|
7
|
+
ConfigLoadResult,
|
|
8
|
+
PresetConfig,
|
|
9
|
+
ValidationResult,
|
|
10
|
+
ValidationError,
|
|
11
|
+
ValidationWarning,
|
|
12
|
+
OutputConfig,
|
|
13
|
+
IndexConfig,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
|
|
16
|
+
const DEFAULT_CONFIG_PATH = 'ai-first.config.json';
|
|
17
|
+
|
|
18
|
+
const PRESETS: Record<AnalysisPreset, PresetConfig> = {
|
|
19
|
+
full: {
|
|
20
|
+
name: 'full',
|
|
21
|
+
description: 'Full analysis with all analyzers enabled',
|
|
22
|
+
analysis: {
|
|
23
|
+
detailLevel: 'full',
|
|
24
|
+
inclusionLevel: 'full',
|
|
25
|
+
analyzers: {
|
|
26
|
+
architecture: { enabled: true },
|
|
27
|
+
techStack: { enabled: true },
|
|
28
|
+
entrypoints: { enabled: true },
|
|
29
|
+
conventions: { enabled: true },
|
|
30
|
+
symbols: { enabled: true },
|
|
31
|
+
dependencies: { enabled: true },
|
|
32
|
+
aiRules: { enabled: true },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
output: {
|
|
36
|
+
directory: 'ai-context',
|
|
37
|
+
formats: ['md', 'json'],
|
|
38
|
+
prettyPrint: true,
|
|
39
|
+
includeMetadata: true,
|
|
40
|
+
},
|
|
41
|
+
index: {
|
|
42
|
+
enabled: true,
|
|
43
|
+
type: 'sqlite',
|
|
44
|
+
incremental: true,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
quick: {
|
|
48
|
+
name: 'quick',
|
|
49
|
+
description: 'Fast analysis with basic information',
|
|
50
|
+
analysis: {
|
|
51
|
+
detailLevel: 'skeleton',
|
|
52
|
+
inclusionLevel: 'directory',
|
|
53
|
+
maxFileSize: 10000,
|
|
54
|
+
analyzers: {
|
|
55
|
+
architecture: { enabled: true },
|
|
56
|
+
techStack: { enabled: true },
|
|
57
|
+
entrypoints: { enabled: true },
|
|
58
|
+
conventions: { enabled: false },
|
|
59
|
+
symbols: { enabled: false },
|
|
60
|
+
dependencies: { enabled: false },
|
|
61
|
+
aiRules: { enabled: false },
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
output: {
|
|
65
|
+
directory: 'ai-context',
|
|
66
|
+
formats: ['md'],
|
|
67
|
+
prettyPrint: false,
|
|
68
|
+
includeMetadata: false,
|
|
69
|
+
},
|
|
70
|
+
index: {
|
|
71
|
+
enabled: false,
|
|
72
|
+
type: 'memory',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
api: {
|
|
76
|
+
name: 'api',
|
|
77
|
+
description: 'Focused on API and backend analysis',
|
|
78
|
+
analysis: {
|
|
79
|
+
detailLevel: 'signatures',
|
|
80
|
+
inclusionLevel: 'compress',
|
|
81
|
+
analyzers: {
|
|
82
|
+
architecture: { enabled: true },
|
|
83
|
+
techStack: { enabled: true },
|
|
84
|
+
entrypoints: { enabled: true },
|
|
85
|
+
conventions: { enabled: true },
|
|
86
|
+
symbols: { enabled: true },
|
|
87
|
+
dependencies: { enabled: true },
|
|
88
|
+
aiRules: { enabled: false },
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
output: {
|
|
92
|
+
directory: 'ai-context',
|
|
93
|
+
formats: ['md', 'json'],
|
|
94
|
+
prettyPrint: true,
|
|
95
|
+
includeMetadata: true,
|
|
96
|
+
},
|
|
97
|
+
index: {
|
|
98
|
+
enabled: true,
|
|
99
|
+
type: 'sqlite',
|
|
100
|
+
incremental: true,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
docs: {
|
|
104
|
+
name: 'docs',
|
|
105
|
+
description: 'Generate documentation-focused output',
|
|
106
|
+
analysis: {
|
|
107
|
+
detailLevel: 'full',
|
|
108
|
+
inclusionLevel: 'full',
|
|
109
|
+
analyzers: {
|
|
110
|
+
architecture: { enabled: true },
|
|
111
|
+
techStack: { enabled: true },
|
|
112
|
+
entrypoints: { enabled: true },
|
|
113
|
+
conventions: { enabled: true },
|
|
114
|
+
symbols: { enabled: true },
|
|
115
|
+
dependencies: { enabled: false },
|
|
116
|
+
aiRules: { enabled: false },
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
output: {
|
|
120
|
+
directory: 'ai-context',
|
|
121
|
+
formats: ['md', 'html'],
|
|
122
|
+
prettyPrint: true,
|
|
123
|
+
includeMetadata: true,
|
|
124
|
+
},
|
|
125
|
+
index: {
|
|
126
|
+
enabled: false,
|
|
127
|
+
type: 'memory',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const DEFAULT_CONFIG: AIFirstConfig = {
|
|
133
|
+
version: '1.0.0',
|
|
134
|
+
preset: 'full',
|
|
135
|
+
analysis: PRESETS.full.analysis as NonNullable<AIFirstConfig['analysis']>,
|
|
136
|
+
output: PRESETS.full.output as OutputConfig,
|
|
137
|
+
index: PRESETS.full.index as IndexConfig,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
function validateConfig(config: unknown): ValidationResult {
|
|
141
|
+
const errors: ValidationError[] = [];
|
|
142
|
+
const warnings: ValidationWarning[] = [];
|
|
143
|
+
|
|
144
|
+
if (!config || typeof config !== 'object') {
|
|
145
|
+
errors.push({ field: 'root', message: 'Config must be an object' });
|
|
146
|
+
return { valid: false, errors, warnings };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const cfg = config as Record<string, unknown>;
|
|
150
|
+
|
|
151
|
+
if (!cfg.version || typeof cfg.version !== 'string') {
|
|
152
|
+
errors.push({ field: 'version', message: 'Version is required and must be a string' });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (cfg.preset !== undefined) {
|
|
156
|
+
const validPresets: AnalysisPreset[] = ['full', 'quick', 'api', 'docs'];
|
|
157
|
+
if (!validPresets.includes(cfg.preset as AnalysisPreset)) {
|
|
158
|
+
errors.push({
|
|
159
|
+
field: 'preset',
|
|
160
|
+
message: `Invalid preset. Must be one of: ${validPresets.join(', ')}`,
|
|
161
|
+
value: cfg.preset,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (cfg.analysis && typeof cfg.analysis !== 'object') {
|
|
167
|
+
errors.push({ field: 'analysis', message: 'Analysis must be an object' });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (cfg.output && typeof cfg.output !== 'object') {
|
|
171
|
+
errors.push({ field: 'output', message: 'Output must be an object' });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (cfg.index && typeof cfg.index !== 'object') {
|
|
175
|
+
errors.push({ field: 'index', message: 'Index must be an object' });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function mergeConfig(base: AIFirstConfig, override: Partial<AIFirstConfig>): AIFirstConfig {
|
|
182
|
+
const result: AIFirstConfig = {
|
|
183
|
+
...base,
|
|
184
|
+
...override,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
if (override.analysis) {
|
|
188
|
+
result.analysis = { ...base.analysis, ...override.analysis };
|
|
189
|
+
}
|
|
190
|
+
if (override.output) {
|
|
191
|
+
result.output = { ...base.output, ...override.output } as OutputConfig;
|
|
192
|
+
}
|
|
193
|
+
if (override.index) {
|
|
194
|
+
result.index = { ...base.index, ...override.index } as IndexConfig;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function getPreset(name: AnalysisPreset): PresetConfig | undefined {
|
|
201
|
+
return PRESETS[name];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function listPresets(): PresetConfig[] {
|
|
205
|
+
return Object.values(PRESETS);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function loadConfig(options: ConfigLoadOptions = {}): ConfigLoadResult {
|
|
209
|
+
const {
|
|
210
|
+
configPath = DEFAULT_CONFIG_PATH,
|
|
211
|
+
preset,
|
|
212
|
+
overrides,
|
|
213
|
+
validate = true,
|
|
214
|
+
throwOnError = false,
|
|
215
|
+
} = options;
|
|
216
|
+
|
|
217
|
+
let config: AIFirstConfig = { ...DEFAULT_CONFIG };
|
|
218
|
+
let source: ConfigLoadResult['source'] = 'default';
|
|
219
|
+
|
|
220
|
+
if (fs.existsSync(configPath)) {
|
|
221
|
+
try {
|
|
222
|
+
const fileContent = fs.readFileSync(configPath, 'utf-8');
|
|
223
|
+
const loadedConfig = JSON.parse(fileContent) as Partial<AIFirstConfig>;
|
|
224
|
+
config = mergeConfig(DEFAULT_CONFIG, loadedConfig);
|
|
225
|
+
source = 'file';
|
|
226
|
+
} catch (error) {
|
|
227
|
+
const parseError: ValidationError = {
|
|
228
|
+
field: 'configFile',
|
|
229
|
+
message: `Failed to parse config file: ${error instanceof Error ? error.message : String(error)}`,
|
|
230
|
+
value: configPath,
|
|
231
|
+
};
|
|
232
|
+
if (throwOnError) {
|
|
233
|
+
throw new Error(parseError.message);
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
config: DEFAULT_CONFIG,
|
|
237
|
+
source: 'default',
|
|
238
|
+
validation: { valid: false, errors: [parseError], warnings: [] },
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (preset && PRESETS[preset]) {
|
|
244
|
+
const p = PRESETS[preset];
|
|
245
|
+
const presetData: Partial<AIFirstConfig> = {
|
|
246
|
+
analysis: p.analysis as AIFirstConfig['analysis'],
|
|
247
|
+
output: p.output as AIFirstConfig['output'],
|
|
248
|
+
index: p.index as AIFirstConfig['index'],
|
|
249
|
+
};
|
|
250
|
+
config = mergeConfig(config, presetData);
|
|
251
|
+
source = source === 'default' ? 'preset' : 'merged';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (overrides) {
|
|
255
|
+
config = mergeConfig(config, overrides);
|
|
256
|
+
source = 'merged';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const validation = validateConfig(config);
|
|
260
|
+
|
|
261
|
+
if (!validation.valid && throwOnError) {
|
|
262
|
+
const errorMessages = validation.errors.map(e => e.message).join('; ');
|
|
263
|
+
throw new Error(`Configuration validation failed: ${errorMessages}`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return { config, source, validation };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function resolveConfigPath(customPath?: string): string {
|
|
270
|
+
if (customPath) {
|
|
271
|
+
return path.resolve(customPath);
|
|
272
|
+
}
|
|
273
|
+
return path.resolve(DEFAULT_CONFIG_PATH);
|
|
274
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
AnalysisPreset,
|
|
3
|
+
ConfigDetailLevel,
|
|
4
|
+
ConfigInclusionLevel,
|
|
5
|
+
FilePatternConfig,
|
|
6
|
+
AnalyzerConfig,
|
|
7
|
+
AnalysisConfig,
|
|
8
|
+
FileInclusionConfig,
|
|
9
|
+
OutputConfig,
|
|
10
|
+
GitConfig,
|
|
11
|
+
IndexConfig,
|
|
12
|
+
ContextConfig,
|
|
13
|
+
PresetConfig,
|
|
14
|
+
AIFirstConfig,
|
|
15
|
+
ValidationResult,
|
|
16
|
+
ValidationError,
|
|
17
|
+
ValidationWarning,
|
|
18
|
+
ConfigLoadOptions,
|
|
19
|
+
ConfigLoadResult,
|
|
20
|
+
} from './types.js';
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
loadConfig,
|
|
24
|
+
getPreset,
|
|
25
|
+
listPresets,
|
|
26
|
+
resolveConfigPath,
|
|
27
|
+
} from './configLoader.js';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export type AnalysisPreset = 'full' | 'quick' | 'api' | 'docs';
|
|
2
|
+
|
|
3
|
+
export type ConfigDetailLevel = 'full' | 'signatures' | 'skeleton';
|
|
4
|
+
|
|
5
|
+
export type ConfigInclusionLevel = 'full' | 'compress' | 'directory' | 'exclude';
|
|
6
|
+
|
|
7
|
+
export interface FilePatternConfig {
|
|
8
|
+
include?: string[];
|
|
9
|
+
exclude?: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface AnalyzerConfig {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
options?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface AnalysisConfig {
|
|
18
|
+
preset?: AnalysisPreset;
|
|
19
|
+
detailLevel?: ConfigDetailLevel;
|
|
20
|
+
inclusionLevel?: ConfigInclusionLevel;
|
|
21
|
+
filePatterns?: FilePatternConfig;
|
|
22
|
+
maxFileSize?: number;
|
|
23
|
+
includePatterns?: string[];
|
|
24
|
+
excludePatterns?: string[];
|
|
25
|
+
analyzers?: {
|
|
26
|
+
architecture?: AnalyzerConfig;
|
|
27
|
+
techStack?: AnalyzerConfig;
|
|
28
|
+
entrypoints?: AnalyzerConfig;
|
|
29
|
+
conventions?: AnalyzerConfig;
|
|
30
|
+
symbols?: AnalyzerConfig;
|
|
31
|
+
dependencies?: AnalyzerConfig;
|
|
32
|
+
aiRules?: AnalyzerConfig;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface FileInclusionConfig {
|
|
37
|
+
level: ConfigInclusionLevel;
|
|
38
|
+
patterns: string[];
|
|
39
|
+
maxFileSize?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface OutputConfig {
|
|
43
|
+
directory: string;
|
|
44
|
+
formats: ('md' | 'json' | 'html')[];
|
|
45
|
+
prettyPrint?: boolean;
|
|
46
|
+
includeMetadata?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface GitConfig {
|
|
50
|
+
includeCommits?: number;
|
|
51
|
+
excludePatterns?: string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface IndexConfig {
|
|
55
|
+
enabled: boolean;
|
|
56
|
+
type: 'sqlite' | 'memory';
|
|
57
|
+
incremental?: boolean;
|
|
58
|
+
watch?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface ContextConfig {
|
|
62
|
+
maxTokens?: number;
|
|
63
|
+
includeEmbeddings?: boolean;
|
|
64
|
+
semanticSearch?: boolean;
|
|
65
|
+
maxResults?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PresetConfig {
|
|
69
|
+
name: AnalysisPreset;
|
|
70
|
+
description: string;
|
|
71
|
+
analysis: Partial<AnalysisConfig>;
|
|
72
|
+
output: Partial<OutputConfig>;
|
|
73
|
+
index: Partial<IndexConfig>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface AIFirstConfig {
|
|
77
|
+
version: string;
|
|
78
|
+
preset?: AnalysisPreset;
|
|
79
|
+
analysis?: AnalysisConfig;
|
|
80
|
+
output?: OutputConfig;
|
|
81
|
+
index?: IndexConfig;
|
|
82
|
+
context?: ContextConfig;
|
|
83
|
+
git?: GitConfig;
|
|
84
|
+
fileInclusion?: FileInclusionConfig;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ValidationResult {
|
|
88
|
+
valid: boolean;
|
|
89
|
+
errors: ValidationError[];
|
|
90
|
+
warnings: ValidationWarning[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface ValidationError {
|
|
94
|
+
field: string;
|
|
95
|
+
message: string;
|
|
96
|
+
value?: unknown;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface ValidationWarning {
|
|
100
|
+
field: string;
|
|
101
|
+
message: string;
|
|
102
|
+
suggestion?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface ConfigLoadOptions {
|
|
106
|
+
configPath?: string;
|
|
107
|
+
preset?: AnalysisPreset;
|
|
108
|
+
overrides?: Partial<AIFirstConfig>;
|
|
109
|
+
validate?: boolean;
|
|
110
|
+
throwOnError?: boolean;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface ConfigLoadResult {
|
|
114
|
+
config: AIFirstConfig;
|
|
115
|
+
source: 'default' | 'file' | 'preset' | 'merged';
|
|
116
|
+
validation: ValidationResult;
|
|
117
|
+
}
|