@codexa/cli 8.5.0

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.
@@ -0,0 +1,351 @@
1
+ /**
2
+ * Flutter/Dart Ecosystem Detector
3
+ *
4
+ * Detects Flutter and Dart projects including:
5
+ * - Flutter (Mobile, Web, Desktop)
6
+ * - Dart CLI/Server applications
7
+ * - State management: Riverpod, Bloc, Provider, GetX
8
+ * - Testing: flutter_test, mockito
9
+ */
10
+
11
+ import { join } from "path";
12
+ import {
13
+ registerDetector,
14
+ Detector,
15
+ DetectorResult,
16
+ DetectedTechnology,
17
+ fileExists,
18
+ dirExists,
19
+ findFiles,
20
+ readText,
21
+ parseYaml,
22
+ } from "./index";
23
+
24
+ interface PubspecYaml {
25
+ name?: string;
26
+ version?: string;
27
+ environment?: {
28
+ sdk?: string;
29
+ flutter?: string;
30
+ };
31
+ dependencies?: Record<string, any>;
32
+ dev_dependencies?: Record<string, any>;
33
+ flutter?: {
34
+ uses_material_design?: boolean;
35
+ assets?: string[];
36
+ fonts?: any[];
37
+ };
38
+ }
39
+
40
+ const flutterDetector: Detector = {
41
+ name: "flutter",
42
+ ecosystem: "flutter",
43
+ priority: 82,
44
+ markers: [
45
+ { type: "file", pattern: "pubspec.yaml", weight: 1.0 },
46
+ { type: "file", pattern: "pubspec.lock", weight: 0.9 },
47
+ { type: "file", pattern: ".flutter-plugins", weight: 0.8 },
48
+ { type: "file", pattern: ".flutter-plugins-dependencies", weight: 0.8 },
49
+ { type: "directory", pattern: "android", weight: 0.6 },
50
+ { type: "directory", pattern: "ios", weight: 0.6 },
51
+ { type: "directory", pattern: "lib", weight: 0.5 },
52
+ { type: "glob", pattern: "**/*.dart", weight: 0.7 },
53
+ ],
54
+
55
+ async detect(cwd: string): Promise<DetectorResult | null> {
56
+ const technologies: DetectedTechnology[] = [];
57
+ const structure: Record<string, string> = {};
58
+ const configFiles: string[] = [];
59
+
60
+ // Check for pubspec.yaml
61
+ const pubspecPath = join(cwd, "pubspec.yaml");
62
+ if (!fileExists(pubspecPath)) {
63
+ // Check for Dart files without pubspec
64
+ const dartFiles = findFiles(cwd, "**/*.dart");
65
+ if (dartFiles.length === 0) return null;
66
+
67
+ technologies.push({
68
+ name: "Dart",
69
+ confidence: 0.6,
70
+ source: "*.dart files (no pubspec)",
71
+ category: "runtime",
72
+ });
73
+
74
+ return { ecosystem: "flutter", technologies, structure, configFiles };
75
+ }
76
+
77
+ configFiles.push("pubspec.yaml");
78
+ if (fileExists(join(cwd, "pubspec.lock"))) configFiles.push("pubspec.lock");
79
+
80
+ const pubspecContent = readText(pubspecPath);
81
+ if (!pubspecContent) return null;
82
+
83
+ const pubspec = parseYaml(pubspecContent) as PubspecYaml;
84
+
85
+ // Collect all dependencies
86
+ const allDeps = new Map<string, any>();
87
+ const addDeps = (deps: Record<string, any> | undefined) => {
88
+ if (!deps) return;
89
+ for (const [name, value] of Object.entries(deps)) {
90
+ allDeps.set(name, value);
91
+ }
92
+ };
93
+
94
+ addDeps(pubspec.dependencies);
95
+ addDeps(pubspec.dev_dependencies);
96
+
97
+ // Detect if Flutter or pure Dart
98
+ const isFlutter = allDeps.has("flutter") || pubspec.flutter !== undefined;
99
+
100
+ if (isFlutter) {
101
+ technologies.push({
102
+ name: "Flutter",
103
+ version: pubspec.environment?.flutter,
104
+ confidence: 1.0,
105
+ source: "pubspec.yaml",
106
+ category: "frontend",
107
+ });
108
+
109
+ // Detect platforms
110
+ const platforms: string[] = [];
111
+ if (dirExists(join(cwd, "android"))) platforms.push("Android");
112
+ if (dirExists(join(cwd, "ios"))) platforms.push("iOS");
113
+ if (dirExists(join(cwd, "web"))) platforms.push("Web");
114
+ if (dirExists(join(cwd, "macos"))) platforms.push("macOS");
115
+ if (dirExists(join(cwd, "windows"))) platforms.push("Windows");
116
+ if (dirExists(join(cwd, "linux"))) platforms.push("Linux");
117
+
118
+ if (platforms.length > 0) {
119
+ technologies.push({
120
+ name: `Flutter (${platforms.join(", ")})`,
121
+ confidence: 0.95,
122
+ source: "Platform directories",
123
+ category: "frontend",
124
+ metadata: { platforms },
125
+ });
126
+ }
127
+ }
128
+
129
+ // Add Dart runtime
130
+ technologies.push({
131
+ name: "Dart",
132
+ version: pubspec.environment?.sdk,
133
+ confidence: 1.0,
134
+ source: "pubspec.yaml",
135
+ category: "runtime",
136
+ });
137
+
138
+ // State Management Detection
139
+ const stateManagement = [
140
+ { deps: ["flutter_riverpod", "riverpod", "hooks_riverpod"], name: "Riverpod", confidence: 1.0 },
141
+ { deps: ["flutter_bloc", "bloc"], name: "Bloc", confidence: 1.0 },
142
+ { deps: ["provider"], name: "Provider", confidence: 1.0 },
143
+ { deps: ["get", "get_it"], name: "GetX", confidence: 1.0 },
144
+ { deps: ["mobx", "flutter_mobx"], name: "MobX", confidence: 1.0 },
145
+ { deps: ["redux", "flutter_redux"], name: "Redux", confidence: 1.0 },
146
+ { deps: ["stacked"], name: "Stacked", confidence: 1.0 },
147
+ ];
148
+
149
+ for (const sm of stateManagement) {
150
+ const found = sm.deps.find(d => allDeps.has(d));
151
+ if (found) {
152
+ technologies.push({
153
+ name: sm.name,
154
+ confidence: sm.confidence,
155
+ source: `Dependency: ${found}`,
156
+ category: "frontend",
157
+ metadata: { type: "state-management" },
158
+ });
159
+ }
160
+ }
161
+
162
+ // Backend/API Libraries
163
+ const apiLibs = [
164
+ { deps: ["dio"], name: "Dio", confidence: 1.0 },
165
+ { deps: ["http"], name: "HTTP", confidence: 0.9 },
166
+ { deps: ["chopper"], name: "Chopper", confidence: 1.0 },
167
+ { deps: ["retrofit"], name: "Retrofit", confidence: 1.0 },
168
+ { deps: ["graphql_flutter", "graphql"], name: "GraphQL", confidence: 1.0 },
169
+ ];
170
+
171
+ for (const lib of apiLibs) {
172
+ const found = lib.deps.find(d => allDeps.has(d));
173
+ if (found) {
174
+ technologies.push({
175
+ name: lib.name,
176
+ confidence: lib.confidence,
177
+ source: `Dependency: ${found}`,
178
+ category: "backend",
179
+ metadata: { type: "http-client" },
180
+ });
181
+ }
182
+ }
183
+
184
+ // Database/Storage Detection
185
+ const databases = [
186
+ { deps: ["sqflite"], name: "SQFlite (SQLite)", confidence: 1.0 },
187
+ { deps: ["hive", "hive_flutter"], name: "Hive", confidence: 1.0 },
188
+ { deps: ["isar", "isar_flutter_libs"], name: "Isar", confidence: 1.0 },
189
+ { deps: ["moor", "drift"], name: "Drift (Moor)", confidence: 1.0 },
190
+ { deps: ["objectbox"], name: "ObjectBox", confidence: 1.0 },
191
+ { deps: ["shared_preferences"], name: "SharedPreferences", confidence: 0.9 },
192
+ { deps: ["firebase_core", "cloud_firestore"], name: "Firebase/Firestore", confidence: 1.0 },
193
+ { deps: ["supabase_flutter", "supabase"], name: "Supabase", confidence: 1.0 },
194
+ { deps: ["appwrite"], name: "Appwrite", confidence: 1.0 },
195
+ ];
196
+
197
+ const detectedDbs = new Set<string>();
198
+ for (const db of databases) {
199
+ const found = db.deps.find(d => allDeps.has(d));
200
+ if (found && !detectedDbs.has(db.name)) {
201
+ technologies.push({
202
+ name: db.name,
203
+ confidence: db.confidence,
204
+ source: `Dependency: ${found}`,
205
+ category: "database",
206
+ });
207
+ detectedDbs.add(db.name);
208
+ }
209
+ }
210
+
211
+ // Auth Detection
212
+ const authProviders = [
213
+ { deps: ["firebase_auth"], name: "Firebase Auth", confidence: 1.0 },
214
+ { deps: ["supabase_auth_ui"], name: "Supabase Auth", confidence: 1.0 },
215
+ { deps: ["google_sign_in"], name: "Google Sign-In", confidence: 0.9 },
216
+ { deps: ["sign_in_with_apple"], name: "Sign in with Apple", confidence: 0.9 },
217
+ { deps: ["flutter_facebook_auth"], name: "Facebook Auth", confidence: 0.9 },
218
+ { deps: ["flutter_appauth"], name: "AppAuth", confidence: 1.0 },
219
+ ];
220
+
221
+ for (const auth of authProviders) {
222
+ const found = auth.deps.find(d => allDeps.has(d));
223
+ if (found) {
224
+ technologies.push({
225
+ name: auth.name,
226
+ confidence: auth.confidence,
227
+ source: `Dependency: ${found}`,
228
+ category: "auth",
229
+ });
230
+ }
231
+ }
232
+
233
+ // Testing Detection
234
+ const testingTools = [
235
+ { deps: ["flutter_test"], name: "Flutter Test", confidence: 1.0 },
236
+ { deps: ["test"], name: "Dart Test", confidence: 0.95 },
237
+ { deps: ["mockito"], name: "Mockito", confidence: 0.95 },
238
+ { deps: ["mocktail"], name: "Mocktail", confidence: 0.95 },
239
+ { deps: ["bloc_test"], name: "Bloc Test", confidence: 0.95 },
240
+ { deps: ["golden_toolkit"], name: "Golden Toolkit", confidence: 0.9 },
241
+ { deps: ["integration_test"], name: "Integration Test", confidence: 0.95 },
242
+ ];
243
+
244
+ for (const test of testingTools) {
245
+ const found = test.deps.find(d => allDeps.has(d));
246
+ if (found) {
247
+ technologies.push({
248
+ name: test.name,
249
+ confidence: test.confidence,
250
+ source: `Dependency: ${found}`,
251
+ category: "testing",
252
+ });
253
+ }
254
+ }
255
+
256
+ // Navigation/Routing
257
+ const navigation = [
258
+ { deps: ["go_router"], name: "GoRouter", confidence: 1.0 },
259
+ { deps: ["auto_route"], name: "AutoRoute", confidence: 1.0 },
260
+ { deps: ["beamer"], name: "Beamer", confidence: 1.0 },
261
+ { deps: ["routemaster"], name: "Routemaster", confidence: 1.0 },
262
+ ];
263
+
264
+ for (const nav of navigation) {
265
+ const found = nav.deps.find(d => allDeps.has(d));
266
+ if (found) {
267
+ technologies.push({
268
+ name: nav.name,
269
+ confidence: nav.confidence,
270
+ source: `Dependency: ${found}`,
271
+ category: "frontend",
272
+ metadata: { type: "routing" },
273
+ });
274
+ }
275
+ }
276
+
277
+ // Code Generation
278
+ const codeGen = [
279
+ { deps: ["freezed", "freezed_annotation"], name: "Freezed", confidence: 1.0 },
280
+ { deps: ["json_serializable"], name: "JSON Serializable", confidence: 0.95 },
281
+ { deps: ["build_runner"], name: "Build Runner", confidence: 0.9 },
282
+ { deps: ["injectable"], name: "Injectable", confidence: 1.0 },
283
+ ];
284
+
285
+ for (const gen of codeGen) {
286
+ const found = gen.deps.find(d => allDeps.has(d));
287
+ if (found) {
288
+ technologies.push({
289
+ name: gen.name,
290
+ confidence: gen.confidence,
291
+ source: `Dependency: ${found}`,
292
+ category: "build",
293
+ });
294
+ }
295
+ }
296
+
297
+ // Structure detection
298
+ const structurePaths = [
299
+ { key: "lib", paths: ["lib"] },
300
+ { key: "screens", paths: ["lib/screens", "lib/pages", "lib/views", "lib/presentation/screens"] },
301
+ { key: "widgets", paths: ["lib/widgets", "lib/components", "lib/presentation/widgets"] },
302
+ { key: "models", paths: ["lib/models", "lib/domain/models", "lib/data/models"] },
303
+ { key: "services", paths: ["lib/services", "lib/data/services"] },
304
+ { key: "providers", paths: ["lib/providers", "lib/riverpod", "lib/blocs"] },
305
+ { key: "repositories", paths: ["lib/repositories", "lib/data/repositories"] },
306
+ { key: "utils", paths: ["lib/utils", "lib/helpers", "lib/core/utils"] },
307
+ { key: "config", paths: ["lib/config", "lib/core/config"] },
308
+ { key: "test", paths: ["test"] },
309
+ { key: "integration_test", paths: ["integration_test"] },
310
+ ];
311
+
312
+ for (const { key, paths } of structurePaths) {
313
+ for (const p of paths) {
314
+ if (dirExists(join(cwd, p))) {
315
+ structure[key] = p;
316
+ break;
317
+ }
318
+ }
319
+ }
320
+
321
+ // Config files
322
+ const configPatterns = [
323
+ "analysis_options.yaml",
324
+ ".dart_tool/package_config.json",
325
+ "build.yaml",
326
+ "melos.yaml",
327
+ "firebase.json",
328
+ ".firebaserc",
329
+ "Podfile",
330
+ "android/build.gradle",
331
+ ];
332
+
333
+ for (const pattern of configPatterns) {
334
+ if (fileExists(join(cwd, pattern))) {
335
+ configFiles.push(pattern);
336
+ }
337
+ }
338
+
339
+ return {
340
+ ecosystem: "flutter",
341
+ technologies,
342
+ structure,
343
+ configFiles: [...new Set(configFiles)],
344
+ };
345
+ },
346
+ };
347
+
348
+ // Register the detector
349
+ registerDetector(flutterDetector);
350
+
351
+ export default flutterDetector;
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Go Ecosystem Detector
3
+ *
4
+ * Detects Go projects including:
5
+ * - Frameworks: Gin, Echo, Fiber, Chi, net/http
6
+ * - ORMs: GORM, Ent, SQLx, SQLC
7
+ * - Testing: built-in testing, testify, gomega
8
+ */
9
+
10
+ import { join } from "path";
11
+ import {
12
+ registerDetector,
13
+ Detector,
14
+ DetectorResult,
15
+ DetectedTechnology,
16
+ fileExists,
17
+ dirExists,
18
+ findFiles,
19
+ readText,
20
+ } from "./index";
21
+
22
+ interface GoMod {
23
+ module: string;
24
+ goVersion?: string;
25
+ require: { path: string; version: string }[];
26
+ }
27
+
28
+ function parseGoMod(content: string): GoMod {
29
+ const result: GoMod = { module: "", require: [] };
30
+
31
+ const moduleMatch = content.match(/^module\s+(.+)$/m);
32
+ if (moduleMatch) result.module = moduleMatch[1].trim();
33
+
34
+ const goMatch = content.match(/^go\s+(\d+\.\d+(?:\.\d+)?)$/m);
35
+ if (goMatch) result.goVersion = goMatch[1];
36
+
37
+ // Parse require block
38
+ const requireBlockMatch = content.match(/require\s*\(([\s\S]*?)\)/);
39
+ if (requireBlockMatch) {
40
+ const requireLines = requireBlockMatch[1].split("\n");
41
+ for (const line of requireLines) {
42
+ const match = line.trim().match(/^([^\s]+)\s+([^\s]+)/);
43
+ if (match && !match[0].startsWith("//")) {
44
+ result.require.push({ path: match[1], version: match[2] });
45
+ }
46
+ }
47
+ }
48
+
49
+ // Parse single-line requires
50
+ const singleRequires = content.matchAll(/^require\s+([^\s]+)\s+([^\s]+)$/gm);
51
+ for (const match of singleRequires) {
52
+ result.require.push({ path: match[1], version: match[2] });
53
+ }
54
+
55
+ return result;
56
+ }
57
+
58
+ const goDetector: Detector = {
59
+ name: "go",
60
+ ecosystem: "go",
61
+ priority: 80,
62
+ markers: [
63
+ { type: "file", pattern: "go.mod", weight: 1.0 },
64
+ { type: "file", pattern: "go.sum", weight: 0.9 },
65
+ { type: "file", pattern: "go.work", weight: 0.9 },
66
+ { type: "glob", pattern: "**/*.go", weight: 0.7 },
67
+ { type: "directory", pattern: "cmd", weight: 0.6 },
68
+ { type: "directory", pattern: "pkg", weight: 0.5 },
69
+ { type: "directory", pattern: "internal", weight: 0.5 },
70
+ ],
71
+
72
+ async detect(cwd: string): Promise<DetectorResult | null> {
73
+ const technologies: DetectedTechnology[] = [];
74
+ const structure: Record<string, string> = {};
75
+ const configFiles: string[] = [];
76
+
77
+ // Check for go.mod
78
+ const goModPath = join(cwd, "go.mod");
79
+ if (!fileExists(goModPath)) {
80
+ // Check for Go files without go.mod (legacy GOPATH)
81
+ const goFiles = findFiles(cwd, "**/*.go");
82
+ if (goFiles.length === 0) return null;
83
+
84
+ technologies.push({
85
+ name: "Go",
86
+ confidence: 0.7,
87
+ source: "*.go files (no go.mod)",
88
+ category: "runtime",
89
+ });
90
+
91
+ return { ecosystem: "go", technologies, structure, configFiles };
92
+ }
93
+
94
+ configFiles.push("go.mod");
95
+ if (fileExists(join(cwd, "go.sum"))) configFiles.push("go.sum");
96
+ if (fileExists(join(cwd, "go.work"))) {
97
+ configFiles.push("go.work");
98
+ technologies.push({
99
+ name: "Go Workspaces",
100
+ confidence: 1.0,
101
+ source: "go.work",
102
+ category: "build",
103
+ });
104
+ }
105
+
106
+ const goModContent = readText(goModPath);
107
+ if (!goModContent) return null;
108
+
109
+ const goMod = parseGoMod(goModContent);
110
+
111
+ // Add Go runtime
112
+ technologies.push({
113
+ name: "Go",
114
+ version: goMod.goVersion,
115
+ confidence: 1.0,
116
+ source: "go.mod",
117
+ category: "runtime",
118
+ });
119
+
120
+ // Create dependency lookup
121
+ const deps = new Map<string, string>();
122
+ for (const req of goMod.require) {
123
+ deps.set(req.path, req.version);
124
+ }
125
+
126
+ // Web Framework Detection
127
+ const webFrameworks = [
128
+ { paths: ["github.com/gin-gonic/gin"], name: "Gin", confidence: 1.0 },
129
+ { paths: ["github.com/labstack/echo/v4", "github.com/labstack/echo"], name: "Echo", confidence: 1.0 },
130
+ { paths: ["github.com/gofiber/fiber/v2", "github.com/gofiber/fiber"], name: "Fiber", confidence: 1.0 },
131
+ { paths: ["github.com/go-chi/chi/v5", "github.com/go-chi/chi"], name: "Chi", confidence: 1.0 },
132
+ { paths: ["github.com/gorilla/mux"], name: "Gorilla Mux", confidence: 0.95 },
133
+ { paths: ["github.com/beego/beego/v2", "github.com/astaxie/beego"], name: "Beego", confidence: 1.0 },
134
+ { paths: ["github.com/kataras/iris/v12", "github.com/kataras/iris"], name: "Iris", confidence: 1.0 },
135
+ { paths: ["github.com/revel/revel"], name: "Revel", confidence: 1.0 },
136
+ { paths: ["github.com/valyala/fasthttp"], name: "FastHTTP", confidence: 0.9 },
137
+ { paths: ["github.com/cloudwego/hertz"], name: "Hertz", confidence: 1.0 },
138
+ ];
139
+
140
+ for (const fw of webFrameworks) {
141
+ const found = fw.paths.find(p => deps.has(p));
142
+ if (found) {
143
+ technologies.push({
144
+ name: fw.name,
145
+ version: deps.get(found),
146
+ confidence: fw.confidence,
147
+ source: `Dependency: ${found}`,
148
+ category: "backend",
149
+ });
150
+ }
151
+ }
152
+
153
+ // ORM/Database Library Detection
154
+ const orms = [
155
+ { paths: ["gorm.io/gorm", "github.com/jinzhu/gorm"], name: "GORM", confidence: 1.0 },
156
+ { paths: ["entgo.io/ent"], name: "Ent", confidence: 1.0 },
157
+ { paths: ["github.com/jmoiron/sqlx"], name: "SQLx", confidence: 1.0 },
158
+ { paths: ["github.com/kyleconroy/sqlc", "github.com/sqlc-dev/sqlc"], name: "SQLC", confidence: 1.0 },
159
+ { paths: ["github.com/uptrace/bun"], name: "Bun", confidence: 1.0 },
160
+ { paths: ["xorm.io/xorm"], name: "XORM", confidence: 1.0 },
161
+ { paths: ["github.com/doug-martin/goqu/v9"], name: "goqu", confidence: 0.95 },
162
+ ];
163
+
164
+ for (const orm of orms) {
165
+ const found = orm.paths.find(p => deps.has(p));
166
+ if (found) {
167
+ technologies.push({
168
+ name: orm.name,
169
+ version: deps.get(found),
170
+ confidence: orm.confidence,
171
+ source: `Dependency: ${found}`,
172
+ category: "orm",
173
+ });
174
+ }
175
+ }
176
+
177
+ // Database Drivers
178
+ const dbDrivers = [
179
+ { paths: ["github.com/lib/pq", "github.com/jackc/pgx/v5", "github.com/jackc/pgx/v4"], name: "PostgreSQL", confidence: 0.9 },
180
+ { paths: ["github.com/go-sql-driver/mysql"], name: "MySQL", confidence: 0.9 },
181
+ { paths: ["github.com/mattn/go-sqlite3", "modernc.org/sqlite"], name: "SQLite", confidence: 0.9 },
182
+ { paths: ["go.mongodb.org/mongo-driver/mongo"], name: "MongoDB", confidence: 0.9 },
183
+ { paths: ["github.com/redis/go-redis/v9", "github.com/go-redis/redis/v8"], name: "Redis", confidence: 0.9 },
184
+ { paths: ["github.com/elastic/go-elasticsearch/v8"], name: "Elasticsearch", confidence: 0.9 },
185
+ { paths: ["github.com/gocql/gocql"], name: "Cassandra", confidence: 0.9 },
186
+ ];
187
+
188
+ const detectedDbs = new Set<string>();
189
+ for (const db of dbDrivers) {
190
+ const found = db.paths.find(p => deps.has(p));
191
+ if (found && !detectedDbs.has(db.name)) {
192
+ technologies.push({
193
+ name: db.name,
194
+ confidence: db.confidence,
195
+ source: `Dependency: ${found}`,
196
+ category: "database",
197
+ });
198
+ detectedDbs.add(db.name);
199
+ }
200
+ }
201
+
202
+ // Testing Tools
203
+ const testingTools = [
204
+ { paths: ["github.com/stretchr/testify"], name: "Testify", confidence: 1.0 },
205
+ { paths: ["github.com/onsi/ginkgo/v2", "github.com/onsi/ginkgo"], name: "Ginkgo", confidence: 1.0 },
206
+ { paths: ["github.com/onsi/gomega"], name: "Gomega", confidence: 0.95 },
207
+ { paths: ["github.com/golang/mock/gomock"], name: "GoMock", confidence: 1.0 },
208
+ { paths: ["github.com/DATA-DOG/go-sqlmock"], name: "SQLMock", confidence: 0.9 },
209
+ ];
210
+
211
+ for (const test of testingTools) {
212
+ const found = test.paths.find(p => deps.has(p));
213
+ if (found) {
214
+ technologies.push({
215
+ name: test.name,
216
+ version: deps.get(found),
217
+ confidence: test.confidence,
218
+ source: `Dependency: ${found}`,
219
+ category: "testing",
220
+ });
221
+ }
222
+ }
223
+
224
+ // Auth/Security
225
+ const authTools = [
226
+ { paths: ["github.com/golang-jwt/jwt/v5", "github.com/dgrijalva/jwt-go"], name: "JWT-Go", confidence: 0.9 },
227
+ { paths: ["github.com/casbin/casbin/v2"], name: "Casbin", confidence: 1.0 },
228
+ { paths: ["golang.org/x/oauth2"], name: "OAuth2", confidence: 0.9 },
229
+ ];
230
+
231
+ for (const auth of authTools) {
232
+ const found = auth.paths.find(p => deps.has(p));
233
+ if (found) {
234
+ technologies.push({
235
+ name: auth.name,
236
+ confidence: auth.confidence,
237
+ source: `Dependency: ${found}`,
238
+ category: "auth",
239
+ });
240
+ }
241
+ }
242
+
243
+ // DevOps/Infrastructure
244
+ const devopsTools = [
245
+ { paths: ["github.com/spf13/cobra"], name: "Cobra CLI", confidence: 0.9 },
246
+ { paths: ["github.com/spf13/viper"], name: "Viper Config", confidence: 0.9 },
247
+ { paths: ["go.uber.org/zap"], name: "Zap Logger", confidence: 0.9 },
248
+ { paths: ["github.com/sirupsen/logrus"], name: "Logrus", confidence: 0.9 },
249
+ { paths: ["github.com/prometheus/client_golang"], name: "Prometheus", confidence: 0.9 },
250
+ { paths: ["go.opentelemetry.io/otel"], name: "OpenTelemetry", confidence: 0.9 },
251
+ ];
252
+
253
+ for (const tool of devopsTools) {
254
+ const found = tool.paths.find(p => deps.has(p));
255
+ if (found) {
256
+ technologies.push({
257
+ name: tool.name,
258
+ confidence: tool.confidence,
259
+ source: `Dependency: ${found}`,
260
+ category: "devops",
261
+ });
262
+ }
263
+ }
264
+
265
+ // Structure detection (standard Go project layout)
266
+ const structurePaths = [
267
+ { key: "cmd", paths: ["cmd"] },
268
+ { key: "internal", paths: ["internal"] },
269
+ { key: "pkg", paths: ["pkg"] },
270
+ { key: "api", paths: ["api", "internal/api", "pkg/api"] },
271
+ { key: "handlers", paths: ["internal/handlers", "handlers", "pkg/handlers"] },
272
+ { key: "services", paths: ["internal/services", "services", "pkg/services"] },
273
+ { key: "models", paths: ["internal/models", "models", "pkg/models", "internal/domain"] },
274
+ { key: "repository", paths: ["internal/repository", "repository", "internal/db"] },
275
+ { key: "config", paths: ["config", "internal/config", "configs"] },
276
+ { key: "migrations", paths: ["migrations", "db/migrations", "internal/db/migrations"] },
277
+ { key: "tests", paths: ["tests", "test"] },
278
+ { key: "scripts", paths: ["scripts"] },
279
+ { key: "docs", paths: ["docs"] },
280
+ ];
281
+
282
+ for (const { key, paths } of structurePaths) {
283
+ for (const p of paths) {
284
+ if (dirExists(join(cwd, p))) {
285
+ structure[key] = p;
286
+ break;
287
+ }
288
+ }
289
+ }
290
+
291
+ // Config files
292
+ const configPatterns = [
293
+ ".golangci.yml",
294
+ ".golangci.yaml",
295
+ "Makefile",
296
+ "air.toml",
297
+ ".air.toml",
298
+ "sqlc.yaml",
299
+ "sqlc.yml",
300
+ ".goreleaser.yml",
301
+ ".goreleaser.yaml",
302
+ "Dockerfile",
303
+ "docker-compose.yml",
304
+ "docker-compose.yaml",
305
+ ];
306
+
307
+ for (const pattern of configPatterns) {
308
+ if (fileExists(join(cwd, pattern))) {
309
+ configFiles.push(pattern);
310
+ }
311
+ }
312
+
313
+ return {
314
+ ecosystem: "go",
315
+ technologies,
316
+ structure,
317
+ configFiles: [...new Set(configFiles)],
318
+ };
319
+ },
320
+ };
321
+
322
+ // Register the detector
323
+ registerDetector(goDetector);
324
+
325
+ export default goDetector;