ai-first-cli 1.1.0 → 1.1.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/CHANGELOG.md +78 -0
- package/README.es.md +137 -1
- package/README.md +136 -4
- package/ai/ai_context.md +2 -2
- package/ai/architecture.md +3 -3
- package/ai/cache.json +85 -57
- package/ai/ccp/jira-123/context.json +7 -0
- package/ai/context/repo.json +56 -0
- package/ai/context/utils.json +7 -0
- package/ai/dependencies.json +51 -1026
- package/ai/files.json +195 -3
- package/ai/git/commit-activity.json +8646 -0
- package/ai/git/recent-features.json +1 -0
- package/ai/git/recent-files.json +52 -0
- package/ai/git/recent-flows.json +1 -0
- package/ai/graph/knowledge-graph.json +43643 -0
- package/ai/graph/module-graph.json +4 -0
- package/ai/graph/symbol-graph.json +3307 -879
- package/ai/graph/symbol-references.json +119 -32
- package/ai/index-state.json +843 -188
- package/ai/index.db +0 -0
- package/ai/modules.json +4 -0
- package/ai/repo-map.json +81 -17
- package/ai/repo_map.json +81 -17
- package/ai/repo_map.md +21 -7
- package/ai/summary.md +5 -5
- package/ai/symbols.json +1 -20287
- package/dist/analyzers/androidResources.d.ts +23 -0
- package/dist/analyzers/androidResources.d.ts.map +1 -0
- package/dist/analyzers/androidResources.js +93 -0
- package/dist/analyzers/androidResources.js.map +1 -0
- package/dist/analyzers/dependencies.d.ts.map +1 -1
- package/dist/analyzers/dependencies.js +37 -0
- package/dist/analyzers/dependencies.js.map +1 -1
- package/dist/analyzers/entrypoints.d.ts.map +1 -1
- package/dist/analyzers/entrypoints.js +71 -1
- package/dist/analyzers/entrypoints.js.map +1 -1
- package/dist/analyzers/gradleModules.d.ts +22 -0
- package/dist/analyzers/gradleModules.d.ts.map +1 -0
- package/dist/analyzers/gradleModules.js +75 -0
- package/dist/analyzers/gradleModules.js.map +1 -0
- package/dist/analyzers/techStack.d.ts +7 -0
- package/dist/analyzers/techStack.d.ts.map +1 -1
- package/dist/analyzers/techStack.js +44 -1
- package/dist/analyzers/techStack.js.map +1 -1
- package/dist/commands/ai-first.d.ts.map +1 -1
- package/dist/commands/ai-first.js +311 -1
- package/dist/commands/ai-first.js.map +1 -1
- package/dist/core/adapters/adapterRegistry.d.ts +39 -0
- package/dist/core/adapters/adapterRegistry.d.ts.map +1 -0
- package/dist/core/adapters/adapterRegistry.js +155 -0
- package/dist/core/adapters/adapterRegistry.js.map +1 -0
- package/dist/core/adapters/baseAdapter.d.ts +49 -0
- package/dist/core/adapters/baseAdapter.d.ts.map +1 -0
- package/dist/core/adapters/baseAdapter.js +28 -0
- package/dist/core/adapters/baseAdapter.js.map +1 -0
- package/dist/core/adapters/community/fastapiAdapter.d.ts +7 -0
- package/dist/core/adapters/community/fastapiAdapter.d.ts.map +1 -0
- package/dist/core/adapters/community/fastapiAdapter.js +40 -0
- package/dist/core/adapters/community/fastapiAdapter.js.map +1 -0
- package/dist/core/adapters/community/index.d.ts +11 -0
- package/dist/core/adapters/community/index.d.ts.map +1 -0
- package/dist/core/adapters/community/index.js +11 -0
- package/dist/core/adapters/community/index.js.map +1 -0
- package/dist/core/adapters/community/laravelAdapter.d.ts +7 -0
- package/dist/core/adapters/community/laravelAdapter.d.ts.map +1 -0
- package/dist/core/adapters/community/laravelAdapter.js +47 -0
- package/dist/core/adapters/community/laravelAdapter.js.map +1 -0
- package/dist/core/adapters/community/nestjsAdapter.d.ts +7 -0
- package/dist/core/adapters/community/nestjsAdapter.d.ts.map +1 -0
- package/dist/core/adapters/community/nestjsAdapter.js +48 -0
- package/dist/core/adapters/community/nestjsAdapter.js.map +1 -0
- package/dist/core/adapters/community/phoenixAdapter.d.ts +7 -0
- package/dist/core/adapters/community/phoenixAdapter.d.ts.map +1 -0
- package/dist/core/adapters/community/phoenixAdapter.js +45 -0
- package/dist/core/adapters/community/phoenixAdapter.js.map +1 -0
- package/dist/core/adapters/community/springBootAdapter.d.ts +7 -0
- package/dist/core/adapters/community/springBootAdapter.d.ts.map +1 -0
- package/dist/core/adapters/community/springBootAdapter.js +44 -0
- package/dist/core/adapters/community/springBootAdapter.js.map +1 -0
- package/dist/core/adapters/dotnetAdapter.d.ts +20 -0
- package/dist/core/adapters/dotnetAdapter.d.ts.map +1 -0
- package/dist/core/adapters/dotnetAdapter.js +86 -0
- package/dist/core/adapters/dotnetAdapter.js.map +1 -0
- package/dist/core/adapters/index.d.ts +18 -0
- package/dist/core/adapters/index.d.ts.map +1 -0
- package/dist/core/adapters/index.js +19 -0
- package/dist/core/adapters/index.js.map +1 -0
- package/dist/core/adapters/javascriptAdapter.d.ts +11 -0
- package/dist/core/adapters/javascriptAdapter.d.ts.map +1 -0
- package/dist/core/adapters/javascriptAdapter.js +47 -0
- package/dist/core/adapters/javascriptAdapter.js.map +1 -0
- package/dist/core/adapters/pythonAdapter.d.ts +20 -0
- package/dist/core/adapters/pythonAdapter.d.ts.map +1 -0
- package/dist/core/adapters/pythonAdapter.js +99 -0
- package/dist/core/adapters/pythonAdapter.js.map +1 -0
- package/dist/core/adapters/railsAdapter.d.ts +10 -0
- package/dist/core/adapters/railsAdapter.d.ts.map +1 -0
- package/dist/core/adapters/railsAdapter.js +52 -0
- package/dist/core/adapters/railsAdapter.js.map +1 -0
- package/dist/core/adapters/salesforceAdapter.d.ts +16 -0
- package/dist/core/adapters/salesforceAdapter.d.ts.map +1 -0
- package/dist/core/adapters/salesforceAdapter.js +64 -0
- package/dist/core/adapters/salesforceAdapter.js.map +1 -0
- package/dist/core/adapters/sdk.d.ts +83 -0
- package/dist/core/adapters/sdk.d.ts.map +1 -0
- package/dist/core/adapters/sdk.js +114 -0
- package/dist/core/adapters/sdk.js.map +1 -0
- package/dist/core/ccp.d.ts +37 -0
- package/dist/core/ccp.d.ts.map +1 -0
- package/dist/core/ccp.js +184 -0
- package/dist/core/ccp.js.map +1 -0
- package/dist/core/gitAnalyzer.d.ts +74 -0
- package/dist/core/gitAnalyzer.d.ts.map +1 -0
- package/dist/core/gitAnalyzer.js +298 -0
- package/dist/core/gitAnalyzer.js.map +1 -0
- package/dist/core/incrementalAnalyzer.d.ts +28 -0
- package/dist/core/incrementalAnalyzer.d.ts.map +1 -0
- package/dist/core/incrementalAnalyzer.js +343 -0
- package/dist/core/incrementalAnalyzer.js.map +1 -0
- package/dist/core/knowledgeGraphBuilder.d.ts +31 -0
- package/dist/core/knowledgeGraphBuilder.d.ts.map +1 -0
- package/dist/core/knowledgeGraphBuilder.js +197 -0
- package/dist/core/knowledgeGraphBuilder.js.map +1 -0
- package/dist/core/lazyAnalyzer.d.ts +57 -0
- package/dist/core/lazyAnalyzer.d.ts.map +1 -0
- package/dist/core/lazyAnalyzer.js +204 -0
- package/dist/core/lazyAnalyzer.js.map +1 -0
- package/dist/core/schema.d.ts +57 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +131 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/semanticContexts.d.ts +40 -0
- package/dist/core/semanticContexts.d.ts.map +1 -0
- package/dist/core/semanticContexts.js +454 -0
- package/dist/core/semanticContexts.js.map +1 -0
- package/docs/es/guide/adapters.md +143 -0
- package/docs/es/guide/ai-repository-schema.md +119 -0
- package/docs/es/guide/features.md +67 -0
- package/docs/es/guide/flows.md +134 -0
- package/docs/es/guide/git-intelligence.md +170 -0
- package/docs/es/guide/incremental-analysis.md +131 -0
- package/docs/es/guide/knowledge-graph.md +135 -0
- package/docs/es/guide/lazy-indexing.md +144 -0
- package/docs/es/guide/performance.md +125 -0
- package/docs/guide/adapters.md +225 -0
- package/docs/guide/ai-repository-schema.md +119 -0
- package/docs/guide/architecture.md +69 -1
- package/docs/guide/flows.md +134 -0
- package/docs/guide/git-intelligence.md +170 -0
- package/docs/guide/incremental-analysis.md +131 -0
- package/docs/guide/knowledge-graph.md +135 -0
- package/docs/guide/lazy-indexing.md +144 -0
- package/docs/guide/performance.md +125 -0
- package/package.json +6 -3
- package/src/analyzers/androidResources.ts +113 -0
- package/src/analyzers/dependencies.ts +41 -0
- package/src/analyzers/entrypoints.ts +80 -1
- package/src/analyzers/gradleModules.ts +100 -0
- package/src/analyzers/techStack.ts +56 -0
- package/src/commands/ai-first.ts +342 -1
- package/src/core/adapters/adapterRegistry.ts +187 -0
- package/src/core/adapters/baseAdapter.ts +82 -0
- package/src/core/adapters/community/fastapiAdapter.ts +50 -0
- package/src/core/adapters/community/index.ts +11 -0
- package/src/core/adapters/community/laravelAdapter.ts +56 -0
- package/src/core/adapters/community/nestjsAdapter.ts +57 -0
- package/src/core/adapters/community/phoenixAdapter.ts +54 -0
- package/src/core/adapters/community/springBootAdapter.ts +53 -0
- package/src/core/adapters/dotnetAdapter.ts +104 -0
- package/src/core/adapters/index.ts +24 -0
- package/src/core/adapters/javascriptAdapter.ts +56 -0
- package/src/core/adapters/pythonAdapter.ts +118 -0
- package/src/core/adapters/railsAdapter.ts +65 -0
- package/src/core/adapters/salesforceAdapter.ts +76 -0
- package/src/core/adapters/sdk.ts +172 -0
- package/src/core/ccp.ts +240 -0
- package/src/core/gitAnalyzer.ts +391 -0
- package/src/core/incrementalAnalyzer.ts +382 -0
- package/src/core/knowledgeGraphBuilder.ts +181 -0
- package/src/core/lazyAnalyzer.ts +261 -0
- package/src/core/schema.ts +157 -0
- package/src/core/semanticContexts.ts +575 -0
- package/tests/adapters.test.ts +159 -0
- package/tests/gitAnalyzer.test.ts +133 -0
- package/tests/incrementalAnalyzer.test.ts +83 -0
- package/tests/knowledgeGraph.test.ts +146 -0
- package/tests/lazyAnalyzer.test.ts +230 -0
- package/tests/schema.test.ts +203 -0
- package/tests/semanticContexts.test.ts +435 -0
- package/ai/context/analyzers.Symbol.json +0 -19
- package/ai/context/analyzers.extractSymbols.json +0 -19
package/src/commands/ai-first.ts
CHANGED
|
@@ -18,8 +18,17 @@ import { generateModuleGraph } from "../core/moduleGraph.js";
|
|
|
18
18
|
import { loadIndexState, computeFileHash, getFilesToIndex, getChangedFilesGit } from "../core/indexState.js";
|
|
19
19
|
import { chunkFiles } from "../core/chunker.js";
|
|
20
20
|
import { generateEmbeddings, saveEmbeddings } from "../core/embeddings.js";
|
|
21
|
+
import { generateContextModules, createCCP, listCCPs, getCCP } from "../core/ccp.js";
|
|
22
|
+
import { generateSemanticContexts } from "../core/semanticContexts.js";
|
|
21
23
|
import { doctorMain } from "./doctor.js";
|
|
22
24
|
import { exploreMain } from "./explore.js";
|
|
25
|
+
import { listAdapters } from "../core/adapters/index.js";
|
|
26
|
+
import { detectGitRepository, generateGitContext, analyzeGitActivity, getRecentFiles } from "../core/gitAnalyzer.js";
|
|
27
|
+
import { buildKnowledgeGraph, loadKnowledgeGraph } from "../core/knowledgeGraphBuilder.js";
|
|
28
|
+
import { runIncrementalUpdate, detectChangedFiles } from "../core/incrementalAnalyzer.js";
|
|
29
|
+
import { generateAllSchema } from "../core/schema.js";
|
|
30
|
+
import ora from "ora";
|
|
31
|
+
import process from "process";
|
|
23
32
|
|
|
24
33
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
34
|
const __dirname = path.dirname(__filename);
|
|
@@ -147,6 +156,26 @@ export async function runAIFirst(options: AIFirstOptions = {}): Promise<AIFirstR
|
|
|
147
156
|
filesCreated.push(aiContextPath);
|
|
148
157
|
console.log(" ✅ Created ai_context.md");
|
|
149
158
|
|
|
159
|
+
// Generate semantic contexts (features and flows)
|
|
160
|
+
try {
|
|
161
|
+
const { features, flows } = generateSemanticContexts(outputDir);
|
|
162
|
+
console.log(` ✅ Created ${features.length} features, ${flows.length} flows`);
|
|
163
|
+
} catch (e: any) {
|
|
164
|
+
console.log(" ⚠️ Semantic contexts: " + (e.message || e));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Generate AI Repository Schema (schema.json, project.json, tools.json)
|
|
168
|
+
try {
|
|
169
|
+
generateAllSchema(rootDir, outputDir);
|
|
170
|
+
console.log(" ✅ Created schema.json, project.json, tools.json");
|
|
171
|
+
} catch (e: any) {
|
|
172
|
+
console.log(" ⚠️ Schema generation: " + (e.message || e));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
console.log("\n✨ Done! Created the following files:");
|
|
176
|
+
|
|
177
|
+
console.log("\n✨ Done! Created the following files:");
|
|
178
|
+
|
|
150
179
|
console.log("\n✨ Done! Created the following files:");
|
|
151
180
|
for (const file of filesCreated) {
|
|
152
181
|
console.log(` - ${path.relative(rootDir, file)}`);
|
|
@@ -1016,6 +1045,9 @@ Commands:
|
|
|
1016
1045
|
doctor Check repository health and AI readiness
|
|
1017
1046
|
explore <module> Explore module dependencies
|
|
1018
1047
|
map Generate repository map (files, modules, graph)
|
|
1048
|
+
adapters List available adapters
|
|
1049
|
+
explore <module> Explore module dependencies
|
|
1050
|
+
map Generate repository map (files, modules, graph)
|
|
1019
1051
|
|
|
1020
1052
|
Options:
|
|
1021
1053
|
-r, --root <dir> Root directory to scan (default: current directory)
|
|
@@ -1080,12 +1112,321 @@ Options:
|
|
|
1080
1112
|
await generateSymbolGraph(rootDir, aiDir);
|
|
1081
1113
|
console.log(" ✅ symbol-graph.json");
|
|
1082
1114
|
|
|
1083
|
-
|
|
1115
|
+
// Generate semantic contexts (features and flows)
|
|
1116
|
+
const { features, flows } = generateSemanticContexts(aiDir);
|
|
1117
|
+
console.log(` ✅ Created ${features.length} features, ${flows.length} flows`);
|
|
1118
|
+
|
|
1084
1119
|
process.exit(0);
|
|
1085
1120
|
} else if (command === 'doctor') {
|
|
1086
1121
|
doctorMain(args.slice(1));
|
|
1087
1122
|
} else if (command === 'explore') {
|
|
1088
1123
|
exploreMain(args.slice(1));
|
|
1124
|
+
} else if (command === 'adapters') {
|
|
1125
|
+
// Adapters command - list available adapters
|
|
1126
|
+
args.shift();
|
|
1127
|
+
|
|
1128
|
+
const showJson = args.includes('--json');
|
|
1129
|
+
|
|
1130
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1131
|
+
console.log(`
|
|
1132
|
+
adapters - List available adapters
|
|
1133
|
+
|
|
1134
|
+
Usage: ai-first adapters [options]
|
|
1135
|
+
|
|
1136
|
+
Options:
|
|
1137
|
+
--json Output as JSON
|
|
1138
|
+
-h, --help Show help message
|
|
1139
|
+
|
|
1140
|
+
Examples:
|
|
1141
|
+
ai-first adapters
|
|
1142
|
+
ai-first adapters --json
|
|
1143
|
+
`);
|
|
1144
|
+
process.exit(0);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
const adapters = listAdapters();
|
|
1148
|
+
|
|
1149
|
+
if (showJson) {
|
|
1150
|
+
console.log(JSON.stringify(adapters, null, 2));
|
|
1151
|
+
} else {
|
|
1152
|
+
console.log("\n📦 Available adapters:\n");
|
|
1153
|
+
console.log("Name | Display Name");
|
|
1154
|
+
console.log("--------------------|-------------------");
|
|
1155
|
+
for (const adapter of adapters) {
|
|
1156
|
+
console.log(`${adapter.name.padEnd(18)}| ${adapter.displayName}`);
|
|
1157
|
+
}
|
|
1158
|
+
console.log(`\nTotal: ${adapters.length} adapters`);
|
|
1159
|
+
}
|
|
1160
|
+
process.exit(0);
|
|
1161
|
+
} else if (command === 'git') {
|
|
1162
|
+
// Git intelligence command
|
|
1163
|
+
args.shift();
|
|
1164
|
+
|
|
1165
|
+
let rootDir = process.cwd();
|
|
1166
|
+
let aiDir = path.join(rootDir, "ai");
|
|
1167
|
+
let limit = 50;
|
|
1168
|
+
let showActivity = false;
|
|
1169
|
+
let showJson = false;
|
|
1170
|
+
|
|
1171
|
+
for (let i = 0; i < args.length; i++) {
|
|
1172
|
+
const arg = args[i];
|
|
1173
|
+
switch (arg) {
|
|
1174
|
+
case "--root":
|
|
1175
|
+
case "-r":
|
|
1176
|
+
rootDir = args[++i];
|
|
1177
|
+
aiDir = path.join(rootDir, "ai");
|
|
1178
|
+
break;
|
|
1179
|
+
case "--limit":
|
|
1180
|
+
case "-n":
|
|
1181
|
+
limit = parseInt(args[++i], 10) || 50;
|
|
1182
|
+
break;
|
|
1183
|
+
case "--activity":
|
|
1184
|
+
case "-a":
|
|
1185
|
+
showActivity = true;
|
|
1186
|
+
break;
|
|
1187
|
+
case "--json":
|
|
1188
|
+
showJson = true;
|
|
1189
|
+
break;
|
|
1190
|
+
case "--help":
|
|
1191
|
+
case "-h":
|
|
1192
|
+
console.log(`
|
|
1193
|
+
git - Analyze recent git activity
|
|
1194
|
+
|
|
1195
|
+
Usage: ai-first git [options]
|
|
1196
|
+
|
|
1197
|
+
Options:
|
|
1198
|
+
-r, --root <dir> Root directory (default: current directory)
|
|
1199
|
+
-n, --limit <n> Number of commits to analyze (default: 50)
|
|
1200
|
+
-a, --activity Show commit activity details
|
|
1201
|
+
--json Output as JSON
|
|
1202
|
+
-h, --help Show help message
|
|
1203
|
+
|
|
1204
|
+
Examples:
|
|
1205
|
+
ai-first git
|
|
1206
|
+
ai-first git --limit 100
|
|
1207
|
+
ai-first git --activity
|
|
1208
|
+
`);
|
|
1209
|
+
process.exit(0);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
if (!detectGitRepository(rootDir)) {
|
|
1214
|
+
console.log("❌ Not a git repository");
|
|
1215
|
+
process.exit(1);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
console.log(`\n📊 Analyzing git activity in: ${rootDir}\n`);
|
|
1219
|
+
|
|
1220
|
+
const result = generateGitContext(rootDir, aiDir);
|
|
1221
|
+
|
|
1222
|
+
if (showJson) {
|
|
1223
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1224
|
+
} else {
|
|
1225
|
+
console.log("📁 Recent files:");
|
|
1226
|
+
for (const file of result.recentFiles.slice(0, 10)) {
|
|
1227
|
+
console.log(` - ${file}`);
|
|
1228
|
+
}
|
|
1229
|
+
if (result.recentFiles.length > 10) {
|
|
1230
|
+
console.log(` ... and ${result.recentFiles.length - 10} more`);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
if (result.recentFeatures.length > 0) {
|
|
1234
|
+
console.log("\n🎯 Recent features:");
|
|
1235
|
+
console.log(` ${result.recentFeatures.join(", ")}`);
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
if (result.recentFlows.length > 0) {
|
|
1239
|
+
console.log("\n🔄 Recent flows:");
|
|
1240
|
+
console.log(` ${result.recentFlows.join(", ")}`);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
if (showActivity && result.activity) {
|
|
1244
|
+
console.log("\n📈 Commit activity:");
|
|
1245
|
+
console.log(` Total commits: ${result.activity.totalCommits}`);
|
|
1246
|
+
console.log(` Date range: ${result.activity.dateRange.start.slice(0, 10)} - ${result.activity.dateRange.end.slice(0, 10)}`);
|
|
1247
|
+
|
|
1248
|
+
const topFiles = Object.entries(result.activity.files)
|
|
1249
|
+
.sort((a, b) => b[1] - a[1])
|
|
1250
|
+
.slice(0, 5);
|
|
1251
|
+
if (topFiles.length > 0) {
|
|
1252
|
+
console.log("\n Most changed files:");
|
|
1253
|
+
for (const [file, count] of topFiles) {
|
|
1254
|
+
console.log(` - ${file}: ${count} commits`);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
console.log("\n✅ Generated:");
|
|
1260
|
+
console.log(" - ai/git/recent-files.json");
|
|
1261
|
+
console.log(" - ai/git/recent-features.json");
|
|
1262
|
+
console.log(" - ai/git/recent-flows.json");
|
|
1263
|
+
if (result.activity) {
|
|
1264
|
+
console.log(" - ai/git/commit-activity.json");
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
process.exit(0);
|
|
1268
|
+
} else if (command === 'graph') {
|
|
1269
|
+
// Knowledge Graph command
|
|
1270
|
+
args.shift();
|
|
1271
|
+
|
|
1272
|
+
let rootDir = process.cwd();
|
|
1273
|
+
let aiDir = path.join(rootDir, "ai");
|
|
1274
|
+
let showJson = false;
|
|
1275
|
+
let showStats = false;
|
|
1276
|
+
|
|
1277
|
+
for (let i = 0; i < args.length; i++) {
|
|
1278
|
+
const arg = args[i];
|
|
1279
|
+
switch (arg) {
|
|
1280
|
+
case "--root":
|
|
1281
|
+
case "-r":
|
|
1282
|
+
rootDir = args[++i];
|
|
1283
|
+
aiDir = path.join(rootDir, "ai");
|
|
1284
|
+
break;
|
|
1285
|
+
case "--json":
|
|
1286
|
+
showJson = true;
|
|
1287
|
+
break;
|
|
1288
|
+
case "--stats":
|
|
1289
|
+
case "-s":
|
|
1290
|
+
showStats = true;
|
|
1291
|
+
break;
|
|
1292
|
+
case "--help":
|
|
1293
|
+
case "-h":
|
|
1294
|
+
console.log(`
|
|
1295
|
+
graph - Generate repository knowledge graph
|
|
1296
|
+
|
|
1297
|
+
Usage: ai-first graph [options]
|
|
1298
|
+
|
|
1299
|
+
Options:
|
|
1300
|
+
-r, --root <dir> Root directory (default: current directory)
|
|
1301
|
+
-s, --stats Show graph statistics
|
|
1302
|
+
--json Output as JSON
|
|
1303
|
+
-h, --help Show help message
|
|
1304
|
+
|
|
1305
|
+
Examples:
|
|
1306
|
+
ai-first graph
|
|
1307
|
+
ai-first graph --stats
|
|
1308
|
+
`);
|
|
1309
|
+
process.exit(0);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
if (!detectGitRepository(rootDir)) {
|
|
1314
|
+
console.log("❌ Not a git repository");
|
|
1315
|
+
process.exit(1);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
console.log(`\n🕸️ Building knowledge graph in: ${rootDir}\n`);
|
|
1319
|
+
|
|
1320
|
+
const graph = buildKnowledgeGraph(rootDir, aiDir);
|
|
1321
|
+
|
|
1322
|
+
if (showJson) {
|
|
1323
|
+
console.log(JSON.stringify(graph, null, 2));
|
|
1324
|
+
} else {
|
|
1325
|
+
console.log("📊 Graph Statistics:");
|
|
1326
|
+
console.log(` Nodes: ${graph.nodes.length}`);
|
|
1327
|
+
console.log(` Edges: ${graph.edges.length}`);
|
|
1328
|
+
console.log(` Sources: ${graph.metadata.sources.join(", ") || "none"}`);
|
|
1329
|
+
|
|
1330
|
+
const nodeTypes = graph.nodes.reduce((acc, n) => { acc[n.type] = (acc[n.type] || 0) + 1; return acc; }, {} as Record<string, number>);
|
|
1331
|
+
const edgeTypes = graph.edges.reduce((acc, e) => { acc[e.type] = (acc[e.type] || 0) + 1; return acc; }, {} as Record<string, number>);
|
|
1332
|
+
|
|
1333
|
+
console.log("\n📍 Node Types:");
|
|
1334
|
+
for (const [type, count] of Object.entries(nodeTypes)) {
|
|
1335
|
+
console.log(` ${type}: ${count}`);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
console.log("\n🔗 Edge Types:");
|
|
1339
|
+
for (const [type, count] of Object.entries(edgeTypes)) {
|
|
1340
|
+
console.log(` ${type}: ${count}`);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
console.log("\n✅ Generated:");
|
|
1344
|
+
console.log(" - ai/graph/knowledge-graph.json");
|
|
1345
|
+
}
|
|
1346
|
+
process.exit(0);
|
|
1347
|
+
} else if (command === 'update') {
|
|
1348
|
+
// Incremental update command
|
|
1349
|
+
args.shift();
|
|
1350
|
+
|
|
1351
|
+
let rootDir = process.cwd();
|
|
1352
|
+
let aiDir = path.join(rootDir, "ai");
|
|
1353
|
+
let useGit = true;
|
|
1354
|
+
let showJson = false;
|
|
1355
|
+
|
|
1356
|
+
for (let i = 0; i < args.length; i++) {
|
|
1357
|
+
const arg = args[i];
|
|
1358
|
+
switch (arg) {
|
|
1359
|
+
case "--root":
|
|
1360
|
+
case "-r":
|
|
1361
|
+
rootDir = args[++i];
|
|
1362
|
+
aiDir = path.join(rootDir, "ai");
|
|
1363
|
+
break;
|
|
1364
|
+
case "--no-git":
|
|
1365
|
+
useGit = false;
|
|
1366
|
+
break;
|
|
1367
|
+
case "--json":
|
|
1368
|
+
showJson = true;
|
|
1369
|
+
break;
|
|
1370
|
+
case "--help":
|
|
1371
|
+
case "-h":
|
|
1372
|
+
console.log(`
|
|
1373
|
+
update - Incrementally update repository context
|
|
1374
|
+
|
|
1375
|
+
Usage: ai-first update [options]
|
|
1376
|
+
|
|
1377
|
+
Options:
|
|
1378
|
+
-r, --root <dir> Root directory (default: current directory)
|
|
1379
|
+
--no-git Use filesystem timestamps instead of git
|
|
1380
|
+
--json Output as JSON
|
|
1381
|
+
-h, --help Show help message
|
|
1382
|
+
|
|
1383
|
+
Examples:
|
|
1384
|
+
ai-first update
|
|
1385
|
+
ai-first update --no-git
|
|
1386
|
+
`);
|
|
1387
|
+
process.exit(0);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if (!fs.existsSync(aiDir)) {
|
|
1392
|
+
console.log("❌ AI context not found. Run 'ai-first init' first.");
|
|
1393
|
+
process.exit(1);
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
console.log(`\n🔄 Running incremental update in: ${rootDir}\n`);
|
|
1397
|
+
|
|
1398
|
+
const result = runIncrementalUpdate(rootDir, aiDir);
|
|
1399
|
+
|
|
1400
|
+
if (result.errors.length > 0) {
|
|
1401
|
+
console.log("⚠️ Errors:");
|
|
1402
|
+
for (const error of result.errors) {
|
|
1403
|
+
console.log(` - ${error}`);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
if (showJson) {
|
|
1408
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1409
|
+
} else {
|
|
1410
|
+
console.log(`📁 Changed files: ${result.changedFiles.length}`);
|
|
1411
|
+
if (result.changedFiles.length > 0) {
|
|
1412
|
+
for (const file of result.changedFiles.slice(0, 5)) {
|
|
1413
|
+
console.log(` ${file.status}: ${file.path}`);
|
|
1414
|
+
}
|
|
1415
|
+
if (result.changedFiles.length > 5) {
|
|
1416
|
+
console.log(` ... and ${result.changedFiles.length - 5} more`);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
console.log(`\n🔧 Updated:`);
|
|
1421
|
+
console.log(` Symbols: ${result.updatedSymbols}`);
|
|
1422
|
+
console.log(` Dependencies: ${result.updatedDependencies}`);
|
|
1423
|
+
console.log(` Features: ${result.updatedFeatures.join(", ") || "none"}`);
|
|
1424
|
+
console.log(` Flows: ${result.updatedFlows.join(", ") || "none"}`);
|
|
1425
|
+
console.log(` Knowledge Graph: ${result.graphUpdated ? "✅" : "❌"}`);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
process.exit(0);
|
|
1429
|
+
process.exit(0);
|
|
1089
1430
|
} else {
|
|
1090
1431
|
console.log(`Unknown command: ${command}`);
|
|
1091
1432
|
console.log(`Use 'ai-first --help' for usage information`);
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { AnalysisAdapter, DEFAULT_ADAPTER } from "./baseAdapter.js";
|
|
4
|
+
import { javascriptAdapter } from "./javascriptAdapter.js";
|
|
5
|
+
import { pythonAdapter, djangoAdapter, flaskAdapter } from "./pythonAdapter.js";
|
|
6
|
+
import { railsAdapter, rubyAdapter } from "./railsAdapter.js";
|
|
7
|
+
import { salesforceAdapter, sfdxAdapter } from "./salesforceAdapter.js";
|
|
8
|
+
import { dotnetAdapter, aspnetCoreAdapter, blazorAdapter } from "./dotnetAdapter.js";
|
|
9
|
+
import { laravelAdapter, nestjsAdapter, springBootAdapter, phoenixAdapter, fastapiAdapter } from "./community/index.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Registry of all available adapters
|
|
13
|
+
*/
|
|
14
|
+
export const ADAPTERS: AnalysisAdapter[] = [
|
|
15
|
+
// JavaScript/TypeScript
|
|
16
|
+
javascriptAdapter,
|
|
17
|
+
nestjsAdapter,
|
|
18
|
+
|
|
19
|
+
// Ruby (must be before Python to detect Gemfile correctly)
|
|
20
|
+
railsAdapter,
|
|
21
|
+
rubyAdapter,
|
|
22
|
+
|
|
23
|
+
// Python
|
|
24
|
+
djangoAdapter,
|
|
25
|
+
flaskAdapter,
|
|
26
|
+
pythonAdapter,
|
|
27
|
+
fastapiAdapter,
|
|
28
|
+
|
|
29
|
+
// PHP
|
|
30
|
+
laravelAdapter,
|
|
31
|
+
|
|
32
|
+
// Elixir
|
|
33
|
+
phoenixAdapter,
|
|
34
|
+
|
|
35
|
+
// Java/Kotlin
|
|
36
|
+
springBootAdapter,
|
|
37
|
+
|
|
38
|
+
// Salesforce
|
|
39
|
+
sfdxAdapter,
|
|
40
|
+
salesforceAdapter,
|
|
41
|
+
|
|
42
|
+
// .NET
|
|
43
|
+
blazorAdapter,
|
|
44
|
+
aspnetCoreAdapter,
|
|
45
|
+
dotnetAdapter
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Adapter detection result
|
|
50
|
+
*/
|
|
51
|
+
export interface AdapterDetectionResult {
|
|
52
|
+
adapter: AnalysisAdapter;
|
|
53
|
+
confidence: number;
|
|
54
|
+
matchedSignals: string[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Detect the appropriate adapter for a project
|
|
59
|
+
*
|
|
60
|
+
* @param rootDir - Project root directory
|
|
61
|
+
* @returns The best matching adapter
|
|
62
|
+
*/
|
|
63
|
+
export function detectAdapter(rootDir: string): AnalysisAdapter {
|
|
64
|
+
const results = detectAllAdapters(rootDir);
|
|
65
|
+
|
|
66
|
+
if (results.length === 0) {
|
|
67
|
+
return DEFAULT_ADAPTER;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Return the adapter with highest confidence
|
|
71
|
+
return results[0].adapter;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Detect all matching adapters with confidence scores
|
|
76
|
+
*
|
|
77
|
+
* @param rootDir - Project root directory
|
|
78
|
+
* @returns Array of matching adapters sorted by confidence
|
|
79
|
+
*/
|
|
80
|
+
export function detectAllAdapters(rootDir: string): AdapterDetectionResult[] {
|
|
81
|
+
const results: AdapterDetectionResult[] = [];
|
|
82
|
+
|
|
83
|
+
for (const adapter of ADAPTERS) {
|
|
84
|
+
const matchedSignals: string[] = [];
|
|
85
|
+
let score = 0;
|
|
86
|
+
|
|
87
|
+
for (const signal of adapter.detectionSignals) {
|
|
88
|
+
const matched = matchSignal(rootDir, signal);
|
|
89
|
+
if (matched) {
|
|
90
|
+
matchedSignals.push(signal.pattern);
|
|
91
|
+
score += getSignalWeight(signal);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (score > 0) {
|
|
96
|
+
results.push({
|
|
97
|
+
adapter,
|
|
98
|
+
confidence: score,
|
|
99
|
+
matchedSignals
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Sort by confidence (highest first)
|
|
105
|
+
results.sort((a, b) => b.confidence - a.confidence);
|
|
106
|
+
|
|
107
|
+
return results;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Match a detection signal against the project
|
|
112
|
+
*/
|
|
113
|
+
function matchSignal(rootDir: string, signal: { type: string; pattern: string; contentPattern?: string }): boolean {
|
|
114
|
+
switch (signal.type) {
|
|
115
|
+
case 'file':
|
|
116
|
+
return matchFileSignal(rootDir, signal.pattern);
|
|
117
|
+
|
|
118
|
+
case 'directory':
|
|
119
|
+
return matchDirectorySignal(rootDir, signal.pattern);
|
|
120
|
+
|
|
121
|
+
case 'content':
|
|
122
|
+
// Content signals require more complex implementation
|
|
123
|
+
// For now, we skip content-based detection
|
|
124
|
+
return false;
|
|
125
|
+
|
|
126
|
+
default:
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Match a file signal
|
|
133
|
+
*/
|
|
134
|
+
function matchFileSignal(rootDir: string, pattern: string): boolean {
|
|
135
|
+
// Simple glob support for *.csproj style patterns
|
|
136
|
+
if (pattern.startsWith('*')) {
|
|
137
|
+
const ext = pattern.slice(1);
|
|
138
|
+
if (!fs.existsSync(rootDir)) return false;
|
|
139
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
|
140
|
+
return entries.some(e => e.isFile() && e.name.endsWith(ext));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return fs.existsSync(path.join(rootDir, pattern));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Match a directory signal
|
|
148
|
+
*/
|
|
149
|
+
function matchDirectorySignal(rootDir: string, pattern: string): boolean {
|
|
150
|
+
if (!fs.existsSync(rootDir)) return false;
|
|
151
|
+
|
|
152
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
|
153
|
+
return entries.some(e => e.isDirectory() && e.name === pattern);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get weight for a signal type
|
|
158
|
+
*/
|
|
159
|
+
function getSignalWeight(signal: { type: string; pattern: string }): number {
|
|
160
|
+
// Higher weight for more specific signals
|
|
161
|
+
switch (signal.type) {
|
|
162
|
+
case 'content':
|
|
163
|
+
return 3;
|
|
164
|
+
case 'directory':
|
|
165
|
+
return 2;
|
|
166
|
+
case 'file':
|
|
167
|
+
default:
|
|
168
|
+
// Higher weight for more specific file patterns
|
|
169
|
+
if (signal.pattern.startsWith('*')) return 1;
|
|
170
|
+
if (signal.pattern.includes('.')) return 2;
|
|
171
|
+
return 1;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get adapter by name
|
|
177
|
+
*/
|
|
178
|
+
export function getAdapter(name: string): AnalysisAdapter | undefined {
|
|
179
|
+
return ADAPTERS.find(a => a.name === name);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* List all available adapters
|
|
184
|
+
*/
|
|
185
|
+
export function listAdapters(): { name: string; displayName: string }[] {
|
|
186
|
+
return ADAPTERS.map(a => ({ name: a.name, displayName: a.displayName }));
|
|
187
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis Adapter Interface
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for language/framework-specific adapters
|
|
5
|
+
* that customize feature and flow detection.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface AnalysisAdapter {
|
|
9
|
+
/** Unique identifier for the adapter */
|
|
10
|
+
name: string;
|
|
11
|
+
|
|
12
|
+
/** Human-readable display name */
|
|
13
|
+
displayName: string;
|
|
14
|
+
|
|
15
|
+
/** File/directory markers that indicate this adapter should be used */
|
|
16
|
+
detectionSignals: DetectionSignal[];
|
|
17
|
+
|
|
18
|
+
/** Root directories to scan for features */
|
|
19
|
+
featureRoots: string[];
|
|
20
|
+
|
|
21
|
+
/** Folders to ignore when detecting features */
|
|
22
|
+
ignoredFolders: string[];
|
|
23
|
+
|
|
24
|
+
/** File name patterns that indicate entrypoints */
|
|
25
|
+
entrypointPatterns: string[];
|
|
26
|
+
|
|
27
|
+
/** Layer definitions for flow detection */
|
|
28
|
+
layerRules: LayerRule[];
|
|
29
|
+
|
|
30
|
+
/** Additional file extensions to include */
|
|
31
|
+
supportedExtensions: string[];
|
|
32
|
+
|
|
33
|
+
/** Patterns for flow entrypoints */
|
|
34
|
+
flowEntrypointPatterns: string[];
|
|
35
|
+
|
|
36
|
+
/** Patterns to exclude from flows */
|
|
37
|
+
flowExcludePatterns: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DetectionSignal {
|
|
41
|
+
/** Type of signal */
|
|
42
|
+
type: 'file' | 'directory' | 'content';
|
|
43
|
+
|
|
44
|
+
/** Pattern to match */
|
|
45
|
+
pattern: string;
|
|
46
|
+
|
|
47
|
+
/** Optional: content to match inside file */
|
|
48
|
+
contentPattern?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface LayerRule {
|
|
52
|
+
/** Layer name */
|
|
53
|
+
name: string;
|
|
54
|
+
|
|
55
|
+
/** Priority (lower = earlier in flow) */
|
|
56
|
+
priority: number;
|
|
57
|
+
|
|
58
|
+
/** Patterns that identify this layer */
|
|
59
|
+
patterns: string[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Default adapter configuration
|
|
64
|
+
*/
|
|
65
|
+
export const DEFAULT_ADAPTER: AnalysisAdapter = {
|
|
66
|
+
name: 'default',
|
|
67
|
+
displayName: 'Default',
|
|
68
|
+
detectionSignals: [],
|
|
69
|
+
featureRoots: ['src', 'app', 'lib', 'modules'],
|
|
70
|
+
ignoredFolders: ['utils', 'helpers', 'types', 'interfaces', 'constants', 'config', 'dto', 'models', 'common', 'shared', 'node_modules', '.git'],
|
|
71
|
+
entrypointPatterns: ['controller', 'route', 'handler', 'command', 'service'],
|
|
72
|
+
layerRules: [
|
|
73
|
+
{ name: 'api', priority: 1, patterns: ['controller', 'handler', 'route', 'router', 'api', 'endpoint'] },
|
|
74
|
+
{ name: 'service', priority: 2, patterns: ['service', 'services', 'usecase', 'interactor'] },
|
|
75
|
+
{ name: 'data', priority: 3, patterns: ['repository', 'repo', 'dal', 'dao', 'data', 'persistence'] },
|
|
76
|
+
{ name: 'domain', priority: 4, patterns: ['model', 'entity', 'schema', 'domain'] },
|
|
77
|
+
{ name: 'util', priority: 5, patterns: ['util', 'helper', 'lib', 'common'] }
|
|
78
|
+
],
|
|
79
|
+
supportedExtensions: ['.ts', '.tsx', '.js', '.jsx', '.py', '.java', '.kt', '.go', '.rs', '.rb', '.php', '.cs', '.vue', '.svelte'],
|
|
80
|
+
flowEntrypointPatterns: ['controller', 'route', 'handler', 'command'],
|
|
81
|
+
flowExcludePatterns: ['repository', 'repo', 'utils', 'helper', 'model', 'entity', 'dto', 'type', 'interface', 'constant', 'config']
|
|
82
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FastAPI Adapter
|
|
3
|
+
*
|
|
4
|
+
* Community adapter for Python FastAPI projects
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAdapter, fileSignal, directorySignal, layerRule } from '../sdk.js';
|
|
8
|
+
|
|
9
|
+
export const fastapiAdapter = createAdapter({
|
|
10
|
+
name: 'fastapi',
|
|
11
|
+
displayName: 'FastAPI',
|
|
12
|
+
|
|
13
|
+
detectionSignals: [
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
featureRoots: [
|
|
17
|
+
'app',
|
|
18
|
+
'app/api',
|
|
19
|
+
'app/services',
|
|
20
|
+
'app/models',
|
|
21
|
+
'app/schemas'
|
|
22
|
+
],
|
|
23
|
+
|
|
24
|
+
ignoredFolders: [
|
|
25
|
+
'venv', '.venv', '__pycache__', '.git',
|
|
26
|
+
'tests', 'test', '.pytest_cache', 'docs'
|
|
27
|
+
],
|
|
28
|
+
|
|
29
|
+
entrypointPatterns: [
|
|
30
|
+
'router', 'APIRouter', 'endpoint', 'route',
|
|
31
|
+
'view', 'controller', 'service'
|
|
32
|
+
],
|
|
33
|
+
|
|
34
|
+
layerRules: [
|
|
35
|
+
layerRule('api', 1, ['router', 'APIRouter', 'endpoint', 'route', 'view']),
|
|
36
|
+
layerRule('service', 2, ['service', 'usecase', 'interactor', 'business']),
|
|
37
|
+
layerRule('data', 3, ['model', 'schema', 'repository', 'dao']),
|
|
38
|
+
layerRule('domain', 4, ['entity', 'schema', 'domain']),
|
|
39
|
+
layerRule('util', 5, ['util', 'helper', 'lib', 'core'])
|
|
40
|
+
],
|
|
41
|
+
|
|
42
|
+
supportedExtensions: ['.py'],
|
|
43
|
+
|
|
44
|
+
flowEntrypointPatterns: ['router', 'APIRouter', 'endpoint', 'route'],
|
|
45
|
+
|
|
46
|
+
flowExcludePatterns: [
|
|
47
|
+
'model', 'schema', 'repository', 'test', 'tests',
|
|
48
|
+
'__pycache__', 'conftest'
|
|
49
|
+
]
|
|
50
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Community Adapters
|
|
3
|
+
*
|
|
4
|
+
* Community-contributed adapters for various frameworks
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { laravelAdapter } from './laravelAdapter.js';
|
|
8
|
+
export { nestjsAdapter } from './nestjsAdapter.js';
|
|
9
|
+
export { springBootAdapter } from './springBootAdapter.js';
|
|
10
|
+
export { phoenixAdapter } from './phoenixAdapter.js';
|
|
11
|
+
export { fastapiAdapter } from './fastapiAdapter.js';
|