@codexa/cli 8.6.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 +760 -760
- package/commands/check.ts +131 -131
- package/commands/clear.ts +170 -170
- package/commands/decide.ts +249 -249
- package/commands/discover.ts +1071 -1071
- package/commands/knowledge.ts +361 -361
- package/commands/patterns.ts +621 -621
- package/commands/plan.ts +376 -376
- package/commands/product.ts +626 -626
- package/commands/research.ts +754 -754
- package/commands/review.ts +463 -463
- package/commands/standards.ts +200 -200
- package/commands/task.ts +623 -623
- package/commands/utils.ts +1021 -1021
- package/db/connection.ts +32 -32
- package/db/schema.ts +719 -719
- 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 -128
- package/detectors/node.ts +493 -493
- package/detectors/python.ts +423 -423
- package/detectors/rust.ts +348 -348
- package/gates/standards-validator.ts +204 -204
- package/gates/validator.ts +441 -441
- package/package.json +44 -43
- package/protocol/process-return.ts +450 -450
- package/protocol/subagent-protocol.ts +401 -401
- package/workflow.ts +783 -782
package/detectors/rust.ts
CHANGED
|
@@ -1,349 +1,349 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rust Ecosystem Detector
|
|
3
|
-
*
|
|
4
|
-
* Detects Rust projects including:
|
|
5
|
-
* - Frameworks: Actix-web, Axum, Rocket, Warp, Tide
|
|
6
|
-
* - ORMs: Diesel, SeaORM, SQLx
|
|
7
|
-
* - Testing: built-in, proptest, criterion
|
|
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
|
-
parseToml,
|
|
21
|
-
} from "./index";
|
|
22
|
-
|
|
23
|
-
interface CargoToml {
|
|
24
|
-
package?: {
|
|
25
|
-
name?: string;
|
|
26
|
-
version?: string;
|
|
27
|
-
edition?: string;
|
|
28
|
-
};
|
|
29
|
-
dependencies?: Record<string, any>;
|
|
30
|
-
"dev-dependencies"?: Record<string, any>;
|
|
31
|
-
"build-dependencies"?: Record<string, any>;
|
|
32
|
-
workspace?: {
|
|
33
|
-
members?: string[];
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function parseCargoToml(content: string): CargoToml {
|
|
38
|
-
return parseToml(content) as CargoToml;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const rustDetector: Detector = {
|
|
42
|
-
name: "rust",
|
|
43
|
-
ecosystem: "rust",
|
|
44
|
-
priority: 75,
|
|
45
|
-
markers: [
|
|
46
|
-
{ type: "file", pattern: "Cargo.toml", weight: 1.0 },
|
|
47
|
-
{ type: "file", pattern: "Cargo.lock", weight: 0.9 },
|
|
48
|
-
{ type: "file", pattern: "rust-toolchain.toml", weight: 0.8 },
|
|
49
|
-
{ type: "file", pattern: "rust-toolchain", weight: 0.8 },
|
|
50
|
-
{ type: "glob", pattern: "**/*.rs", weight: 0.7 },
|
|
51
|
-
{ type: "directory", pattern: "src", weight: 0.4 },
|
|
52
|
-
{ type: "directory", pattern: "target", weight: 0.3 },
|
|
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 Cargo.toml
|
|
61
|
-
const cargoPath = join(cwd, "Cargo.toml");
|
|
62
|
-
if (!fileExists(cargoPath)) {
|
|
63
|
-
// Check for Rust files without Cargo.toml
|
|
64
|
-
const rsFiles = findFiles(cwd, "**/*.rs");
|
|
65
|
-
if (rsFiles.length === 0) return null;
|
|
66
|
-
|
|
67
|
-
technologies.push({
|
|
68
|
-
name: "Rust",
|
|
69
|
-
confidence: 0.6,
|
|
70
|
-
source: "*.rs files (no Cargo.toml)",
|
|
71
|
-
category: "runtime",
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return { ecosystem: "rust", technologies, structure, configFiles };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
configFiles.push("Cargo.toml");
|
|
78
|
-
if (fileExists(join(cwd, "Cargo.lock"))) configFiles.push("Cargo.lock");
|
|
79
|
-
if (fileExists(join(cwd, "rust-toolchain.toml"))) configFiles.push("rust-toolchain.toml");
|
|
80
|
-
|
|
81
|
-
const cargoContent = readText(cargoPath);
|
|
82
|
-
if (!cargoContent) return null;
|
|
83
|
-
|
|
84
|
-
const cargo = parseCargoToml(cargoContent);
|
|
85
|
-
|
|
86
|
-
// Add Rust runtime
|
|
87
|
-
technologies.push({
|
|
88
|
-
name: "Rust",
|
|
89
|
-
version: cargo.package?.edition ? `Edition ${cargo.package.edition}` : undefined,
|
|
90
|
-
confidence: 1.0,
|
|
91
|
-
source: "Cargo.toml",
|
|
92
|
-
category: "runtime",
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Check for workspace
|
|
96
|
-
if (cargo.workspace?.members) {
|
|
97
|
-
technologies.push({
|
|
98
|
-
name: "Cargo Workspace",
|
|
99
|
-
confidence: 1.0,
|
|
100
|
-
source: "Cargo.toml [workspace]",
|
|
101
|
-
category: "build",
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Collect all dependencies
|
|
106
|
-
const allDeps = new Map<string, any>();
|
|
107
|
-
const addDeps = (deps: Record<string, any> | undefined) => {
|
|
108
|
-
if (!deps) return;
|
|
109
|
-
for (const [name, value] of Object.entries(deps)) {
|
|
110
|
-
allDeps.set(name, value);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
addDeps(cargo.dependencies);
|
|
115
|
-
addDeps(cargo["dev-dependencies"]);
|
|
116
|
-
addDeps(cargo["build-dependencies"]);
|
|
117
|
-
|
|
118
|
-
// Web Framework Detection
|
|
119
|
-
const webFrameworks = [
|
|
120
|
-
{ deps: ["actix-web"], name: "Actix Web", confidence: 1.0 },
|
|
121
|
-
{ deps: ["axum"], name: "Axum", confidence: 1.0 },
|
|
122
|
-
{ deps: ["rocket"], name: "Rocket", confidence: 1.0 },
|
|
123
|
-
{ deps: ["warp"], name: "Warp", confidence: 1.0 },
|
|
124
|
-
{ deps: ["tide"], name: "Tide", confidence: 1.0 },
|
|
125
|
-
{ deps: ["hyper"], name: "Hyper", confidence: 0.85 },
|
|
126
|
-
{ deps: ["poem"], name: "Poem", confidence: 1.0 },
|
|
127
|
-
{ deps: ["salvo"], name: "Salvo", confidence: 1.0 },
|
|
128
|
-
{ deps: ["ntex"], name: "Ntex", confidence: 1.0 },
|
|
129
|
-
];
|
|
130
|
-
|
|
131
|
-
for (const fw of webFrameworks) {
|
|
132
|
-
const found = fw.deps.find(d => allDeps.has(d));
|
|
133
|
-
if (found) {
|
|
134
|
-
const depValue = allDeps.get(found);
|
|
135
|
-
const version = typeof depValue === "string" ? depValue : depValue?.version;
|
|
136
|
-
technologies.push({
|
|
137
|
-
name: fw.name,
|
|
138
|
-
version,
|
|
139
|
-
confidence: fw.confidence,
|
|
140
|
-
source: `Dependency: ${found}`,
|
|
141
|
-
category: "backend",
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ORM/Database Library Detection
|
|
147
|
-
const orms = [
|
|
148
|
-
{ deps: ["diesel"], name: "Diesel", confidence: 1.0 },
|
|
149
|
-
{ deps: ["sea-orm"], name: "SeaORM", confidence: 1.0 },
|
|
150
|
-
{ deps: ["sqlx"], name: "SQLx", confidence: 1.0 },
|
|
151
|
-
{ deps: ["rbatis"], name: "Rbatis", confidence: 1.0 },
|
|
152
|
-
{ deps: ["rusqlite"], name: "rusqlite", confidence: 0.9 },
|
|
153
|
-
];
|
|
154
|
-
|
|
155
|
-
for (const orm of orms) {
|
|
156
|
-
const found = orm.deps.find(d => allDeps.has(d));
|
|
157
|
-
if (found) {
|
|
158
|
-
const depValue = allDeps.get(found);
|
|
159
|
-
const version = typeof depValue === "string" ? depValue : depValue?.version;
|
|
160
|
-
technologies.push({
|
|
161
|
-
name: orm.name,
|
|
162
|
-
version,
|
|
163
|
-
confidence: orm.confidence,
|
|
164
|
-
source: `Dependency: ${found}`,
|
|
165
|
-
category: "orm",
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Database Drivers
|
|
171
|
-
const dbDrivers = [
|
|
172
|
-
{ deps: ["tokio-postgres", "postgres"], name: "PostgreSQL", confidence: 0.9 },
|
|
173
|
-
{ deps: ["mysql", "mysql_async"], name: "MySQL", confidence: 0.9 },
|
|
174
|
-
{ deps: ["mongodb"], name: "MongoDB", confidence: 0.9 },
|
|
175
|
-
{ deps: ["redis"], name: "Redis", confidence: 0.9 },
|
|
176
|
-
{ deps: ["elasticsearch"], name: "Elasticsearch", confidence: 0.9 },
|
|
177
|
-
];
|
|
178
|
-
|
|
179
|
-
const detectedDbs = new Set<string>();
|
|
180
|
-
for (const db of dbDrivers) {
|
|
181
|
-
const found = db.deps.find(d => allDeps.has(d));
|
|
182
|
-
if (found && !detectedDbs.has(db.name)) {
|
|
183
|
-
technologies.push({
|
|
184
|
-
name: db.name,
|
|
185
|
-
confidence: db.confidence,
|
|
186
|
-
source: `Dependency: ${found}`,
|
|
187
|
-
category: "database",
|
|
188
|
-
});
|
|
189
|
-
detectedDbs.add(db.name);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Async Runtime
|
|
194
|
-
const asyncRuntimes = [
|
|
195
|
-
{ deps: ["tokio"], name: "Tokio", confidence: 1.0 },
|
|
196
|
-
{ deps: ["async-std"], name: "async-std", confidence: 1.0 },
|
|
197
|
-
{ deps: ["smol"], name: "Smol", confidence: 1.0 },
|
|
198
|
-
];
|
|
199
|
-
|
|
200
|
-
for (const runtime of asyncRuntimes) {
|
|
201
|
-
const found = runtime.deps.find(d => allDeps.has(d));
|
|
202
|
-
if (found) {
|
|
203
|
-
technologies.push({
|
|
204
|
-
name: runtime.name,
|
|
205
|
-
confidence: runtime.confidence,
|
|
206
|
-
source: `Dependency: ${found}`,
|
|
207
|
-
category: "runtime",
|
|
208
|
-
metadata: { type: "async-runtime" },
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Serialization
|
|
214
|
-
const serializationLibs = [
|
|
215
|
-
{ deps: ["serde", "serde_json"], name: "Serde", confidence: 0.95 },
|
|
216
|
-
];
|
|
217
|
-
|
|
218
|
-
for (const lib of serializationLibs) {
|
|
219
|
-
const found = lib.deps.find(d => allDeps.has(d));
|
|
220
|
-
if (found) {
|
|
221
|
-
technologies.push({
|
|
222
|
-
name: lib.name,
|
|
223
|
-
confidence: lib.confidence,
|
|
224
|
-
source: `Dependency: ${found}`,
|
|
225
|
-
category: "backend",
|
|
226
|
-
metadata: { type: "serialization" },
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Testing Tools
|
|
232
|
-
const testingTools = [
|
|
233
|
-
{ deps: ["proptest"], name: "Proptest", confidence: 1.0 },
|
|
234
|
-
{ deps: ["quickcheck"], name: "QuickCheck", confidence: 1.0 },
|
|
235
|
-
{ deps: ["criterion"], name: "Criterion (Benchmarks)", confidence: 1.0 },
|
|
236
|
-
{ deps: ["mockall"], name: "Mockall", confidence: 1.0 },
|
|
237
|
-
{ deps: ["rstest"], name: "rstest", confidence: 1.0 },
|
|
238
|
-
];
|
|
239
|
-
|
|
240
|
-
for (const test of testingTools) {
|
|
241
|
-
const found = test.deps.find(d => allDeps.has(d));
|
|
242
|
-
if (found) {
|
|
243
|
-
technologies.push({
|
|
244
|
-
name: test.name,
|
|
245
|
-
confidence: test.confidence,
|
|
246
|
-
source: `Dependency: ${found}`,
|
|
247
|
-
category: "testing",
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// CLI/DevTools
|
|
253
|
-
const devTools = [
|
|
254
|
-
{ deps: ["clap"], name: "Clap CLI", confidence: 0.9 },
|
|
255
|
-
{ deps: ["structopt"], name: "StructOpt CLI", confidence: 0.9 },
|
|
256
|
-
{ deps: ["tracing"], name: "Tracing", confidence: 0.9 },
|
|
257
|
-
{ deps: ["log", "env_logger"], name: "log", confidence: 0.85 },
|
|
258
|
-
{ deps: ["config"], name: "config-rs", confidence: 0.9 },
|
|
259
|
-
];
|
|
260
|
-
|
|
261
|
-
for (const tool of devTools) {
|
|
262
|
-
const found = tool.deps.find(d => allDeps.has(d));
|
|
263
|
-
if (found) {
|
|
264
|
-
technologies.push({
|
|
265
|
-
name: tool.name,
|
|
266
|
-
confidence: tool.confidence,
|
|
267
|
-
source: `Dependency: ${found}`,
|
|
268
|
-
category: "devops",
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// WASM Support
|
|
274
|
-
if (allDeps.has("wasm-bindgen") || allDeps.has("wasm-pack")) {
|
|
275
|
-
technologies.push({
|
|
276
|
-
name: "WebAssembly",
|
|
277
|
-
confidence: 1.0,
|
|
278
|
-
source: "wasm-bindgen/wasm-pack dependency",
|
|
279
|
-
category: "frontend",
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Embedded/Systems
|
|
284
|
-
if (allDeps.has("embedded-hal") || allDeps.has("cortex-m")) {
|
|
285
|
-
technologies.push({
|
|
286
|
-
name: "Embedded Systems",
|
|
287
|
-
confidence: 1.0,
|
|
288
|
-
source: "embedded-hal/cortex-m dependency",
|
|
289
|
-
category: "backend",
|
|
290
|
-
metadata: { type: "embedded" },
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Structure detection
|
|
295
|
-
const structurePaths = [
|
|
296
|
-
{ key: "src", paths: ["src"] },
|
|
297
|
-
{ key: "api", paths: ["src/api", "src/routes", "src/handlers"] },
|
|
298
|
-
{ key: "models", paths: ["src/models", "src/domain", "src/entities"] },
|
|
299
|
-
{ key: "services", paths: ["src/services", "src/service"] },
|
|
300
|
-
{ key: "repository", paths: ["src/repository", "src/db", "src/repos"] },
|
|
301
|
-
{ key: "config", paths: ["src/config", "config"] },
|
|
302
|
-
{ key: "migrations", paths: ["migrations", "src/migrations"] },
|
|
303
|
-
{ key: "tests", paths: ["tests"] },
|
|
304
|
-
{ key: "benches", paths: ["benches"] },
|
|
305
|
-
{ key: "examples", paths: ["examples"] },
|
|
306
|
-
];
|
|
307
|
-
|
|
308
|
-
for (const { key, paths } of structurePaths) {
|
|
309
|
-
for (const p of paths) {
|
|
310
|
-
if (dirExists(join(cwd, p))) {
|
|
311
|
-
structure[key] = p;
|
|
312
|
-
break;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Config files
|
|
318
|
-
const configPatterns = [
|
|
319
|
-
".cargo/config.toml",
|
|
320
|
-
"clippy.toml",
|
|
321
|
-
".clippy.toml",
|
|
322
|
-
"rustfmt.toml",
|
|
323
|
-
".rustfmt.toml",
|
|
324
|
-
"deny.toml",
|
|
325
|
-
"Makefile",
|
|
326
|
-
"Makefile.toml",
|
|
327
|
-
"Dockerfile",
|
|
328
|
-
"docker-compose.yml",
|
|
329
|
-
];
|
|
330
|
-
|
|
331
|
-
for (const pattern of configPatterns) {
|
|
332
|
-
if (fileExists(join(cwd, pattern))) {
|
|
333
|
-
configFiles.push(pattern);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return {
|
|
338
|
-
ecosystem: "rust",
|
|
339
|
-
technologies,
|
|
340
|
-
structure,
|
|
341
|
-
configFiles: [...new Set(configFiles)],
|
|
342
|
-
};
|
|
343
|
-
},
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
// Register the detector
|
|
347
|
-
registerDetector(rustDetector);
|
|
348
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Rust Ecosystem Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects Rust projects including:
|
|
5
|
+
* - Frameworks: Actix-web, Axum, Rocket, Warp, Tide
|
|
6
|
+
* - ORMs: Diesel, SeaORM, SQLx
|
|
7
|
+
* - Testing: built-in, proptest, criterion
|
|
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
|
+
parseToml,
|
|
21
|
+
} from "./index";
|
|
22
|
+
|
|
23
|
+
interface CargoToml {
|
|
24
|
+
package?: {
|
|
25
|
+
name?: string;
|
|
26
|
+
version?: string;
|
|
27
|
+
edition?: string;
|
|
28
|
+
};
|
|
29
|
+
dependencies?: Record<string, any>;
|
|
30
|
+
"dev-dependencies"?: Record<string, any>;
|
|
31
|
+
"build-dependencies"?: Record<string, any>;
|
|
32
|
+
workspace?: {
|
|
33
|
+
members?: string[];
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function parseCargoToml(content: string): CargoToml {
|
|
38
|
+
return parseToml(content) as CargoToml;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const rustDetector: Detector = {
|
|
42
|
+
name: "rust",
|
|
43
|
+
ecosystem: "rust",
|
|
44
|
+
priority: 75,
|
|
45
|
+
markers: [
|
|
46
|
+
{ type: "file", pattern: "Cargo.toml", weight: 1.0 },
|
|
47
|
+
{ type: "file", pattern: "Cargo.lock", weight: 0.9 },
|
|
48
|
+
{ type: "file", pattern: "rust-toolchain.toml", weight: 0.8 },
|
|
49
|
+
{ type: "file", pattern: "rust-toolchain", weight: 0.8 },
|
|
50
|
+
{ type: "glob", pattern: "**/*.rs", weight: 0.7 },
|
|
51
|
+
{ type: "directory", pattern: "src", weight: 0.4 },
|
|
52
|
+
{ type: "directory", pattern: "target", weight: 0.3 },
|
|
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 Cargo.toml
|
|
61
|
+
const cargoPath = join(cwd, "Cargo.toml");
|
|
62
|
+
if (!fileExists(cargoPath)) {
|
|
63
|
+
// Check for Rust files without Cargo.toml
|
|
64
|
+
const rsFiles = findFiles(cwd, "**/*.rs");
|
|
65
|
+
if (rsFiles.length === 0) return null;
|
|
66
|
+
|
|
67
|
+
technologies.push({
|
|
68
|
+
name: "Rust",
|
|
69
|
+
confidence: 0.6,
|
|
70
|
+
source: "*.rs files (no Cargo.toml)",
|
|
71
|
+
category: "runtime",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return { ecosystem: "rust", technologies, structure, configFiles };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
configFiles.push("Cargo.toml");
|
|
78
|
+
if (fileExists(join(cwd, "Cargo.lock"))) configFiles.push("Cargo.lock");
|
|
79
|
+
if (fileExists(join(cwd, "rust-toolchain.toml"))) configFiles.push("rust-toolchain.toml");
|
|
80
|
+
|
|
81
|
+
const cargoContent = readText(cargoPath);
|
|
82
|
+
if (!cargoContent) return null;
|
|
83
|
+
|
|
84
|
+
const cargo = parseCargoToml(cargoContent);
|
|
85
|
+
|
|
86
|
+
// Add Rust runtime
|
|
87
|
+
technologies.push({
|
|
88
|
+
name: "Rust",
|
|
89
|
+
version: cargo.package?.edition ? `Edition ${cargo.package.edition}` : undefined,
|
|
90
|
+
confidence: 1.0,
|
|
91
|
+
source: "Cargo.toml",
|
|
92
|
+
category: "runtime",
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Check for workspace
|
|
96
|
+
if (cargo.workspace?.members) {
|
|
97
|
+
technologies.push({
|
|
98
|
+
name: "Cargo Workspace",
|
|
99
|
+
confidence: 1.0,
|
|
100
|
+
source: "Cargo.toml [workspace]",
|
|
101
|
+
category: "build",
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Collect all dependencies
|
|
106
|
+
const allDeps = new Map<string, any>();
|
|
107
|
+
const addDeps = (deps: Record<string, any> | undefined) => {
|
|
108
|
+
if (!deps) return;
|
|
109
|
+
for (const [name, value] of Object.entries(deps)) {
|
|
110
|
+
allDeps.set(name, value);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
addDeps(cargo.dependencies);
|
|
115
|
+
addDeps(cargo["dev-dependencies"]);
|
|
116
|
+
addDeps(cargo["build-dependencies"]);
|
|
117
|
+
|
|
118
|
+
// Web Framework Detection
|
|
119
|
+
const webFrameworks = [
|
|
120
|
+
{ deps: ["actix-web"], name: "Actix Web", confidence: 1.0 },
|
|
121
|
+
{ deps: ["axum"], name: "Axum", confidence: 1.0 },
|
|
122
|
+
{ deps: ["rocket"], name: "Rocket", confidence: 1.0 },
|
|
123
|
+
{ deps: ["warp"], name: "Warp", confidence: 1.0 },
|
|
124
|
+
{ deps: ["tide"], name: "Tide", confidence: 1.0 },
|
|
125
|
+
{ deps: ["hyper"], name: "Hyper", confidence: 0.85 },
|
|
126
|
+
{ deps: ["poem"], name: "Poem", confidence: 1.0 },
|
|
127
|
+
{ deps: ["salvo"], name: "Salvo", confidence: 1.0 },
|
|
128
|
+
{ deps: ["ntex"], name: "Ntex", confidence: 1.0 },
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
for (const fw of webFrameworks) {
|
|
132
|
+
const found = fw.deps.find(d => allDeps.has(d));
|
|
133
|
+
if (found) {
|
|
134
|
+
const depValue = allDeps.get(found);
|
|
135
|
+
const version = typeof depValue === "string" ? depValue : depValue?.version;
|
|
136
|
+
technologies.push({
|
|
137
|
+
name: fw.name,
|
|
138
|
+
version,
|
|
139
|
+
confidence: fw.confidence,
|
|
140
|
+
source: `Dependency: ${found}`,
|
|
141
|
+
category: "backend",
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ORM/Database Library Detection
|
|
147
|
+
const orms = [
|
|
148
|
+
{ deps: ["diesel"], name: "Diesel", confidence: 1.0 },
|
|
149
|
+
{ deps: ["sea-orm"], name: "SeaORM", confidence: 1.0 },
|
|
150
|
+
{ deps: ["sqlx"], name: "SQLx", confidence: 1.0 },
|
|
151
|
+
{ deps: ["rbatis"], name: "Rbatis", confidence: 1.0 },
|
|
152
|
+
{ deps: ["rusqlite"], name: "rusqlite", confidence: 0.9 },
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
for (const orm of orms) {
|
|
156
|
+
const found = orm.deps.find(d => allDeps.has(d));
|
|
157
|
+
if (found) {
|
|
158
|
+
const depValue = allDeps.get(found);
|
|
159
|
+
const version = typeof depValue === "string" ? depValue : depValue?.version;
|
|
160
|
+
technologies.push({
|
|
161
|
+
name: orm.name,
|
|
162
|
+
version,
|
|
163
|
+
confidence: orm.confidence,
|
|
164
|
+
source: `Dependency: ${found}`,
|
|
165
|
+
category: "orm",
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Database Drivers
|
|
171
|
+
const dbDrivers = [
|
|
172
|
+
{ deps: ["tokio-postgres", "postgres"], name: "PostgreSQL", confidence: 0.9 },
|
|
173
|
+
{ deps: ["mysql", "mysql_async"], name: "MySQL", confidence: 0.9 },
|
|
174
|
+
{ deps: ["mongodb"], name: "MongoDB", confidence: 0.9 },
|
|
175
|
+
{ deps: ["redis"], name: "Redis", confidence: 0.9 },
|
|
176
|
+
{ deps: ["elasticsearch"], name: "Elasticsearch", confidence: 0.9 },
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
const detectedDbs = new Set<string>();
|
|
180
|
+
for (const db of dbDrivers) {
|
|
181
|
+
const found = db.deps.find(d => allDeps.has(d));
|
|
182
|
+
if (found && !detectedDbs.has(db.name)) {
|
|
183
|
+
technologies.push({
|
|
184
|
+
name: db.name,
|
|
185
|
+
confidence: db.confidence,
|
|
186
|
+
source: `Dependency: ${found}`,
|
|
187
|
+
category: "database",
|
|
188
|
+
});
|
|
189
|
+
detectedDbs.add(db.name);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Async Runtime
|
|
194
|
+
const asyncRuntimes = [
|
|
195
|
+
{ deps: ["tokio"], name: "Tokio", confidence: 1.0 },
|
|
196
|
+
{ deps: ["async-std"], name: "async-std", confidence: 1.0 },
|
|
197
|
+
{ deps: ["smol"], name: "Smol", confidence: 1.0 },
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
for (const runtime of asyncRuntimes) {
|
|
201
|
+
const found = runtime.deps.find(d => allDeps.has(d));
|
|
202
|
+
if (found) {
|
|
203
|
+
technologies.push({
|
|
204
|
+
name: runtime.name,
|
|
205
|
+
confidence: runtime.confidence,
|
|
206
|
+
source: `Dependency: ${found}`,
|
|
207
|
+
category: "runtime",
|
|
208
|
+
metadata: { type: "async-runtime" },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Serialization
|
|
214
|
+
const serializationLibs = [
|
|
215
|
+
{ deps: ["serde", "serde_json"], name: "Serde", confidence: 0.95 },
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
for (const lib of serializationLibs) {
|
|
219
|
+
const found = lib.deps.find(d => allDeps.has(d));
|
|
220
|
+
if (found) {
|
|
221
|
+
technologies.push({
|
|
222
|
+
name: lib.name,
|
|
223
|
+
confidence: lib.confidence,
|
|
224
|
+
source: `Dependency: ${found}`,
|
|
225
|
+
category: "backend",
|
|
226
|
+
metadata: { type: "serialization" },
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Testing Tools
|
|
232
|
+
const testingTools = [
|
|
233
|
+
{ deps: ["proptest"], name: "Proptest", confidence: 1.0 },
|
|
234
|
+
{ deps: ["quickcheck"], name: "QuickCheck", confidence: 1.0 },
|
|
235
|
+
{ deps: ["criterion"], name: "Criterion (Benchmarks)", confidence: 1.0 },
|
|
236
|
+
{ deps: ["mockall"], name: "Mockall", confidence: 1.0 },
|
|
237
|
+
{ deps: ["rstest"], name: "rstest", confidence: 1.0 },
|
|
238
|
+
];
|
|
239
|
+
|
|
240
|
+
for (const test of testingTools) {
|
|
241
|
+
const found = test.deps.find(d => allDeps.has(d));
|
|
242
|
+
if (found) {
|
|
243
|
+
technologies.push({
|
|
244
|
+
name: test.name,
|
|
245
|
+
confidence: test.confidence,
|
|
246
|
+
source: `Dependency: ${found}`,
|
|
247
|
+
category: "testing",
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// CLI/DevTools
|
|
253
|
+
const devTools = [
|
|
254
|
+
{ deps: ["clap"], name: "Clap CLI", confidence: 0.9 },
|
|
255
|
+
{ deps: ["structopt"], name: "StructOpt CLI", confidence: 0.9 },
|
|
256
|
+
{ deps: ["tracing"], name: "Tracing", confidence: 0.9 },
|
|
257
|
+
{ deps: ["log", "env_logger"], name: "log", confidence: 0.85 },
|
|
258
|
+
{ deps: ["config"], name: "config-rs", confidence: 0.9 },
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
for (const tool of devTools) {
|
|
262
|
+
const found = tool.deps.find(d => allDeps.has(d));
|
|
263
|
+
if (found) {
|
|
264
|
+
technologies.push({
|
|
265
|
+
name: tool.name,
|
|
266
|
+
confidence: tool.confidence,
|
|
267
|
+
source: `Dependency: ${found}`,
|
|
268
|
+
category: "devops",
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// WASM Support
|
|
274
|
+
if (allDeps.has("wasm-bindgen") || allDeps.has("wasm-pack")) {
|
|
275
|
+
technologies.push({
|
|
276
|
+
name: "WebAssembly",
|
|
277
|
+
confidence: 1.0,
|
|
278
|
+
source: "wasm-bindgen/wasm-pack dependency",
|
|
279
|
+
category: "frontend",
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Embedded/Systems
|
|
284
|
+
if (allDeps.has("embedded-hal") || allDeps.has("cortex-m")) {
|
|
285
|
+
technologies.push({
|
|
286
|
+
name: "Embedded Systems",
|
|
287
|
+
confidence: 1.0,
|
|
288
|
+
source: "embedded-hal/cortex-m dependency",
|
|
289
|
+
category: "backend",
|
|
290
|
+
metadata: { type: "embedded" },
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Structure detection
|
|
295
|
+
const structurePaths = [
|
|
296
|
+
{ key: "src", paths: ["src"] },
|
|
297
|
+
{ key: "api", paths: ["src/api", "src/routes", "src/handlers"] },
|
|
298
|
+
{ key: "models", paths: ["src/models", "src/domain", "src/entities"] },
|
|
299
|
+
{ key: "services", paths: ["src/services", "src/service"] },
|
|
300
|
+
{ key: "repository", paths: ["src/repository", "src/db", "src/repos"] },
|
|
301
|
+
{ key: "config", paths: ["src/config", "config"] },
|
|
302
|
+
{ key: "migrations", paths: ["migrations", "src/migrations"] },
|
|
303
|
+
{ key: "tests", paths: ["tests"] },
|
|
304
|
+
{ key: "benches", paths: ["benches"] },
|
|
305
|
+
{ key: "examples", paths: ["examples"] },
|
|
306
|
+
];
|
|
307
|
+
|
|
308
|
+
for (const { key, paths } of structurePaths) {
|
|
309
|
+
for (const p of paths) {
|
|
310
|
+
if (dirExists(join(cwd, p))) {
|
|
311
|
+
structure[key] = p;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Config files
|
|
318
|
+
const configPatterns = [
|
|
319
|
+
".cargo/config.toml",
|
|
320
|
+
"clippy.toml",
|
|
321
|
+
".clippy.toml",
|
|
322
|
+
"rustfmt.toml",
|
|
323
|
+
".rustfmt.toml",
|
|
324
|
+
"deny.toml",
|
|
325
|
+
"Makefile",
|
|
326
|
+
"Makefile.toml",
|
|
327
|
+
"Dockerfile",
|
|
328
|
+
"docker-compose.yml",
|
|
329
|
+
];
|
|
330
|
+
|
|
331
|
+
for (const pattern of configPatterns) {
|
|
332
|
+
if (fileExists(join(cwd, pattern))) {
|
|
333
|
+
configFiles.push(pattern);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
ecosystem: "rust",
|
|
339
|
+
technologies,
|
|
340
|
+
structure,
|
|
341
|
+
configFiles: [...new Set(configFiles)],
|
|
342
|
+
};
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// Register the detector
|
|
347
|
+
registerDetector(rustDetector);
|
|
348
|
+
|
|
349
349
|
export default rustDetector;
|