@codexa/cli 8.5.0 → 8.6.9
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/commands/architect.ts +1 -137
- package/commands/clear.ts +1 -5
- package/commands/discover.ts +1071 -999
- package/commands/product.ts +0 -2
- package/commands/research.ts +1 -1
- package/commands/standards.ts +0 -23
- package/commands/task.ts +623 -623
- package/db/schema.ts +0 -69
- package/detectors/README.md +109 -109
- package/detectors/dotnet.ts +357 -357
- package/detectors/flutter.ts +350 -350
- package/detectors/go.ts +324 -324
- package/detectors/index.ts +387 -387
- package/detectors/jvm.ts +433 -433
- package/detectors/loader.ts +128 -140
- package/detectors/node.ts +493 -493
- package/detectors/python.ts +423 -423
- package/detectors/rust.ts +348 -348
- package/package.json +5 -4
- package/protocol/subagent-protocol.ts +0 -10
- package/workflow.ts +783 -800
package/detectors/go.ts
CHANGED
|
@@ -1,325 +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
|
-
|
|
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
325
|
export default goDetector;
|