@archpilotlabs/archpilot 0.0.7 → 0.0.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/README.md +53 -9
- package/dist/archpilot-cli.js +820 -29
- package/package.json +34 -34
package/README.md
CHANGED
|
@@ -5,14 +5,18 @@
|
|
|
5
5
|
<h1 align="center">ArchPilot</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
|
|
8
|
+
Architecture guardrails for AI-native software development
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
+
ArchPilot validates your repository against architecture rules and helps engineering teams move faster with AI-assisted development-without sacrificing architectural integrity.
|
|
12
|
+
|
|
13
|
+
**Your AI writes code. ArchPilot protects architecture.**
|
|
14
|
+
|
|
11
15
|
<p align="center">
|
|
12
16
|
Validate • Enforce • Measure architecture continuously
|
|
13
17
|
</p>
|
|
14
18
|
|
|
15
|
-
ArchPilot
|
|
19
|
+
ArchPilot makes architecture **visible, enforceable, and measurable** as your system evolves.
|
|
16
20
|
|
|
17
21
|
---
|
|
18
22
|
|
|
@@ -24,6 +28,10 @@ Over time, boundaries blur, dependencies leak, and architectural decisions drift
|
|
|
24
28
|
|
|
25
29
|
ArchPilot turns architecture into something you can **actually validate, enforce, and track continuously**.
|
|
26
30
|
|
|
31
|
+
AI accelerates code delivery-but architectural drift accelerates too.
|
|
32
|
+
|
|
33
|
+
ArchPilot gives teams deterministic architecture guardrails in local development, CI, and governance workflows.
|
|
34
|
+
|
|
27
35
|
---
|
|
28
36
|
|
|
29
37
|
## 🚀 What it does
|
|
@@ -40,7 +48,46 @@ No runtime agents. No external services. Fully deterministic and local-first.
|
|
|
40
48
|
|
|
41
49
|
---
|
|
42
50
|
|
|
43
|
-
##
|
|
51
|
+
## 🧩 Supported Stacks
|
|
52
|
+
|
|
53
|
+
ArchPilot supports **practical deterministic architecture detection** across modern application stacks.
|
|
54
|
+
|
|
55
|
+
### Backend
|
|
56
|
+
|
|
57
|
+
* Node.js / TypeScript
|
|
58
|
+
* NestJS
|
|
59
|
+
* Express.js
|
|
60
|
+
* Java
|
|
61
|
+
* Spring / Spring Boot
|
|
62
|
+
* Kotlin
|
|
63
|
+
* FastAPI
|
|
64
|
+
* Django
|
|
65
|
+
* Flask
|
|
66
|
+
* PHP
|
|
67
|
+
* Laravel
|
|
68
|
+
* Go
|
|
69
|
+
* .NET
|
|
70
|
+
* Ruby on Rails
|
|
71
|
+
|
|
72
|
+
### Frontend
|
|
73
|
+
|
|
74
|
+
* React
|
|
75
|
+
* Next.js
|
|
76
|
+
* Angular
|
|
77
|
+
* Vue
|
|
78
|
+
|
|
79
|
+
### Infrastructure
|
|
80
|
+
|
|
81
|
+
* Terraform
|
|
82
|
+
* Ansible
|
|
83
|
+
|
|
84
|
+
ArchPilot detects stack shape from practical repository evidence - framework markers, manifests, project layout, and source structure - then applies conservative architecture discovery defaults locally.
|
|
85
|
+
|
|
86
|
+
**No cloud scanning. No remote indexing. Deterministic local validation.**
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## ☁️ Local-first. Cloud-powered.
|
|
44
91
|
|
|
45
92
|
Start locally in minutes:
|
|
46
93
|
|
|
@@ -65,12 +112,9 @@ archpilot cloud connect
|
|
|
65
112
|
archpilot cloud disconnect
|
|
66
113
|
```
|
|
67
114
|
|
|
68
|
-
Cloud setup only asks for your API token.
|
|
69
|
-
|
|
70
|
-
`https://api.archpilot.org`
|
|
71
|
-
|
|
72
|
-
For local development, set `ARCHPILOT_CLOUD_URL=http://localhost:4000` before running Cloud commands. CLI `--server` remains available for one-off debugging and automated tests.
|
|
115
|
+
Cloud setup only asks for your API token.
|
|
73
116
|
|
|
117
|
+
ArchPilot uses the canonical production API automatically-no server URL setup required for normal use.
|
|
74
118
|
Learn more:
|
|
75
119
|
|
|
76
120
|
https://archpilot.org/docs
|
|
@@ -203,7 +247,7 @@ archpilot governance upload
|
|
|
203
247
|
|
|
204
248
|
---
|
|
205
249
|
|
|
206
|
-
##
|
|
250
|
+
## ⚙️ Core Capabilities
|
|
207
251
|
|
|
208
252
|
* Architecture-as-code (`.archpilot/`)
|
|
209
253
|
* Dependency validation and module contracts
|
package/dist/archpilot-cli.js
CHANGED
|
@@ -210932,15 +210932,20 @@ var import_node_fs = require("node:fs");
|
|
|
210932
210932
|
var validProjectKinds = /* @__PURE__ */ new Set(["backend", "frontend", "library"]);
|
|
210933
210933
|
var validCanonicalStackIds = /* @__PURE__ */ new Set([
|
|
210934
210934
|
"node_typescript",
|
|
210935
|
+
"express",
|
|
210935
210936
|
"nestjs",
|
|
210936
210937
|
"java",
|
|
210937
210938
|
"spring",
|
|
210938
210939
|
"fastapi",
|
|
210940
|
+
"django",
|
|
210941
|
+
"flask",
|
|
210939
210942
|
"python",
|
|
210940
210943
|
"php",
|
|
210944
|
+
"laravel",
|
|
210941
210945
|
"go",
|
|
210942
210946
|
"dotnet",
|
|
210943
210947
|
"ruby_rails",
|
|
210948
|
+
"kotlin",
|
|
210944
210949
|
"kotlin_spring",
|
|
210945
210950
|
"rust",
|
|
210946
210951
|
"react",
|
|
@@ -210954,15 +210959,20 @@ var validCanonicalStackIds = /* @__PURE__ */ new Set([
|
|
|
210954
210959
|
]);
|
|
210955
210960
|
var canonicalStackLabels = {
|
|
210956
210961
|
node_typescript: "TypeScript / Node.js",
|
|
210962
|
+
express: "Express.js",
|
|
210957
210963
|
nestjs: "NestJS",
|
|
210958
210964
|
java: "Java",
|
|
210959
210965
|
spring: "Spring",
|
|
210960
210966
|
fastapi: "FastAPI",
|
|
210967
|
+
django: "Django",
|
|
210968
|
+
flask: "Flask",
|
|
210961
210969
|
python: "Python",
|
|
210962
210970
|
php: "PHP",
|
|
210971
|
+
laravel: "Laravel",
|
|
210963
210972
|
go: "Go",
|
|
210964
210973
|
dotnet: ".NET",
|
|
210965
210974
|
ruby_rails: "Ruby / Rails",
|
|
210975
|
+
kotlin: "Kotlin",
|
|
210966
210976
|
kotlin_spring: "Kotlin / Spring",
|
|
210967
210977
|
rust: "Rust",
|
|
210968
210978
|
react: "React",
|
|
@@ -211173,6 +211183,103 @@ var nodeTypescriptAdapter = buildAdapter({
|
|
|
211173
211183
|
var stackAdaptersById = {
|
|
211174
211184
|
other: genericDefaultAdapter,
|
|
211175
211185
|
node_typescript: nodeTypescriptAdapter,
|
|
211186
|
+
express: buildAdapter({
|
|
211187
|
+
id: "express",
|
|
211188
|
+
displayName: canonicalStackLabels.express,
|
|
211189
|
+
ecosystem: "node",
|
|
211190
|
+
category: "framework",
|
|
211191
|
+
priority: 70,
|
|
211192
|
+
manifestDetectionHints: ["package.json", "tsconfig.json", "app.js", "app.ts", "server.js", "server.ts"],
|
|
211193
|
+
buildToolHints: ["npm", "pnpm", "yarn"],
|
|
211194
|
+
defaults: {
|
|
211195
|
+
sourceRoots: ["src", "."],
|
|
211196
|
+
moduleRootCandidates: ["src/modules", "src/features", "routes", "src/routes", "src"],
|
|
211197
|
+
apiRoots: ["routes", "src/routes", "src/api", "api"],
|
|
211198
|
+
databaseRoots: ["prisma", "db", "database", "migrations"],
|
|
211199
|
+
configFiles: ["package.json", "tsconfig.json"],
|
|
211200
|
+
fileExtensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"],
|
|
211201
|
+
dependencyFileExtensions: [".ts", ".js", ".mjs", ".cjs"],
|
|
211202
|
+
ignoreDirectories: ["node_modules", "dist", "coverage"],
|
|
211203
|
+
entrypointHints: ["app.ts", "server.ts", "src/app.ts", "src/server.ts", "app.js", "server.js", "src/app.js", "src/server.js"],
|
|
211204
|
+
publicEntrypointDirectories: ["public"],
|
|
211205
|
+
moduleIndexFileName: "index.ts"
|
|
211206
|
+
},
|
|
211207
|
+
detect: (context) => {
|
|
211208
|
+
const evidence = [];
|
|
211209
|
+
let strongSignals = 0;
|
|
211210
|
+
let mediumSignals = 0;
|
|
211211
|
+
let score = 0;
|
|
211212
|
+
const hasExpressDependency = context.hasPackageDependency("express");
|
|
211213
|
+
const hasExpressFactory = context.hasAnyFileMatchingPattern(
|
|
211214
|
+
/\.(ts|js|mjs|cjs)$/iu,
|
|
211215
|
+
/\bexpress\s*\(\s*\)/u
|
|
211216
|
+
);
|
|
211217
|
+
const hasExpressImport = context.hasAnyFileMatchingPattern(
|
|
211218
|
+
/\.(ts|js|mjs|cjs)$/iu,
|
|
211219
|
+
/\b(import\s+express\s+from\s+['"]express['"]|require\s*\(\s*['"]express['"]\s*\))/u
|
|
211220
|
+
);
|
|
211221
|
+
const hasAppUse = context.hasAnyFileMatchingPattern(
|
|
211222
|
+
/\.(ts|js|mjs|cjs)$/iu,
|
|
211223
|
+
/\bapp\.use\s*\(/u
|
|
211224
|
+
);
|
|
211225
|
+
const hasRouterUsage = context.hasAnyFileMatchingPattern(
|
|
211226
|
+
/\.(ts|js|mjs|cjs)$/iu,
|
|
211227
|
+
/\b(router|Router)\s*\.\s*(get|post|put|patch|delete|use)\s*\(/u
|
|
211228
|
+
);
|
|
211229
|
+
const hasRoutesDirectory = context.hasDirectory("routes") || context.hasDirectory("src/routes");
|
|
211230
|
+
const hasRouteFiles = context.hasAnyPathMatchingPattern(/(^|\/)(routes|src\/routes)\/.+\.(ts|js|mjs|cjs)$/iu);
|
|
211231
|
+
if (hasExpressDependency) {
|
|
211232
|
+
strongSignals += 1;
|
|
211233
|
+
score += 46;
|
|
211234
|
+
evidence.push("Found package.json with express dependency");
|
|
211235
|
+
}
|
|
211236
|
+
if (hasExpressFactory) {
|
|
211237
|
+
strongSignals += 1;
|
|
211238
|
+
score += 28;
|
|
211239
|
+
evidence.push("Found express() app construction");
|
|
211240
|
+
}
|
|
211241
|
+
if (hasExpressImport) {
|
|
211242
|
+
mediumSignals += 1;
|
|
211243
|
+
score += 12;
|
|
211244
|
+
evidence.push("Found Express import or require");
|
|
211245
|
+
}
|
|
211246
|
+
if (hasAppUse) {
|
|
211247
|
+
mediumSignals += 1;
|
|
211248
|
+
score += 10;
|
|
211249
|
+
evidence.push("Found app.use(...) middleware or router mounting");
|
|
211250
|
+
}
|
|
211251
|
+
if (hasRouterUsage) {
|
|
211252
|
+
mediumSignals += 1;
|
|
211253
|
+
score += 10;
|
|
211254
|
+
evidence.push("Found router HTTP method usage");
|
|
211255
|
+
}
|
|
211256
|
+
if (hasRoutesDirectory) {
|
|
211257
|
+
mediumSignals += 1;
|
|
211258
|
+
score += 6;
|
|
211259
|
+
evidence.push("Found routes/ or src/routes/ directory");
|
|
211260
|
+
}
|
|
211261
|
+
if (hasRouteFiles) {
|
|
211262
|
+
mediumSignals += 1;
|
|
211263
|
+
score += 5;
|
|
211264
|
+
evidence.push("Found route files under routes/");
|
|
211265
|
+
}
|
|
211266
|
+
const hasSafeExpressEvidence = hasExpressDependency && (hasExpressFactory || hasExpressImport || hasAppUse || hasRouterUsage || hasRoutesDirectory);
|
|
211267
|
+
if (!hasSafeExpressEvidence) {
|
|
211268
|
+
return null;
|
|
211269
|
+
}
|
|
211270
|
+
const confidence = strongSignals >= 2 || strongSignals >= 1 && mediumSignals >= 2 ? "high" : strongSignals >= 1 ? "medium" : "low";
|
|
211271
|
+
return toResult({
|
|
211272
|
+
adapterId: "express",
|
|
211273
|
+
confidence,
|
|
211274
|
+
score,
|
|
211275
|
+
evidence,
|
|
211276
|
+
projectKindHints: ["backend"],
|
|
211277
|
+
apiStyleHint: "rest"
|
|
211278
|
+
});
|
|
211279
|
+
},
|
|
211280
|
+
resolveProjectKinds: () => ["backend"],
|
|
211281
|
+
getImportExtractionMode: () => "typescript-imports"
|
|
211282
|
+
}),
|
|
211176
211283
|
nestjs: buildAdapter({
|
|
211177
211284
|
id: "nestjs",
|
|
211178
211285
|
displayName: canonicalStackLabels.nestjs,
|
|
@@ -211448,9 +211555,9 @@ var stackAdaptersById = {
|
|
|
211448
211555
|
],
|
|
211449
211556
|
buildToolHints: ["maven", "gradle"],
|
|
211450
211557
|
defaults: {
|
|
211451
|
-
sourceRoots: ["src/main/java", "src"],
|
|
211452
|
-
moduleRootCandidates: ["src/main/java"],
|
|
211453
|
-
apiRoots: ["src/main/java"],
|
|
211558
|
+
sourceRoots: ["src/main/java", "src/main/kotlin", "src"],
|
|
211559
|
+
moduleRootCandidates: ["src/main/java", "src/main/kotlin"],
|
|
211560
|
+
apiRoots: ["src/main/java", "src/main/kotlin"],
|
|
211454
211561
|
databaseRoots: ["src/main/resources", "src/main/resources/db"],
|
|
211455
211562
|
configFiles: [
|
|
211456
211563
|
"pom.xml",
|
|
@@ -211470,7 +211577,7 @@ var stackAdaptersById = {
|
|
|
211470
211577
|
"out",
|
|
211471
211578
|
...commonIgnoreDirectories
|
|
211472
211579
|
],
|
|
211473
|
-
entrypointHints: ["src/main/java"],
|
|
211580
|
+
entrypointHints: ["src/main/java", "src/main/kotlin", "Application.java", "Application.kt"],
|
|
211474
211581
|
publicEntrypointDirectories: [],
|
|
211475
211582
|
moduleIndexFileName: "Application.java"
|
|
211476
211583
|
},
|
|
@@ -211496,7 +211603,7 @@ var stackAdaptersById = {
|
|
|
211496
211603
|
/\.(java|kt)$/iu,
|
|
211497
211604
|
/@SpringBootApplication\b/u
|
|
211498
211605
|
);
|
|
211499
|
-
const
|
|
211606
|
+
const hasMainSourceWithDependencies = (context.hasDirectory("src/main/java") || context.hasDirectory("src/main/kotlin")) && hasSpringDependencyEvidence;
|
|
211500
211607
|
const hasApplicationConfigWithDependencies = (context.hasFile("application.yml") || context.hasFile("application.yaml") || context.hasFile("application.properties")) && hasSpringDependencyEvidence;
|
|
211501
211608
|
const hasRestController = context.hasAnyFileMatchingPattern(
|
|
211502
211609
|
/\.(java|kt)$/iu,
|
|
@@ -211520,9 +211627,9 @@ var stackAdaptersById = {
|
|
|
211520
211627
|
);
|
|
211521
211628
|
const hasResourcesDirectory = context.hasDirectory("src/main/resources");
|
|
211522
211629
|
const hasWrapperWithSpringEvidence = (context.hasFile("mvnw") || context.hasFile("gradlew")) && hasSpringDependencyEvidence;
|
|
211523
|
-
const
|
|
211630
|
+
const hasTestJvmSource = context.hasDirectory("src/test/java") || context.hasDirectory("src/test/kotlin");
|
|
211524
211631
|
const hasBootstrapConfig = context.hasFile("bootstrap.yml") || context.hasFile("bootstrap.yaml");
|
|
211525
|
-
const
|
|
211632
|
+
const hasJvmPackageShape = context.hasDirectory("src/main/java/com") || context.hasDirectory("src/main/java/org") || context.hasDirectory("src/main/kotlin/com") || context.hasDirectory("src/main/kotlin/org");
|
|
211526
211633
|
if (hasPomSpringDependency) {
|
|
211527
211634
|
strongSignals += 1;
|
|
211528
211635
|
score += 54;
|
|
@@ -211538,10 +211645,10 @@ var stackAdaptersById = {
|
|
|
211538
211645
|
score += 44;
|
|
211539
211646
|
evidence.push("Found @SpringBootApplication in source");
|
|
211540
211647
|
}
|
|
211541
|
-
if (
|
|
211648
|
+
if (hasMainSourceWithDependencies) {
|
|
211542
211649
|
strongSignals += 1;
|
|
211543
211650
|
score += 20;
|
|
211544
|
-
evidence.push("Found
|
|
211651
|
+
evidence.push("Found JVM main source root with Spring dependency evidence");
|
|
211545
211652
|
}
|
|
211546
211653
|
if (hasApplicationConfigWithDependencies) {
|
|
211547
211654
|
strongSignals += 1;
|
|
@@ -211583,22 +211690,22 @@ var stackAdaptersById = {
|
|
|
211583
211690
|
score += 4;
|
|
211584
211691
|
evidence.push("Found Maven/Gradle wrapper with Spring dependency evidence");
|
|
211585
211692
|
}
|
|
211586
|
-
if (
|
|
211693
|
+
if (hasTestJvmSource) {
|
|
211587
211694
|
weakSignals += 1;
|
|
211588
211695
|
score += 2;
|
|
211589
|
-
evidence.push("Found
|
|
211696
|
+
evidence.push("Found JVM test source directory");
|
|
211590
211697
|
}
|
|
211591
211698
|
if (hasBootstrapConfig) {
|
|
211592
211699
|
weakSignals += 1;
|
|
211593
211700
|
score += 2;
|
|
211594
211701
|
evidence.push("Found bootstrap.yml or bootstrap.yaml");
|
|
211595
211702
|
}
|
|
211596
|
-
if (
|
|
211703
|
+
if (hasJvmPackageShape) {
|
|
211597
211704
|
weakSignals += 1;
|
|
211598
211705
|
score += 1;
|
|
211599
|
-
evidence.push("Found conventional
|
|
211706
|
+
evidence.push("Found conventional JVM package directory under main source root");
|
|
211600
211707
|
}
|
|
211601
|
-
const hasSafeSpringCoreEvidence = hasSpringDependencyEvidence || hasSpringBootApplication || (hasRestController || hasController || hasService || hasRepository || hasMappingAnnotation) && (context.hasDirectory("src/main/java") || hasResourcesDirectory);
|
|
211708
|
+
const hasSafeSpringCoreEvidence = hasSpringDependencyEvidence || hasSpringBootApplication || (hasRestController || hasController || hasService || hasRepository || hasMappingAnnotation) && (context.hasDirectory("src/main/java") || context.hasDirectory("src/main/kotlin") || hasResourcesDirectory);
|
|
211602
211709
|
if (!hasSafeSpringCoreEvidence || strongSignals === 0) {
|
|
211603
211710
|
return null;
|
|
211604
211711
|
}
|
|
@@ -211805,6 +211912,326 @@ var stackAdaptersById = {
|
|
|
211805
211912
|
resolveProjectKinds: () => ["backend"],
|
|
211806
211913
|
getImportExtractionMode: () => "python-imports"
|
|
211807
211914
|
}),
|
|
211915
|
+
django: buildAdapter({
|
|
211916
|
+
id: "django",
|
|
211917
|
+
displayName: canonicalStackLabels.django,
|
|
211918
|
+
ecosystem: "python",
|
|
211919
|
+
category: "framework",
|
|
211920
|
+
priority: 68,
|
|
211921
|
+
manifestDetectionHints: [
|
|
211922
|
+
"requirements.txt",
|
|
211923
|
+
"pyproject.toml",
|
|
211924
|
+
"Pipfile",
|
|
211925
|
+
"Pipfile.lock",
|
|
211926
|
+
"poetry.lock",
|
|
211927
|
+
"manage.py",
|
|
211928
|
+
"settings.py",
|
|
211929
|
+
"urls.py",
|
|
211930
|
+
"wsgi.py",
|
|
211931
|
+
"asgi.py"
|
|
211932
|
+
],
|
|
211933
|
+
buildToolHints: ["pip", "poetry", "django-admin"],
|
|
211934
|
+
defaults: {
|
|
211935
|
+
sourceRoots: [".", "src", "app"],
|
|
211936
|
+
moduleRootCandidates: [".", "src", "app"],
|
|
211937
|
+
apiRoots: [".", "src", "app"],
|
|
211938
|
+
databaseRoots: ["migrations", "db", "database"],
|
|
211939
|
+
configFiles: ["requirements.txt", "pyproject.toml", "Pipfile", "Pipfile.lock", "poetry.lock", "manage.py"],
|
|
211940
|
+
fileExtensions: [".py", ".toml", ".txt", ".sql", ".yaml", ".yml"],
|
|
211941
|
+
dependencyFileExtensions: [".py"],
|
|
211942
|
+
ignoreDirectories: [
|
|
211943
|
+
"__pycache__",
|
|
211944
|
+
".pytest_cache",
|
|
211945
|
+
".venv",
|
|
211946
|
+
"venv",
|
|
211947
|
+
"dist",
|
|
211948
|
+
"build",
|
|
211949
|
+
".idea",
|
|
211950
|
+
...commonIgnoreDirectories
|
|
211951
|
+
],
|
|
211952
|
+
entrypointHints: ["manage.py", "wsgi.py", "asgi.py", "settings.py", "urls.py"],
|
|
211953
|
+
publicEntrypointDirectories: [],
|
|
211954
|
+
moduleIndexFileName: "__init__.py"
|
|
211955
|
+
},
|
|
211956
|
+
detect: (context) => {
|
|
211957
|
+
const evidence = [];
|
|
211958
|
+
let strongSignals = 0;
|
|
211959
|
+
let mediumSignals = 0;
|
|
211960
|
+
let weakSignals = 0;
|
|
211961
|
+
let score = 0;
|
|
211962
|
+
const hasRequirementsDjango = context.hasFileMatchingPattern(
|
|
211963
|
+
"requirements.txt",
|
|
211964
|
+
/(^|\s)django([=<>~!]|$)/imu
|
|
211965
|
+
);
|
|
211966
|
+
const hasPyprojectDjango = context.hasFileMatchingPattern("pyproject.toml", /\bdjango\b/iu);
|
|
211967
|
+
const hasPoetryLockDjango = context.hasFileMatchingPattern(
|
|
211968
|
+
"poetry.lock",
|
|
211969
|
+
/\bname\s*=\s*["']django["']/iu
|
|
211970
|
+
);
|
|
211971
|
+
const hasPipfileDjango = context.hasFileMatchingPattern("Pipfile", /\bdjango\b/iu);
|
|
211972
|
+
const hasPipfileLockDjango = context.hasFileMatchingPattern("Pipfile.lock", /"django"\s*:/iu);
|
|
211973
|
+
const hasDjangoDependencyEvidence = hasRequirementsDjango || hasPyprojectDjango || hasPoetryLockDjango || hasPipfileDjango || hasPipfileLockDjango;
|
|
211974
|
+
const hasManagePy = context.hasFile("manage.py");
|
|
211975
|
+
const hasDjangoSettingsModule = context.hasFileMatchingPattern(
|
|
211976
|
+
"manage.py",
|
|
211977
|
+
/\bDJANGO_SETTINGS_MODULE\b/u
|
|
211978
|
+
);
|
|
211979
|
+
const hasSettingsPy = context.hasFile("settings.py");
|
|
211980
|
+
const hasUrlsPy = context.hasFile("urls.py");
|
|
211981
|
+
const hasWsgiOrAsgi = context.hasFile("wsgi.py") || context.hasFile("asgi.py");
|
|
211982
|
+
const hasInstalledApps = context.hasFileMatchingPattern("settings.py", /\bINSTALLED_APPS\s*=/u);
|
|
211983
|
+
const hasDjangoAdmin = context.hasAnyFileMatchingPattern(/(^|\/)(manage|settings|urls|wsgi|asgi)\.py$/iu, /\bdjango-admin\b/iu);
|
|
211984
|
+
const hasDjangoImport = context.hasAnyFileMatchingPattern(/\.py$/iu, /\b(from|import)\s+django\b/u);
|
|
211985
|
+
const hasDjangoUrlsImport = context.hasAnyFileMatchingPattern(
|
|
211986
|
+
/\.py$/iu,
|
|
211987
|
+
/\bfrom\s+django\.urls\s+import\s+(?:path|include|re_path)\b/u
|
|
211988
|
+
);
|
|
211989
|
+
if (hasRequirementsDjango) {
|
|
211990
|
+
strongSignals += 1;
|
|
211991
|
+
score += 52;
|
|
211992
|
+
evidence.push("Found requirements.txt with django dependency");
|
|
211993
|
+
}
|
|
211994
|
+
if (hasPyprojectDjango) {
|
|
211995
|
+
strongSignals += 1;
|
|
211996
|
+
score += 52;
|
|
211997
|
+
evidence.push("Found pyproject.toml with django dependency");
|
|
211998
|
+
}
|
|
211999
|
+
if (hasPoetryLockDjango || hasPipfileDjango || hasPipfileLockDjango) {
|
|
212000
|
+
strongSignals += 1;
|
|
212001
|
+
score += 50;
|
|
212002
|
+
evidence.push("Found Pipfile/lock metadata with django dependency");
|
|
212003
|
+
}
|
|
212004
|
+
if (hasManagePy) {
|
|
212005
|
+
strongSignals += 1;
|
|
212006
|
+
score += 34;
|
|
212007
|
+
evidence.push("Found manage.py");
|
|
212008
|
+
}
|
|
212009
|
+
if (hasDjangoSettingsModule) {
|
|
212010
|
+
strongSignals += 1;
|
|
212011
|
+
score += 24;
|
|
212012
|
+
evidence.push("Found DJANGO_SETTINGS_MODULE in manage.py");
|
|
212013
|
+
}
|
|
212014
|
+
if (hasInstalledApps) {
|
|
212015
|
+
strongSignals += 1;
|
|
212016
|
+
score += 24;
|
|
212017
|
+
evidence.push("Found INSTALLED_APPS in settings.py");
|
|
212018
|
+
}
|
|
212019
|
+
if (hasDjangoImport) {
|
|
212020
|
+
strongSignals += 1;
|
|
212021
|
+
score += 22;
|
|
212022
|
+
evidence.push("Found django import in source");
|
|
212023
|
+
}
|
|
212024
|
+
if (hasSettingsPy) {
|
|
212025
|
+
mediumSignals += 1;
|
|
212026
|
+
score += 12;
|
|
212027
|
+
evidence.push("Found settings.py");
|
|
212028
|
+
}
|
|
212029
|
+
if (hasUrlsPy) {
|
|
212030
|
+
mediumSignals += 1;
|
|
212031
|
+
score += 10;
|
|
212032
|
+
evidence.push("Found urls.py");
|
|
212033
|
+
}
|
|
212034
|
+
if (hasWsgiOrAsgi) {
|
|
212035
|
+
mediumSignals += 1;
|
|
212036
|
+
score += 10;
|
|
212037
|
+
evidence.push("Found wsgi.py or asgi.py");
|
|
212038
|
+
}
|
|
212039
|
+
if (hasDjangoUrlsImport) {
|
|
212040
|
+
mediumSignals += 1;
|
|
212041
|
+
score += 10;
|
|
212042
|
+
evidence.push("Found Django URL routing import");
|
|
212043
|
+
}
|
|
212044
|
+
if (hasDjangoAdmin) {
|
|
212045
|
+
weakSignals += 1;
|
|
212046
|
+
score += 3;
|
|
212047
|
+
evidence.push("Found django-admin reference");
|
|
212048
|
+
}
|
|
212049
|
+
if (context.hasDirectory("migrations")) {
|
|
212050
|
+
weakSignals += 1;
|
|
212051
|
+
score += 2;
|
|
212052
|
+
evidence.push("Found migrations directory");
|
|
212053
|
+
}
|
|
212054
|
+
const hasSafeDjangoCoreEvidence = hasDjangoDependencyEvidence || hasManagePy && (hasDjangoSettingsModule || hasSettingsPy || hasUrlsPy || hasWsgiOrAsgi) || hasInstalledApps && (hasSettingsPy || hasDjangoImport) || hasDjangoImport && (hasDjangoUrlsImport || hasUrlsPy);
|
|
212055
|
+
if (!hasSafeDjangoCoreEvidence || strongSignals === 0) {
|
|
212056
|
+
return null;
|
|
212057
|
+
}
|
|
212058
|
+
const hasRestEvidence = hasUrlsPy || hasDjangoUrlsImport;
|
|
212059
|
+
const confidence = strongSignals >= 2 ? "high" : strongSignals >= 1 || mediumSignals >= 3 || mediumSignals >= 2 && weakSignals >= 1 ? "medium" : "low";
|
|
212060
|
+
return toResult({
|
|
212061
|
+
adapterId: "django",
|
|
212062
|
+
confidence,
|
|
212063
|
+
score,
|
|
212064
|
+
evidence,
|
|
212065
|
+
projectKindHints: ["backend"],
|
|
212066
|
+
apiStyleHint: hasRestEvidence ? "rest" : "unknown"
|
|
212067
|
+
});
|
|
212068
|
+
},
|
|
212069
|
+
resolveProjectKinds: () => ["backend"],
|
|
212070
|
+
getImportExtractionMode: () => "python-imports"
|
|
212071
|
+
}),
|
|
212072
|
+
flask: buildAdapter({
|
|
212073
|
+
id: "flask",
|
|
212074
|
+
displayName: canonicalStackLabels.flask,
|
|
212075
|
+
ecosystem: "python",
|
|
212076
|
+
category: "framework",
|
|
212077
|
+
priority: 66,
|
|
212078
|
+
manifestDetectionHints: [
|
|
212079
|
+
"requirements.txt",
|
|
212080
|
+
"pyproject.toml",
|
|
212081
|
+
"Pipfile",
|
|
212082
|
+
"Pipfile.lock",
|
|
212083
|
+
"poetry.lock",
|
|
212084
|
+
"app.py",
|
|
212085
|
+
"wsgi.py",
|
|
212086
|
+
"main.py"
|
|
212087
|
+
],
|
|
212088
|
+
buildToolHints: ["pip", "poetry", "flask"],
|
|
212089
|
+
defaults: {
|
|
212090
|
+
sourceRoots: ["app", "src", "."],
|
|
212091
|
+
moduleRootCandidates: ["app", "src/app", "src", "blueprints", "api"],
|
|
212092
|
+
apiRoots: ["app", "src", "blueprints", "api"],
|
|
212093
|
+
databaseRoots: ["migrations", "app/db", "app/database", "src/db", "src/database"],
|
|
212094
|
+
configFiles: ["requirements.txt", "pyproject.toml", "Pipfile", "Pipfile.lock", "poetry.lock"],
|
|
212095
|
+
fileExtensions: [".py", ".toml", ".txt", ".sql", ".yaml", ".yml"],
|
|
212096
|
+
dependencyFileExtensions: [".py"],
|
|
212097
|
+
ignoreDirectories: [
|
|
212098
|
+
"__pycache__",
|
|
212099
|
+
".pytest_cache",
|
|
212100
|
+
".venv",
|
|
212101
|
+
"venv",
|
|
212102
|
+
"dist",
|
|
212103
|
+
"build",
|
|
212104
|
+
".idea",
|
|
212105
|
+
...commonIgnoreDirectories
|
|
212106
|
+
],
|
|
212107
|
+
entrypointHints: ["app.py", "main.py", "wsgi.py", "app/__init__.py"],
|
|
212108
|
+
publicEntrypointDirectories: [],
|
|
212109
|
+
moduleIndexFileName: "__init__.py"
|
|
212110
|
+
},
|
|
212111
|
+
detect: (context) => {
|
|
212112
|
+
const evidence = [];
|
|
212113
|
+
let strongSignals = 0;
|
|
212114
|
+
let mediumSignals = 0;
|
|
212115
|
+
let weakSignals = 0;
|
|
212116
|
+
let score = 0;
|
|
212117
|
+
const hasRequirementsFlask = context.hasFileMatchingPattern(
|
|
212118
|
+
"requirements.txt",
|
|
212119
|
+
/(^|\s)flask([=<>~!]|$)/imu
|
|
212120
|
+
);
|
|
212121
|
+
const hasPyprojectFlask = context.hasFileMatchingPattern("pyproject.toml", /\bflask\b/iu);
|
|
212122
|
+
const hasPoetryLockFlask = context.hasFileMatchingPattern(
|
|
212123
|
+
"poetry.lock",
|
|
212124
|
+
/\bname\s*=\s*["']flask["']/iu
|
|
212125
|
+
);
|
|
212126
|
+
const hasPipfileFlask = context.hasFileMatchingPattern("Pipfile", /\bflask\b/iu);
|
|
212127
|
+
const hasPipfileLockFlask = context.hasFileMatchingPattern("Pipfile.lock", /"flask"\s*:/iu);
|
|
212128
|
+
const hasFlaskDependencyEvidence = hasRequirementsFlask || hasPyprojectFlask || hasPoetryLockFlask || hasPipfileFlask || hasPipfileLockFlask;
|
|
212129
|
+
const hasFlaskImport = context.hasAnyFileMatchingPattern(
|
|
212130
|
+
/\.py$/iu,
|
|
212131
|
+
/\bfrom\s+flask\s+import\s+.*\bFlask\b/u
|
|
212132
|
+
);
|
|
212133
|
+
const hasFlaskConstruction = context.hasAnyFileMatchingPattern(
|
|
212134
|
+
/\.py$/iu,
|
|
212135
|
+
/\b\w+\s*=\s*Flask\s*\(\s*__name__/u
|
|
212136
|
+
);
|
|
212137
|
+
const hasRouteDecorator = context.hasAnyFileMatchingPattern(
|
|
212138
|
+
/\.py$/iu,
|
|
212139
|
+
/@\w+\.route\s*\(/u
|
|
212140
|
+
);
|
|
212141
|
+
const hasMethodRouteDecorator = context.hasAnyFileMatchingPattern(
|
|
212142
|
+
/\.py$/iu,
|
|
212143
|
+
/@\w+\.(?:get|post|put|delete)\s*\(/u
|
|
212144
|
+
);
|
|
212145
|
+
const hasBlueprintImport = context.hasAnyFileMatchingPattern(
|
|
212146
|
+
/\.py$/iu,
|
|
212147
|
+
/\bfrom\s+flask\s+import\s+.*\bBlueprint\b/u
|
|
212148
|
+
);
|
|
212149
|
+
const hasBlueprintConstruction = context.hasAnyFileMatchingPattern(
|
|
212150
|
+
/\.py$/iu,
|
|
212151
|
+
/\b\w+\s*=\s*Blueprint\s*\(/u
|
|
212152
|
+
);
|
|
212153
|
+
const hasFlaskEntrypointConstruction = context.hasAnyFileMatchingPattern(
|
|
212154
|
+
/(^|\/)(app|main|wsgi)\.py$/iu,
|
|
212155
|
+
/\b\w+\s*=\s*Flask\s*\(/u
|
|
212156
|
+
);
|
|
212157
|
+
if (hasRequirementsFlask) {
|
|
212158
|
+
strongSignals += 1;
|
|
212159
|
+
score += 52;
|
|
212160
|
+
evidence.push("Found requirements.txt with flask dependency");
|
|
212161
|
+
}
|
|
212162
|
+
if (hasPyprojectFlask) {
|
|
212163
|
+
strongSignals += 1;
|
|
212164
|
+
score += 52;
|
|
212165
|
+
evidence.push("Found pyproject.toml with flask dependency");
|
|
212166
|
+
}
|
|
212167
|
+
if (hasPoetryLockFlask || hasPipfileFlask || hasPipfileLockFlask) {
|
|
212168
|
+
strongSignals += 1;
|
|
212169
|
+
score += 50;
|
|
212170
|
+
evidence.push("Found Pipfile/lock metadata with flask dependency");
|
|
212171
|
+
}
|
|
212172
|
+
if (hasFlaskImport) {
|
|
212173
|
+
strongSignals += 1;
|
|
212174
|
+
score += 34;
|
|
212175
|
+
evidence.push("Found Flask import in source");
|
|
212176
|
+
}
|
|
212177
|
+
if (hasFlaskConstruction) {
|
|
212178
|
+
strongSignals += 1;
|
|
212179
|
+
score += 34;
|
|
212180
|
+
evidence.push("Found Flask application construction in source");
|
|
212181
|
+
}
|
|
212182
|
+
if (hasRouteDecorator) {
|
|
212183
|
+
strongSignals += 1;
|
|
212184
|
+
score += 22;
|
|
212185
|
+
evidence.push("Found Flask route decorator in source");
|
|
212186
|
+
}
|
|
212187
|
+
if (hasMethodRouteDecorator) {
|
|
212188
|
+
mediumSignals += 1;
|
|
212189
|
+
score += 10;
|
|
212190
|
+
evidence.push("Found Flask method route decorator in source");
|
|
212191
|
+
}
|
|
212192
|
+
if (hasBlueprintImport) {
|
|
212193
|
+
mediumSignals += 1;
|
|
212194
|
+
score += 10;
|
|
212195
|
+
evidence.push("Found Blueprint import in source");
|
|
212196
|
+
}
|
|
212197
|
+
if (hasBlueprintConstruction) {
|
|
212198
|
+
mediumSignals += 1;
|
|
212199
|
+
score += 8;
|
|
212200
|
+
evidence.push("Found Blueprint construction in source");
|
|
212201
|
+
}
|
|
212202
|
+
if (hasFlaskEntrypointConstruction) {
|
|
212203
|
+
mediumSignals += 1;
|
|
212204
|
+
score += 8;
|
|
212205
|
+
evidence.push("Found Flask construction in app.py/main.py/wsgi.py");
|
|
212206
|
+
}
|
|
212207
|
+
if (context.hasDirectory("blueprints")) {
|
|
212208
|
+
weakSignals += 1;
|
|
212209
|
+
score += 2;
|
|
212210
|
+
evidence.push("Found blueprints directory");
|
|
212211
|
+
}
|
|
212212
|
+
if (context.hasDirectory("app") || context.hasDirectory("src")) {
|
|
212213
|
+
weakSignals += 1;
|
|
212214
|
+
score += 2;
|
|
212215
|
+
evidence.push("Found typical Python backend layout directory");
|
|
212216
|
+
}
|
|
212217
|
+
const hasSafeFlaskCoreEvidence = hasFlaskDependencyEvidence || hasFlaskImport && hasFlaskConstruction || hasFlaskImport && (hasRouteDecorator || hasMethodRouteDecorator || hasBlueprintImport) || hasBlueprintImport && hasBlueprintConstruction;
|
|
212218
|
+
if (!hasSafeFlaskCoreEvidence || strongSignals === 0) {
|
|
212219
|
+
return null;
|
|
212220
|
+
}
|
|
212221
|
+
const hasRestEvidence = hasRouteDecorator || hasMethodRouteDecorator || hasBlueprintImport;
|
|
212222
|
+
const confidence = strongSignals >= 2 ? "high" : strongSignals >= 1 || mediumSignals >= 3 || mediumSignals >= 2 && weakSignals >= 1 ? "medium" : "low";
|
|
212223
|
+
return toResult({
|
|
212224
|
+
adapterId: "flask",
|
|
212225
|
+
confidence,
|
|
212226
|
+
score,
|
|
212227
|
+
evidence,
|
|
212228
|
+
projectKindHints: ["backend"],
|
|
212229
|
+
apiStyleHint: hasRestEvidence ? "rest" : "unknown"
|
|
212230
|
+
});
|
|
212231
|
+
},
|
|
212232
|
+
resolveProjectKinds: () => ["backend"],
|
|
212233
|
+
getImportExtractionMode: () => "python-imports"
|
|
212234
|
+
}),
|
|
211808
212235
|
python: buildAdapter({
|
|
211809
212236
|
id: "python",
|
|
211810
212237
|
displayName: canonicalStackLabels.python,
|
|
@@ -211867,6 +212294,101 @@ var stackAdaptersById = {
|
|
|
211867
212294
|
resolveProjectKinds: () => ["backend", "library"],
|
|
211868
212295
|
getImportExtractionMode: () => "python-imports"
|
|
211869
212296
|
}),
|
|
212297
|
+
laravel: buildAdapter({
|
|
212298
|
+
id: "laravel",
|
|
212299
|
+
displayName: canonicalStackLabels.laravel,
|
|
212300
|
+
ecosystem: "php",
|
|
212301
|
+
category: "framework",
|
|
212302
|
+
priority: 70,
|
|
212303
|
+
manifestDetectionHints: ["composer.json", "artisan", "web.php", "api.php", "app.php"],
|
|
212304
|
+
buildToolHints: ["composer", "artisan"],
|
|
212305
|
+
defaults: {
|
|
212306
|
+
sourceRoots: ["app", "routes", "config"],
|
|
212307
|
+
moduleRootCandidates: ["app/Modules", "app/Services", "app/Http/Controllers", "app"],
|
|
212308
|
+
apiRoots: ["routes", "app/Http/Controllers"],
|
|
212309
|
+
databaseRoots: ["database", "database/migrations"],
|
|
212310
|
+
configFiles: ["composer.json", "artisan", "config/app.php"],
|
|
212311
|
+
fileExtensions: [".php"],
|
|
212312
|
+
dependencyFileExtensions: [".php"],
|
|
212313
|
+
ignoreDirectories: [
|
|
212314
|
+
"vendor",
|
|
212315
|
+
"storage",
|
|
212316
|
+
"bootstrap/cache",
|
|
212317
|
+
"public",
|
|
212318
|
+
...commonIgnoreDirectories
|
|
212319
|
+
],
|
|
212320
|
+
entrypointHints: ["artisan", "public/index.php", "bootstrap/app.php"],
|
|
212321
|
+
publicEntrypointDirectories: [],
|
|
212322
|
+
moduleIndexFileName: "index.php"
|
|
212323
|
+
},
|
|
212324
|
+
detect: (context) => {
|
|
212325
|
+
const evidence = [];
|
|
212326
|
+
let strongSignals = 0;
|
|
212327
|
+
let mediumSignals = 0;
|
|
212328
|
+
let score = 0;
|
|
212329
|
+
const hasLaravelComposer = context.hasFileMatchingPattern(
|
|
212330
|
+
"composer.json",
|
|
212331
|
+
/["']laravel\/framework["']/iu
|
|
212332
|
+
);
|
|
212333
|
+
const hasArtisan = context.hasFile("artisan");
|
|
212334
|
+
const hasRoutesWeb = context.hasAnyPathMatchingPattern(/(^|\/)routes\/web\.php$/iu);
|
|
212335
|
+
const hasRoutesApi = context.hasAnyPathMatchingPattern(/(^|\/)routes\/api\.php$/iu);
|
|
212336
|
+
const hasControllers = context.hasDirectory("app/Http/Controllers");
|
|
212337
|
+
const hasConfigApp = context.hasAnyPathMatchingPattern(/(^|\/)config\/app\.php$/iu);
|
|
212338
|
+
const hasLaravelRouteFacade = context.hasAnyFileMatchingPattern(
|
|
212339
|
+
/(^|\/)routes\/.+\.php$/iu,
|
|
212340
|
+
/\bRoute::(get|post|put|patch|delete|middleware|group)\s*\(/u
|
|
212341
|
+
);
|
|
212342
|
+
if (hasLaravelComposer) {
|
|
212343
|
+
strongSignals += 1;
|
|
212344
|
+
score += 50;
|
|
212345
|
+
evidence.push("Found composer.json with laravel/framework dependency");
|
|
212346
|
+
}
|
|
212347
|
+
if (hasArtisan) {
|
|
212348
|
+
strongSignals += 1;
|
|
212349
|
+
score += 18;
|
|
212350
|
+
evidence.push("Found artisan entrypoint");
|
|
212351
|
+
}
|
|
212352
|
+
if (hasRoutesWeb) {
|
|
212353
|
+
mediumSignals += 1;
|
|
212354
|
+
score += 10;
|
|
212355
|
+
evidence.push("Found routes/web.php");
|
|
212356
|
+
}
|
|
212357
|
+
if (hasRoutesApi) {
|
|
212358
|
+
mediumSignals += 1;
|
|
212359
|
+
score += 10;
|
|
212360
|
+
evidence.push("Found routes/api.php");
|
|
212361
|
+
}
|
|
212362
|
+
if (hasControllers) {
|
|
212363
|
+
mediumSignals += 1;
|
|
212364
|
+
score += 10;
|
|
212365
|
+
evidence.push("Found app/Http/Controllers directory");
|
|
212366
|
+
}
|
|
212367
|
+
if (hasConfigApp) {
|
|
212368
|
+
mediumSignals += 1;
|
|
212369
|
+
score += 6;
|
|
212370
|
+
evidence.push("Found config/app.php");
|
|
212371
|
+
}
|
|
212372
|
+
if (hasLaravelRouteFacade) {
|
|
212373
|
+
mediumSignals += 1;
|
|
212374
|
+
score += 8;
|
|
212375
|
+
evidence.push("Found Laravel Route facade usage");
|
|
212376
|
+
}
|
|
212377
|
+
if (!hasLaravelComposer || !(hasArtisan || hasRoutesWeb || hasRoutesApi || hasControllers)) {
|
|
212378
|
+
return null;
|
|
212379
|
+
}
|
|
212380
|
+
return toResult({
|
|
212381
|
+
adapterId: "laravel",
|
|
212382
|
+
confidence: strongSignals >= 2 || mediumSignals >= 2 ? "high" : "medium",
|
|
212383
|
+
score,
|
|
212384
|
+
evidence,
|
|
212385
|
+
projectKindHints: ["backend"],
|
|
212386
|
+
apiStyleHint: hasRoutesApi || hasLaravelRouteFacade ? "rest" : "unknown"
|
|
212387
|
+
});
|
|
212388
|
+
},
|
|
212389
|
+
resolveProjectKinds: () => ["backend"],
|
|
212390
|
+
getImportExtractionMode: () => "php-imports"
|
|
212391
|
+
}),
|
|
211870
212392
|
php: buildAdapter({
|
|
211871
212393
|
id: "php",
|
|
211872
212394
|
displayName: canonicalStackLabels.php,
|
|
@@ -212154,23 +212676,182 @@ var stackAdaptersById = {
|
|
|
212154
212676
|
displayName: canonicalStackLabels.ruby_rails,
|
|
212155
212677
|
ecosystem: "other",
|
|
212156
212678
|
category: "framework",
|
|
212157
|
-
priority:
|
|
212158
|
-
manifestDetectionHints: ["Gemfile"],
|
|
212679
|
+
priority: 70,
|
|
212680
|
+
manifestDetectionHints: ["Gemfile", "rails", "routes.rb", "application.rb"],
|
|
212159
212681
|
buildToolHints: ["bundle"],
|
|
212160
212682
|
defaults: {
|
|
212161
|
-
sourceRoots: ["app"],
|
|
212162
|
-
moduleRootCandidates: ["app"],
|
|
212163
|
-
apiRoots: ["app/controllers"],
|
|
212683
|
+
sourceRoots: ["app", "config"],
|
|
212684
|
+
moduleRootCandidates: ["app/services", "app/controllers", "app/models", "app"],
|
|
212685
|
+
apiRoots: ["app/controllers", "config/routes.rb"],
|
|
212164
212686
|
databaseRoots: ["db"],
|
|
212165
|
-
configFiles: ["Gemfile"],
|
|
212687
|
+
configFiles: ["Gemfile", "config/routes.rb", "config/application.rb"],
|
|
212166
212688
|
fileExtensions: [".rb"],
|
|
212167
212689
|
dependencyFileExtensions: [".rb"],
|
|
212168
|
-
ignoreDirectories: [...commonIgnoreDirectories],
|
|
212690
|
+
ignoreDirectories: ["vendor", "tmp", "log", ...commonIgnoreDirectories],
|
|
212169
212691
|
entrypointHints: ["config/application.rb"],
|
|
212170
212692
|
publicEntrypointDirectories: [],
|
|
212171
212693
|
moduleIndexFileName: "application.rb"
|
|
212172
212694
|
},
|
|
212173
|
-
detect: () =>
|
|
212695
|
+
detect: (context) => {
|
|
212696
|
+
const evidence = [];
|
|
212697
|
+
let strongSignals = 0;
|
|
212698
|
+
let mediumSignals = 0;
|
|
212699
|
+
let score = 0;
|
|
212700
|
+
const hasRailsGem = context.hasFileMatchingPattern("Gemfile", /\bgem\s+['"]rails['"]/u);
|
|
212701
|
+
const hasBinRails = context.hasAnyPathMatchingPattern(/(^|\/)bin\/rails$/u);
|
|
212702
|
+
const hasRoutes = context.hasAnyPathMatchingPattern(/(^|\/)config\/routes\.rb$/u);
|
|
212703
|
+
const hasControllers = context.hasDirectory("app/controllers");
|
|
212704
|
+
const hasModels = context.hasDirectory("app/models");
|
|
212705
|
+
const hasServices = context.hasDirectory("app/services");
|
|
212706
|
+
const hasRailsRoutesDraw = context.hasFileMatchingPattern("routes.rb", /\bRails\.application\.routes\.draw\b/u);
|
|
212707
|
+
const hasApplicationClass = context.hasAnyFileMatchingPattern(
|
|
212708
|
+
/(^|\/)config\/application\.rb$/u,
|
|
212709
|
+
/\bclass\s+Application\s+<\s+Rails::Application\b/u
|
|
212710
|
+
);
|
|
212711
|
+
const hasApplicationController = context.hasAnyFileMatchingPattern(
|
|
212712
|
+
/(^|\/)app\/controllers\/.+\.rb$/u,
|
|
212713
|
+
/\bApplicationController\b/u
|
|
212714
|
+
);
|
|
212715
|
+
if (hasRailsGem) {
|
|
212716
|
+
strongSignals += 1;
|
|
212717
|
+
score += 48;
|
|
212718
|
+
evidence.push("Found Gemfile with rails gem");
|
|
212719
|
+
}
|
|
212720
|
+
if (hasBinRails) {
|
|
212721
|
+
strongSignals += 1;
|
|
212722
|
+
score += 18;
|
|
212723
|
+
evidence.push("Found bin/rails");
|
|
212724
|
+
}
|
|
212725
|
+
if (hasRoutes) {
|
|
212726
|
+
mediumSignals += 1;
|
|
212727
|
+
score += 10;
|
|
212728
|
+
evidence.push("Found config/routes.rb");
|
|
212729
|
+
}
|
|
212730
|
+
if (hasControllers) {
|
|
212731
|
+
mediumSignals += 1;
|
|
212732
|
+
score += 8;
|
|
212733
|
+
evidence.push("Found app/controllers directory");
|
|
212734
|
+
}
|
|
212735
|
+
if (hasModels) {
|
|
212736
|
+
mediumSignals += 1;
|
|
212737
|
+
score += 6;
|
|
212738
|
+
evidence.push("Found app/models directory");
|
|
212739
|
+
}
|
|
212740
|
+
if (hasServices) {
|
|
212741
|
+
mediumSignals += 1;
|
|
212742
|
+
score += 5;
|
|
212743
|
+
evidence.push("Found app/services directory");
|
|
212744
|
+
}
|
|
212745
|
+
if (hasRailsRoutesDraw) {
|
|
212746
|
+
mediumSignals += 1;
|
|
212747
|
+
score += 8;
|
|
212748
|
+
evidence.push("Found Rails routes draw block");
|
|
212749
|
+
}
|
|
212750
|
+
if (hasApplicationClass) {
|
|
212751
|
+
mediumSignals += 1;
|
|
212752
|
+
score += 8;
|
|
212753
|
+
evidence.push("Found Rails application class");
|
|
212754
|
+
}
|
|
212755
|
+
if (hasApplicationController) {
|
|
212756
|
+
mediumSignals += 1;
|
|
212757
|
+
score += 5;
|
|
212758
|
+
evidence.push("Found ApplicationController inheritance");
|
|
212759
|
+
}
|
|
212760
|
+
if (!hasRailsGem || !(hasBinRails || hasRoutes || hasControllers || hasApplicationClass)) {
|
|
212761
|
+
return null;
|
|
212762
|
+
}
|
|
212763
|
+
return toResult({
|
|
212764
|
+
adapterId: "ruby_rails",
|
|
212765
|
+
confidence: strongSignals >= 2 || mediumSignals >= 3 ? "high" : "medium",
|
|
212766
|
+
score,
|
|
212767
|
+
evidence,
|
|
212768
|
+
projectKindHints: ["backend"],
|
|
212769
|
+
apiStyleHint: hasRoutes || hasControllers ? "rest" : "unknown"
|
|
212770
|
+
});
|
|
212771
|
+
},
|
|
212772
|
+
resolveProjectKinds: () => ["backend"],
|
|
212773
|
+
getImportExtractionMode: () => "generic"
|
|
212774
|
+
}),
|
|
212775
|
+
kotlin: buildAdapter({
|
|
212776
|
+
id: "kotlin",
|
|
212777
|
+
displayName: canonicalStackLabels.kotlin,
|
|
212778
|
+
ecosystem: "jvm",
|
|
212779
|
+
category: "generic-language",
|
|
212780
|
+
priority: 40,
|
|
212781
|
+
manifestDetectionHints: ["build.gradle.kts", "pom.xml", "settings.gradle.kts"],
|
|
212782
|
+
buildToolHints: ["gradle", "maven"],
|
|
212783
|
+
defaults: {
|
|
212784
|
+
sourceRoots: ["src/main/kotlin", "src"],
|
|
212785
|
+
moduleRootCandidates: ["src/main/kotlin", "src"],
|
|
212786
|
+
apiRoots: ["src/main/kotlin"],
|
|
212787
|
+
databaseRoots: ["src/main/resources/db", "src/main/resources/migrations"],
|
|
212788
|
+
configFiles: ["build.gradle.kts", "pom.xml", "settings.gradle.kts"],
|
|
212789
|
+
fileExtensions: [".kt", ".kts"],
|
|
212790
|
+
dependencyFileExtensions: [".kt", ".kts"],
|
|
212791
|
+
ignoreDirectories: [
|
|
212792
|
+
"target",
|
|
212793
|
+
"build",
|
|
212794
|
+
".gradle",
|
|
212795
|
+
".idea",
|
|
212796
|
+
"out",
|
|
212797
|
+
...commonIgnoreDirectories
|
|
212798
|
+
],
|
|
212799
|
+
entrypointHints: ["Application.kt", "Main.kt"],
|
|
212800
|
+
publicEntrypointDirectories: [],
|
|
212801
|
+
moduleIndexFileName: "Application.kt"
|
|
212802
|
+
},
|
|
212803
|
+
detect: (context) => {
|
|
212804
|
+
const evidence = [];
|
|
212805
|
+
let score = 0;
|
|
212806
|
+
const hasBuildGradleKts = context.hasFile("build.gradle.kts");
|
|
212807
|
+
const hasSettingsGradleKts = context.hasFile("settings.gradle.kts");
|
|
212808
|
+
const hasKotlinPluginInGradle = context.hasFileMatchingPattern("build.gradle.kts", /\bkotlin\s*\(\s*["']jvm["']\s*\)/u) || context.hasFileMatchingPattern("build.gradle.kts", /\bid\s*\(\s*["']org\.jetbrains\.kotlin\.jvm["']\s*\)/u);
|
|
212809
|
+
const hasPomKotlinPlugin = context.hasFileMatchingPattern("pom.xml", /\bkotlin-maven-plugin\b/u) || context.hasFileMatchingPattern("pom.xml", /\borg\.jetbrains\.kotlin\b/u);
|
|
212810
|
+
const hasKotlinSourceRoot = context.hasDirectory("src/main/kotlin");
|
|
212811
|
+
const hasKtFiles = context.hasFileExtension(".kt") || context.hasFileExtension(".kts");
|
|
212812
|
+
const hasKotlinPackageShape = context.hasDirectory("src/main/kotlin/com") || context.hasDirectory("src/main/kotlin/org");
|
|
212813
|
+
if (hasBuildGradleKts) {
|
|
212814
|
+
score += 30;
|
|
212815
|
+
evidence.push("Found build.gradle.kts");
|
|
212816
|
+
}
|
|
212817
|
+
if (hasSettingsGradleKts) {
|
|
212818
|
+
score += 8;
|
|
212819
|
+
evidence.push("Found settings.gradle.kts");
|
|
212820
|
+
}
|
|
212821
|
+
if (hasKotlinPluginInGradle) {
|
|
212822
|
+
score += 32;
|
|
212823
|
+
evidence.push("Found Kotlin JVM plugin in build.gradle.kts");
|
|
212824
|
+
}
|
|
212825
|
+
if (hasPomKotlinPlugin) {
|
|
212826
|
+
score += 32;
|
|
212827
|
+
evidence.push("Found Kotlin Maven plugin markers in pom.xml");
|
|
212828
|
+
}
|
|
212829
|
+
if (hasKotlinSourceRoot) {
|
|
212830
|
+
score += 18;
|
|
212831
|
+
evidence.push("Found src/main/kotlin source root");
|
|
212832
|
+
}
|
|
212833
|
+
if (hasKtFiles) {
|
|
212834
|
+
score += 16;
|
|
212835
|
+
evidence.push("Found Kotlin source files");
|
|
212836
|
+
}
|
|
212837
|
+
if (hasKotlinPackageShape) {
|
|
212838
|
+
score += 4;
|
|
212839
|
+
evidence.push("Found conventional Kotlin package directory under src/main/kotlin");
|
|
212840
|
+
}
|
|
212841
|
+
const hasSafeKotlinEvidence = hasKtFiles && (hasBuildGradleKts || hasKotlinPluginInGradle || hasPomKotlinPlugin || hasKotlinSourceRoot);
|
|
212842
|
+
if (!hasSafeKotlinEvidence) {
|
|
212843
|
+
return null;
|
|
212844
|
+
}
|
|
212845
|
+
return toResult({
|
|
212846
|
+
adapterId: "kotlin",
|
|
212847
|
+
confidence: (hasKotlinPluginInGradle || hasPomKotlinPlugin) && hasKotlinSourceRoot ? "high" : hasBuildGradleKts || hasKotlinSourceRoot ? "medium" : "low",
|
|
212848
|
+
score,
|
|
212849
|
+
evidence,
|
|
212850
|
+
projectKindHints: ["backend", "library"],
|
|
212851
|
+
apiStyleHint: "unknown"
|
|
212852
|
+
});
|
|
212853
|
+
},
|
|
212854
|
+
resolveProjectKinds: () => ["backend", "library"],
|
|
212174
212855
|
getImportExtractionMode: () => "generic"
|
|
212175
212856
|
}),
|
|
212176
212857
|
kotlin_spring: buildAdapter({
|
|
@@ -212426,7 +213107,7 @@ var stackAdaptersById = {
|
|
|
212426
213107
|
let score = 0;
|
|
212427
213108
|
if (hasVueDependency) {
|
|
212428
213109
|
strongSignals += 1;
|
|
212429
|
-
score +=
|
|
213110
|
+
score += 30;
|
|
212430
213111
|
evidence.push("Found package.json with vue dependency");
|
|
212431
213112
|
}
|
|
212432
213113
|
if (hasAppVue) {
|
|
@@ -212441,12 +213122,12 @@ var stackAdaptersById = {
|
|
|
212441
213122
|
}
|
|
212442
213123
|
if (hasVitePluginInConfig) {
|
|
212443
213124
|
strongSignals += 1;
|
|
212444
|
-
score +=
|
|
213125
|
+
score += 24;
|
|
212445
213126
|
evidence.push("Found Vue plugin usage in vite.config.ts or vite.config.js");
|
|
212446
213127
|
}
|
|
212447
213128
|
if (hasVitePluginDependency) {
|
|
212448
213129
|
strongSignals += 1;
|
|
212449
|
-
score +=
|
|
213130
|
+
score += 22;
|
|
212450
213131
|
evidence.push("Found package.json with @vitejs/plugin-vue dependency");
|
|
212451
213132
|
}
|
|
212452
213133
|
if (hasSrcViews) {
|
|
@@ -212461,12 +213142,12 @@ var stackAdaptersById = {
|
|
|
212461
213142
|
}
|
|
212462
213143
|
if (hasCreateAppReference) {
|
|
212463
213144
|
mediumSignals += 1;
|
|
212464
|
-
score +=
|
|
213145
|
+
score += 12;
|
|
212465
213146
|
evidence.push("Found createApp usage in src/main.ts or src/main.js");
|
|
212466
213147
|
}
|
|
212467
213148
|
if (hasViteConfig && hasVueDependency) {
|
|
212468
213149
|
mediumSignals += 1;
|
|
212469
|
-
score +=
|
|
213150
|
+
score += 8;
|
|
212470
213151
|
evidence.push("Found vite.config.ts or vite.config.js with Vue package evidence");
|
|
212471
213152
|
}
|
|
212472
213153
|
if (hasTsConfigApp) {
|
|
@@ -231311,13 +231992,20 @@ var ignoredDirectoryNames2 = /* @__PURE__ */ new Set([
|
|
|
231311
231992
|
]);
|
|
231312
231993
|
var backendStackIds = /* @__PURE__ */ new Set([
|
|
231313
231994
|
"spring",
|
|
231995
|
+
"express",
|
|
231314
231996
|
"fastapi",
|
|
231997
|
+
"django",
|
|
231998
|
+
"flask",
|
|
231315
231999
|
"dotnet",
|
|
231316
232000
|
"nestjs",
|
|
231317
232001
|
"java",
|
|
231318
232002
|
"python",
|
|
231319
232003
|
"php",
|
|
232004
|
+
"laravel",
|
|
231320
232005
|
"go",
|
|
232006
|
+
"ruby_rails",
|
|
232007
|
+
"kotlin",
|
|
232008
|
+
"kotlin_spring",
|
|
231321
232009
|
"node_typescript",
|
|
231322
232010
|
"node_javascript"
|
|
231323
232011
|
]);
|
|
@@ -231535,14 +232223,21 @@ function buildDetectionContext(workspaceRoot, filePaths, pathsByFileName, extens
|
|
|
231535
232223
|
function toDetectedStack(adapterId) {
|
|
231536
232224
|
switch (adapterId) {
|
|
231537
232225
|
case "node_typescript":
|
|
232226
|
+
case "express":
|
|
231538
232227
|
case "nestjs":
|
|
231539
232228
|
case "java":
|
|
231540
232229
|
case "spring":
|
|
231541
232230
|
case "fastapi":
|
|
232231
|
+
case "django":
|
|
232232
|
+
case "flask":
|
|
231542
232233
|
case "dotnet":
|
|
231543
232234
|
case "python":
|
|
231544
232235
|
case "php":
|
|
232236
|
+
case "laravel":
|
|
231545
232237
|
case "go":
|
|
232238
|
+
case "ruby_rails":
|
|
232239
|
+
case "kotlin":
|
|
232240
|
+
case "kotlin_spring":
|
|
231546
232241
|
case "react":
|
|
231547
232242
|
case "nextjs":
|
|
231548
232243
|
case "angular":
|
|
@@ -231563,6 +232258,9 @@ function resolveLanguages(stacks) {
|
|
|
231563
232258
|
if (stacks.includes("spring")) {
|
|
231564
232259
|
languages.add("java");
|
|
231565
232260
|
}
|
|
232261
|
+
if (stacks.includes("kotlin") || stacks.includes("kotlin_spring")) {
|
|
232262
|
+
languages.add("kotlin");
|
|
232263
|
+
}
|
|
231566
232264
|
if (stacks.includes("dotnet")) {
|
|
231567
232265
|
languages.add("csharp");
|
|
231568
232266
|
}
|
|
@@ -231572,9 +232270,21 @@ function resolveLanguages(stacks) {
|
|
|
231572
232270
|
if (stacks.includes("fastapi")) {
|
|
231573
232271
|
languages.add("python");
|
|
231574
232272
|
}
|
|
232273
|
+
if (stacks.includes("django")) {
|
|
232274
|
+
languages.add("python");
|
|
232275
|
+
}
|
|
232276
|
+
if (stacks.includes("flask")) {
|
|
232277
|
+
languages.add("python");
|
|
232278
|
+
}
|
|
231575
232279
|
if (stacks.includes("php")) {
|
|
231576
232280
|
languages.add("php");
|
|
231577
232281
|
}
|
|
232282
|
+
if (stacks.includes("laravel")) {
|
|
232283
|
+
languages.add("php");
|
|
232284
|
+
}
|
|
232285
|
+
if (stacks.includes("ruby_rails")) {
|
|
232286
|
+
languages.add("ruby");
|
|
232287
|
+
}
|
|
231578
232288
|
if (stacks.includes("go")) {
|
|
231579
232289
|
languages.add("go");
|
|
231580
232290
|
}
|
|
@@ -231588,6 +232298,12 @@ function resolveLanguages(stacks) {
|
|
|
231588
232298
|
languages.add("typescript");
|
|
231589
232299
|
languages.add("javascript");
|
|
231590
232300
|
}
|
|
232301
|
+
if (stacks.includes("express")) {
|
|
232302
|
+
languages.add("javascript");
|
|
232303
|
+
if (stacks.includes("node_typescript")) {
|
|
232304
|
+
languages.add("typescript");
|
|
232305
|
+
}
|
|
232306
|
+
}
|
|
231591
232307
|
if (stacks.includes("react") || stacks.includes("nextjs") || stacks.includes("angular") || stacks.includes("vue")) {
|
|
231592
232308
|
languages.add(stacks.includes("node_typescript") ? "typescript" : "javascript");
|
|
231593
232309
|
}
|
|
@@ -232065,6 +232781,7 @@ var sourceFileExtensions = /* @__PURE__ */ new Set([
|
|
|
232065
232781
|
".tsx",
|
|
232066
232782
|
".js",
|
|
232067
232783
|
".jsx",
|
|
232784
|
+
".vue",
|
|
232068
232785
|
".java",
|
|
232069
232786
|
".py",
|
|
232070
232787
|
".php",
|
|
@@ -232099,7 +232816,9 @@ var roleFileHints = [
|
|
|
232099
232816
|
"layout.tsx",
|
|
232100
232817
|
"layout.jsx",
|
|
232101
232818
|
"route.ts",
|
|
232102
|
-
"route.js"
|
|
232819
|
+
"route.js",
|
|
232820
|
+
"view.vue",
|
|
232821
|
+
"page.vue"
|
|
232103
232822
|
];
|
|
232104
232823
|
function normalizePath13(value) {
|
|
232105
232824
|
return value.replaceAll("\\", "/");
|
|
@@ -232329,6 +233048,12 @@ function collectExplicitRoots(workspaceRoot) {
|
|
|
232329
233048
|
"backend/src/features",
|
|
232330
233049
|
"frontend/src/modules",
|
|
232331
233050
|
"frontend/src/features",
|
|
233051
|
+
"frontend/src/views",
|
|
233052
|
+
"src/views",
|
|
233053
|
+
"routes",
|
|
233054
|
+
"src/routes",
|
|
233055
|
+
"app/Modules",
|
|
233056
|
+
"app/services",
|
|
232332
233057
|
"services",
|
|
232333
233058
|
"packages",
|
|
232334
233059
|
"libs"
|
|
@@ -232355,6 +233080,47 @@ function collectExplicitRoots(workspaceRoot) {
|
|
|
232355
233080
|
}
|
|
232356
233081
|
return uniqueSorted(roots);
|
|
232357
233082
|
}
|
|
233083
|
+
function collectJavaPackageRoots(workspaceRoot) {
|
|
233084
|
+
const roots = [];
|
|
233085
|
+
for (const sourceRoot of ["src/main/java", "src/main/kotlin", "src"]) {
|
|
233086
|
+
const absoluteSourceRoot = path53.join(workspaceRoot, ...sourceRoot.split("/"));
|
|
233087
|
+
if (!pathExists15(absoluteSourceRoot)) {
|
|
233088
|
+
continue;
|
|
233089
|
+
}
|
|
233090
|
+
const queue = [
|
|
233091
|
+
{ absolutePath: absoluteSourceRoot, relativePath: sourceRoot, depth: 0 }
|
|
233092
|
+
];
|
|
233093
|
+
while (queue.length > 0) {
|
|
233094
|
+
const current = queue.shift();
|
|
233095
|
+
if (!current) {
|
|
233096
|
+
continue;
|
|
233097
|
+
}
|
|
233098
|
+
if (current.depth > 6) {
|
|
233099
|
+
continue;
|
|
233100
|
+
}
|
|
233101
|
+
for (const entry of safeReadDirEntries(current.absolutePath)) {
|
|
233102
|
+
if (!entry.isDirectory() || ignoredDirectoryNames4.has(entry.name)) {
|
|
233103
|
+
continue;
|
|
233104
|
+
}
|
|
233105
|
+
const childRelativePath = normalizePath13(`${current.relativePath}/${entry.name}`);
|
|
233106
|
+
const lowerName = entry.name.toLowerCase();
|
|
233107
|
+
if (lowerName === "modules" || lowerName === "features") {
|
|
233108
|
+
const childCount = safeReadDirEntries(path53.join(current.absolutePath, entry.name)).filter((child) => child.isDirectory() && !ignoredDirectoryNames4.has(child.name)).length;
|
|
233109
|
+
if (childCount >= 2) {
|
|
233110
|
+
roots.push(childRelativePath);
|
|
233111
|
+
}
|
|
233112
|
+
continue;
|
|
233113
|
+
}
|
|
233114
|
+
queue.push({
|
|
233115
|
+
absolutePath: path53.join(current.absolutePath, entry.name),
|
|
233116
|
+
relativePath: childRelativePath,
|
|
233117
|
+
depth: current.depth + 1
|
|
233118
|
+
});
|
|
233119
|
+
}
|
|
233120
|
+
}
|
|
233121
|
+
}
|
|
233122
|
+
return roots;
|
|
233123
|
+
}
|
|
232358
233124
|
function collectFallbackSrcModules(workspaceRoot, context) {
|
|
232359
233125
|
const srcRoot = path53.join(workspaceRoot, "src");
|
|
232360
233126
|
const srcEntries = safeReadDirEntries(srcRoot).filter((entry) => entry.isDirectory() && !ignoredDirectoryNames4.has(entry.name)).sort((left, right) => left.name.localeCompare(right.name));
|
|
@@ -232392,6 +233158,14 @@ function detectModules(workspaceRoot, options) {
|
|
|
232392
233158
|
projectKinds: options?.projectKinds,
|
|
232393
233159
|
stacks: options?.stacks
|
|
232394
233160
|
};
|
|
233161
|
+
if (options?.stacks?.some((stack) => stack === "java" || stack === "spring" || stack === "kotlin" || stack === "kotlin_spring")) {
|
|
233162
|
+
for (const root of collectJavaPackageRoots(workspaceRoot)) {
|
|
233163
|
+
if (!explicitRoots.includes(root)) {
|
|
233164
|
+
explicitRoots.push(root);
|
|
233165
|
+
}
|
|
233166
|
+
}
|
|
233167
|
+
explicitRoots.sort((left, right) => left.localeCompare(right));
|
|
233168
|
+
}
|
|
232395
233169
|
for (const root of explicitRoots) {
|
|
232396
233170
|
if (root.endsWith("/src/modules") || root === "src/modules" || root === "backend/src/modules") {
|
|
232397
233171
|
evidence.push(`Found ${root} directory`);
|
|
@@ -233398,10 +234172,16 @@ function resolveImplementationProfile(input2) {
|
|
|
233398
234172
|
return "frontend-vue";
|
|
233399
234173
|
case "nestjs":
|
|
233400
234174
|
return input2.apiStyleHint === "rest" ? "backend-nestjs-rest" : "backend-nestjs";
|
|
234175
|
+
case "express":
|
|
234176
|
+
return input2.apiStyleHint === "rest" ? "backend-express-rest" : "backend-express";
|
|
233401
234177
|
case "spring":
|
|
233402
234178
|
return input2.apiStyleHint === "rest" ? "backend-spring-rest" : "backend-spring";
|
|
233403
234179
|
case "fastapi":
|
|
233404
234180
|
return input2.apiStyleHint === "rest" ? "backend-fastapi-rest" : "backend-fastapi";
|
|
234181
|
+
case "django":
|
|
234182
|
+
return input2.apiStyleHint === "rest" ? "backend-django-rest" : "backend-django";
|
|
234183
|
+
case "flask":
|
|
234184
|
+
return input2.apiStyleHint === "rest" ? "backend-flask-rest" : "backend-flask";
|
|
233405
234185
|
case "dotnet":
|
|
233406
234186
|
return input2.apiStyleHint === "rest" ? "backend-dotnet-webapi" : "backend-dotnet";
|
|
233407
234187
|
case "java":
|
|
@@ -233410,6 +234190,14 @@ function resolveImplementationProfile(input2) {
|
|
|
233410
234190
|
return "backend-python";
|
|
233411
234191
|
case "php":
|
|
233412
234192
|
return "backend-php";
|
|
234193
|
+
case "laravel":
|
|
234194
|
+
return input2.apiStyleHint === "rest" ? "backend-laravel-rest" : "backend-laravel";
|
|
234195
|
+
case "ruby_rails":
|
|
234196
|
+
return input2.apiStyleHint === "rest" ? "backend-rails-rest" : "backend-rails";
|
|
234197
|
+
case "kotlin":
|
|
234198
|
+
return "backend-kotlin";
|
|
234199
|
+
case "kotlin_spring":
|
|
234200
|
+
return input2.apiStyleHint === "rest" ? "backend-kotlin-spring-rest" : "backend-kotlin-spring";
|
|
233413
234201
|
case "go":
|
|
233414
234202
|
return "backend-go";
|
|
233415
234203
|
case "node_typescript":
|
|
@@ -233457,6 +234245,9 @@ function resolveNormalizedProjectKinds(detection, evidence) {
|
|
|
233457
234245
|
addEvidence6(evidence, `Normalized project kinds from selected adapter '${selectedAdapter.id}' hints`);
|
|
233458
234246
|
} else if (detection.topology.topology === "monorepo" && selectedHints.length > 0) {
|
|
233459
234247
|
normalizedKinds = uniqueSortedKinds([...heuristicKinds, ...selectedHints]);
|
|
234248
|
+
if (normalizedKinds.includes("library") && !selectedHints.includes("library") && (detection.architectureStyleSignals?.sharedPackageCount ?? 0) === 0) {
|
|
234249
|
+
normalizedKinds = normalizedKinds.filter((kind) => kind !== "library");
|
|
234250
|
+
}
|
|
233460
234251
|
addEvidence6(evidence, "Normalized monorepo project kinds from adapter hints plus heuristic evidence");
|
|
233461
234252
|
} else if (heuristicKinds.length > 0) {
|
|
233462
234253
|
normalizedKinds = uniqueSortedKinds(heuristicKinds);
|
|
@@ -233569,7 +234360,7 @@ function resolveStackSelections(detection, projectKinds) {
|
|
|
233569
234360
|
}
|
|
233570
234361
|
if (projectKinds.includes("library")) {
|
|
233571
234362
|
const selectedLibrary = detection.stacks.selectedAdapterId;
|
|
233572
|
-
if (selectedLibrary === "terraform" || selectedLibrary === "ansible" || selectedLibrary === "node_typescript" || selectedLibrary === "python" || selectedLibrary === "go") {
|
|
234363
|
+
if (selectedLibrary === "terraform" || selectedLibrary === "ansible" || selectedLibrary === "node_typescript" || selectedLibrary === "python" || selectedLibrary === "go" || selectedLibrary === "kotlin") {
|
|
233573
234364
|
selections.library = selectedLibrary;
|
|
233574
234365
|
}
|
|
233575
234366
|
}
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@archpilotlabs/archpilot",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Executable architecture governance CLI",
|
|
5
|
-
"homepage": "https://archpilot.org",
|
|
6
|
-
"bugs": {
|
|
7
|
-
"url": "https://archpilot.org/contact"
|
|
8
|
-
},
|
|
9
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
10
|
-
"bin": {
|
|
11
|
-
"archpilot": "./dist/archpilot-cli.js"
|
|
12
|
-
},
|
|
13
|
-
"main": "./dist/archpilot-cli.js",
|
|
14
|
-
"files": [
|
|
15
|
-
"dist"
|
|
16
|
-
],
|
|
17
|
-
"keywords": [
|
|
18
|
-
"architecture",
|
|
19
|
-
"architecture-validation",
|
|
20
|
-
"governance",
|
|
21
|
-
"cli",
|
|
22
|
-
"dependency-validation",
|
|
23
|
-
"adr",
|
|
24
|
-
"ci",
|
|
25
|
-
"developer-tools"
|
|
26
|
-
],
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "npm run compile",
|
|
29
|
-
"compile": "npm run check-types && npm run lint && node esbuild.js",
|
|
30
|
-
"watch": "node esbuild.js --watch",
|
|
31
|
-
"check-types": "tsc --noEmit -p tsconfig.json",
|
|
32
|
-
"lint": "eslint src"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@archpilotlabs/archpilot",
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"description": "Executable architecture governance CLI",
|
|
5
|
+
"homepage": "https://archpilot.org",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://archpilot.org/contact"
|
|
8
|
+
},
|
|
9
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
10
|
+
"bin": {
|
|
11
|
+
"archpilot": "./dist/archpilot-cli.js"
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/archpilot-cli.js",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"architecture",
|
|
19
|
+
"architecture-validation",
|
|
20
|
+
"governance",
|
|
21
|
+
"cli",
|
|
22
|
+
"dependency-validation",
|
|
23
|
+
"adr",
|
|
24
|
+
"ci",
|
|
25
|
+
"developer-tools"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "npm run compile",
|
|
29
|
+
"compile": "npm run check-types && npm run lint && node esbuild.js",
|
|
30
|
+
"watch": "node esbuild.js --watch",
|
|
31
|
+
"check-types": "tsc --noEmit -p tsconfig.json",
|
|
32
|
+
"lint": "eslint src"
|
|
33
|
+
}
|
|
34
|
+
}
|