forgehive 1.0.1 → 1.0.3

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.
Files changed (2) hide show
  1. package/dist/cli.js +1055 -49
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3149,61 +3149,243 @@ import { createInterface as createInterface2 } from "node:readline";
3149
3149
  import fs from "node:fs";
3150
3150
  import path from "node:path";
3151
3151
  var TIER1 = [
3152
+ // JavaScript / Node
3152
3153
  "package.json",
3154
+ // Python
3153
3155
  "pyproject.toml",
3156
+ "requirements.txt",
3157
+ "Pipfile",
3158
+ "setup.py",
3159
+ "setup.cfg",
3160
+ // Rust
3154
3161
  "Cargo.toml",
3162
+ // Go
3155
3163
  "go.mod",
3164
+ // Java / Kotlin
3156
3165
  "pom.xml",
3166
+ "build.gradle",
3167
+ "build.gradle.kts",
3168
+ "settings.gradle",
3169
+ "settings.gradle.kts",
3170
+ // Ruby
3157
3171
  "Gemfile",
3158
- "composer.json"
3172
+ // PHP
3173
+ "composer.json",
3174
+ // .NET
3175
+ "global.json",
3176
+ "Directory.Build.props",
3177
+ // Swift / Apple
3178
+ "Package.swift",
3179
+ "Podfile",
3180
+ "Cartfile",
3181
+ // Dart / Flutter
3182
+ "pubspec.yaml",
3183
+ // Elixir
3184
+ "mix.exs",
3185
+ // Scala
3186
+ "build.sbt",
3187
+ // Clojure
3188
+ "deps.edn",
3189
+ "project.clj",
3190
+ // C / C++
3191
+ "CMakeLists.txt",
3192
+ "conanfile.txt",
3193
+ "conanfile.py",
3194
+ "vcpkg.json",
3195
+ // Crystal
3196
+ "shard.yml",
3197
+ // Lua
3198
+ "rockspec",
3199
+ // Zig
3200
+ "build.zig",
3201
+ // Perl
3202
+ "cpanfile",
3203
+ "Makefile.PL",
3204
+ // Terraform (root-level)
3205
+ "terraform.tfvars",
3206
+ "main.tf"
3159
3207
  ];
3160
3208
  var TIER2_FILES = [
3209
+ // Containers
3161
3210
  "Dockerfile",
3162
3211
  "docker-compose.yml",
3163
- ".gitlab-ci.yml"
3212
+ "docker-compose.yaml",
3213
+ // CI/CD
3214
+ ".gitlab-ci.yml",
3215
+ ".travis.yml",
3216
+ "Jenkinsfile",
3217
+ "circle.yml",
3218
+ ".circleci/config.yml",
3219
+ "azure-pipelines.yml",
3220
+ "bitbucket-pipelines.yml",
3221
+ // Hosting / Deploy
3222
+ "netlify.toml",
3223
+ "vercel.json",
3224
+ "fly.toml",
3225
+ "render.yaml",
3226
+ "heroku.yml",
3227
+ "app.yaml",
3228
+ "appspec.yml",
3229
+ // Config / Ops
3230
+ "Vagrantfile",
3231
+ "ansible.cfg",
3232
+ ".envrc"
3164
3233
  ];
3165
3234
  var TIER2_DIRS = [
3166
3235
  ".github/workflows",
3167
3236
  "terraform",
3168
- "k8s"
3237
+ "k8s",
3238
+ ".circleci",
3239
+ "ansible",
3240
+ "charts",
3241
+ "helm",
3242
+ "pulumi",
3243
+ "cdk"
3169
3244
  ];
3170
3245
  var TIER3_PATTERNS = [
3246
+ // JavaScript tooling
3171
3247
  /^\.eslintrc(\.(json|js|yml|yaml|cjs))?$/,
3248
+ /^eslint\.config\.(js|mjs|cjs|ts)$/,
3172
3249
  /^jest\.config\.(js|ts|mjs|cjs|json)$/,
3173
3250
  /^vitest\.config\.(js|ts|mjs)$/,
3251
+ /^vite\.config\.(js|ts|mjs|cjs)$/,
3252
+ /^webpack\.config\.(js|ts|mjs|cjs)$/,
3253
+ /^next\.config\.(js|ts|mjs|cjs)$/,
3254
+ /^nuxt\.config\.(js|ts|mjs)$/,
3255
+ /^astro\.config\.(js|ts|mjs)$/,
3256
+ /^svelte\.config\.(js|ts|mjs)$/,
3257
+ /^remix\.config\.(js|ts|mjs)$/,
3258
+ /^tailwind\.config\.(js|ts|mjs|cjs)$/,
3259
+ /^postcss\.config\.(js|ts|mjs|cjs)$/,
3260
+ /^\.babelrc(\.(json|js|ts))?$/,
3261
+ /^babel\.config\.(js|json|ts|mjs)$/,
3262
+ /^drizzle\.config\.(js|ts|mjs)$/,
3263
+ /^tsconfig.*\.json$/,
3264
+ /^\.prettierrc(\.(json|js|yml|yaml|ts))?$/,
3265
+ /^prettier\.config\.(js|mjs|cjs|ts)$/,
3266
+ /^playwright\.config\.(js|ts|mjs)$/,
3267
+ /^cypress\.config\.(js|ts|mjs|cjs)$/,
3268
+ // Python tooling
3174
3269
  /^pytest\.ini$/,
3270
+ /^tox\.ini$/,
3271
+ /^mypy\.ini$/,
3272
+ /^\.mypy\.ini$/,
3273
+ /^\.flake8$/,
3274
+ /^\.pylintrc$/,
3275
+ /^ruff\.toml$/,
3276
+ // Ruby tooling
3277
+ /^\.rubocop\.yml$/,
3278
+ /^Rakefile$/,
3279
+ /^Guardfile$/,
3280
+ // Go tooling
3281
+ /^\.golangci\.yml$/,
3282
+ /^\.golangci\.yaml$/,
3283
+ // Java tooling
3284
+ /^gradlew$/,
3285
+ /^mvnw$/,
3286
+ /^\.java-version$/,
3287
+ /^checkstyle\.xml$/,
3288
+ /^spotbugs-filter\.xml$/,
3289
+ // Version managers
3290
+ /^\.ruby-version$/,
3291
+ /^\.python-version$/,
3292
+ /^\.node-version$/,
3293
+ /^\.nvmrc$/,
3294
+ /^\.tool-versions$/,
3295
+ // API / Spec
3175
3296
  /^openapi\.(yaml|yml|json)$/,
3176
- /^\.pre-commit-config\.yaml$/
3297
+ /^swagger\.(yaml|yml|json)$/,
3298
+ /^graphql\.config\.(js|ts|yml|yaml|json)$/,
3299
+ /^schema\.graphql$/,
3300
+ /^\.graphqlrc(\.(json|js|yml|yaml))?$/,
3301
+ // Infra
3302
+ /^\.pre-commit-config\.yaml$/,
3303
+ /^\.editorconfig$/,
3304
+ /^sonar-project\.properties$/,
3305
+ /^\.hadolint\.yaml$/,
3306
+ // Prisma
3307
+ /^schema\.prisma$/
3177
3308
  ];
3309
+ var DOTNET_EXTENSIONS = [".sln", ".csproj", ".fsproj", ".vbproj"];
3310
+ var SWIFT_EXTENSIONS = [".xcodeproj", ".xcworkspace"];
3178
3311
  function scan(projectRoot2) {
3179
3312
  const signals = [];
3313
+ const seenPaths = /* @__PURE__ */ new Set();
3314
+ const addSignal = (tier, filePath, filename) => {
3315
+ if (seenPaths.has(filePath)) return;
3316
+ seenPaths.add(filePath);
3317
+ signals.push(signal(tier, filePath, filename));
3318
+ };
3180
3319
  for (const filename of TIER1) {
3181
3320
  if (fs.existsSync(path.join(projectRoot2, filename))) {
3182
- signals.push(signal(1, filename, filename));
3321
+ addSignal(1, filename, filename);
3183
3322
  }
3184
3323
  }
3185
3324
  for (const filename of TIER2_FILES) {
3186
3325
  if (fs.existsSync(path.join(projectRoot2, filename))) {
3187
- signals.push(signal(2, filename, path.basename(filename)));
3326
+ addSignal(2, filename, path.basename(filename));
3188
3327
  }
3189
3328
  }
3190
3329
  for (const dir of TIER2_DIRS) {
3191
3330
  const abs = path.join(projectRoot2, dir);
3192
3331
  if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) continue;
3193
- for (const child of fs.readdirSync(abs)) {
3194
- const rel = path.join(dir, child);
3195
- signals.push(signal(2, rel, child));
3332
+ try {
3333
+ for (const child of fs.readdirSync(abs)) {
3334
+ const rel = path.join(dir, child);
3335
+ addSignal(2, rel, child);
3336
+ }
3337
+ } catch {
3196
3338
  }
3197
3339
  }
3198
- for (const entry of fs.readdirSync(projectRoot2)) {
3199
- const abs = path.join(projectRoot2, entry);
3200
- if (!fs.statSync(abs).isFile()) continue;
3201
- for (const pattern of TIER3_PATTERNS) {
3202
- if (pattern.test(entry)) {
3203
- signals.push(signal(3, entry, entry));
3204
- break;
3340
+ try {
3341
+ for (const entry of fs.readdirSync(projectRoot2)) {
3342
+ const abs = path.join(projectRoot2, entry);
3343
+ if (!fs.statSync(abs).isFile()) continue;
3344
+ for (const pattern of TIER3_PATTERNS) {
3345
+ if (pattern.test(entry)) {
3346
+ addSignal(3, entry, entry);
3347
+ break;
3348
+ }
3205
3349
  }
3350
+ const ext = path.extname(entry).toLowerCase();
3351
+ if (DOTNET_EXTENSIONS.includes(ext)) addSignal(1, entry, entry);
3352
+ if (SWIFT_EXTENSIONS.includes(ext)) addSignal(1, entry, entry);
3353
+ if (entry.endsWith(".nimble")) addSignal(1, entry, entry);
3206
3354
  }
3355
+ } catch {
3356
+ }
3357
+ try {
3358
+ for (const entry of fs.readdirSync(projectRoot2)) {
3359
+ const abs = path.join(projectRoot2, entry);
3360
+ if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) continue;
3361
+ try {
3362
+ for (const child of fs.readdirSync(abs)) {
3363
+ const childAbs = path.join(abs, child);
3364
+ const ext = path.extname(child).toLowerCase();
3365
+ const rel = path.join(entry, child);
3366
+ if ([".csproj", ".fsproj", ".vbproj"].includes(ext)) {
3367
+ addSignal(1, rel, child);
3368
+ }
3369
+ if (SWIFT_EXTENSIONS.includes(ext)) {
3370
+ addSignal(1, rel, child);
3371
+ }
3372
+ if (child === "schema.prisma") {
3373
+ addSignal(3, rel, child);
3374
+ }
3375
+ for (const pattern of TIER3_PATTERNS) {
3376
+ if (pattern.test(child) && !seenPaths.has(rel)) {
3377
+ try {
3378
+ if (fs.statSync(childAbs).isFile()) addSignal(3, rel, child);
3379
+ } catch {
3380
+ }
3381
+ break;
3382
+ }
3383
+ }
3384
+ }
3385
+ } catch {
3386
+ }
3387
+ }
3388
+ } catch {
3207
3389
  }
3208
3390
  return {
3209
3391
  scanned_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3213,113 +3395,937 @@ function scan(projectRoot2) {
3213
3395
  };
3214
3396
  }
3215
3397
  function extractPackages(projectRoot2) {
3398
+ const packages = /* @__PURE__ */ new Set();
3399
+ addAll(packages, extractNodePackages(projectRoot2));
3400
+ addAll(packages, extractPythonPackages(projectRoot2));
3401
+ addAll(packages, extractDotnetPackages(projectRoot2));
3402
+ addAll(packages, extractRubyPackages(projectRoot2));
3403
+ addAll(packages, extractGradlePackages(projectRoot2));
3404
+ addAll(packages, extractDartPackages(projectRoot2));
3405
+ addAll(packages, extractCargoPackages(projectRoot2));
3406
+ addAll(packages, extractGoPackages(projectRoot2));
3407
+ addAll(packages, extractElixirPackages(projectRoot2));
3408
+ return [...packages];
3409
+ }
3410
+ function addAll(set2, items) {
3411
+ for (const item of items) set2.add(item);
3412
+ }
3413
+ function extractNodePackages(projectRoot2) {
3216
3414
  const pkgPath = path.join(projectRoot2, "package.json");
3217
3415
  if (!fs.existsSync(pkgPath)) return [];
3218
3416
  try {
3219
3417
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
3220
- const all = /* @__PURE__ */ new Set([
3418
+ return [
3221
3419
  ...Object.keys(pkg.dependencies ?? {}),
3222
- ...Object.keys(pkg.devDependencies ?? {})
3223
- ]);
3224
- return [...all];
3420
+ ...Object.keys(pkg.devDependencies ?? {}),
3421
+ ...Object.keys(pkg.peerDependencies ?? {})
3422
+ ];
3225
3423
  } catch {
3226
3424
  return [];
3227
3425
  }
3228
3426
  }
3427
+ function extractPythonPackages(projectRoot2) {
3428
+ const packages = [];
3429
+ const reqPath = path.join(projectRoot2, "requirements.txt");
3430
+ if (fs.existsSync(reqPath)) {
3431
+ try {
3432
+ for (const line of fs.readFileSync(reqPath, "utf8").split("\n")) {
3433
+ const clean = line.trim().split(/[>=<!;\[#]/)[0].trim();
3434
+ if (clean && !clean.startsWith("-")) packages.push(clean);
3435
+ }
3436
+ } catch {
3437
+ }
3438
+ }
3439
+ const pyprojectPath = path.join(projectRoot2, "pyproject.toml");
3440
+ if (fs.existsSync(pyprojectPath)) {
3441
+ try {
3442
+ const content = fs.readFileSync(pyprojectPath, "utf8");
3443
+ for (const match of content.matchAll(/^\s*"?([a-zA-Z0-9_\-]+)[>=<!\s"]/gm)) {
3444
+ const name = match[1].trim();
3445
+ if (name && name !== "python") packages.push(name);
3446
+ }
3447
+ } catch {
3448
+ }
3449
+ }
3450
+ const pipfilePath = path.join(projectRoot2, "Pipfile");
3451
+ if (fs.existsSync(pipfilePath)) {
3452
+ try {
3453
+ const content = fs.readFileSync(pipfilePath, "utf8");
3454
+ for (const match of content.matchAll(/^([a-zA-Z0-9_\-]+)\s*=/gm)) {
3455
+ const name = match[1].trim();
3456
+ if (name && !["source", "requires"].includes(name)) packages.push(name);
3457
+ }
3458
+ } catch {
3459
+ }
3460
+ }
3461
+ return packages;
3462
+ }
3463
+ function extractRubyPackages(projectRoot2) {
3464
+ const gemfilePath = path.join(projectRoot2, "Gemfile");
3465
+ if (!fs.existsSync(gemfilePath)) return [];
3466
+ const packages = [];
3467
+ try {
3468
+ const content = fs.readFileSync(gemfilePath, "utf8");
3469
+ for (const match of content.matchAll(/^\s*gem\s+['"]([^'"]+)['"]/gm)) {
3470
+ packages.push(match[1]);
3471
+ }
3472
+ } catch {
3473
+ }
3474
+ return packages;
3475
+ }
3476
+ function extractGradlePackages(projectRoot2) {
3477
+ const packages = [];
3478
+ const gradleFiles = ["build.gradle", "build.gradle.kts"];
3479
+ for (const file of gradleFiles) {
3480
+ const p = path.join(projectRoot2, file);
3481
+ if (!fs.existsSync(p)) continue;
3482
+ try {
3483
+ const content = fs.readFileSync(p, "utf8");
3484
+ for (const match of content.matchAll(/['"]([a-zA-Z0-9._\-]+):([a-zA-Z0-9._\-]+):[^'"]+['"]/g)) {
3485
+ packages.push(`${match[1]}:${match[2]}`);
3486
+ }
3487
+ } catch {
3488
+ }
3489
+ }
3490
+ return packages;
3491
+ }
3492
+ function extractDartPackages(projectRoot2) {
3493
+ const pubspecPath = path.join(projectRoot2, "pubspec.yaml");
3494
+ if (!fs.existsSync(pubspecPath)) return [];
3495
+ const packages = [];
3496
+ try {
3497
+ const content = fs.readFileSync(pubspecPath, "utf8");
3498
+ let inDeps = false;
3499
+ for (const line of content.split("\n")) {
3500
+ if (/^(dependencies|dev_dependencies|dependency_overrides)\s*:/.test(line)) {
3501
+ inDeps = true;
3502
+ continue;
3503
+ }
3504
+ if (inDeps && /^\S/.test(line) && !line.startsWith(" ")) {
3505
+ inDeps = false;
3506
+ }
3507
+ if (inDeps) {
3508
+ const match = line.match(/^\s{2}([a-zA-Z0-9_]+)\s*:/);
3509
+ if (match && match[1] !== "sdk") packages.push(match[1]);
3510
+ }
3511
+ }
3512
+ } catch {
3513
+ }
3514
+ return packages;
3515
+ }
3516
+ function extractDotnetPackages(projectRoot2) {
3517
+ const packages = /* @__PURE__ */ new Set();
3518
+ const pattern = /PackageReference\s+Include="([^"]+)"/gi;
3519
+ const scanDir = (dir, depth = 0) => {
3520
+ if (depth > 3) return;
3521
+ try {
3522
+ for (const entry of fs.readdirSync(dir)) {
3523
+ if (entry.startsWith(".") || entry === "node_modules") continue;
3524
+ const abs = path.join(dir, entry);
3525
+ const ext = path.extname(entry).toLowerCase();
3526
+ if ([".csproj", ".fsproj", ".vbproj"].includes(ext)) {
3527
+ try {
3528
+ const content = fs.readFileSync(abs, "utf8");
3529
+ for (const match of content.matchAll(pattern)) packages.add(match[1]);
3530
+ } catch {
3531
+ }
3532
+ } else {
3533
+ try {
3534
+ if (fs.statSync(abs).isDirectory()) scanDir(abs, depth + 1);
3535
+ } catch {
3536
+ }
3537
+ }
3538
+ }
3539
+ } catch {
3540
+ }
3541
+ };
3542
+ scanDir(projectRoot2);
3543
+ return [...packages];
3544
+ }
3545
+ function extractCargoPackages(projectRoot2) {
3546
+ const cargoPath = path.join(projectRoot2, "Cargo.toml");
3547
+ if (!fs.existsSync(cargoPath)) return [];
3548
+ const packages = [];
3549
+ try {
3550
+ const content = fs.readFileSync(cargoPath, "utf8");
3551
+ let inDeps = false;
3552
+ for (const line of content.split("\n")) {
3553
+ if (/^\[(dependencies|dev-dependencies|build-dependencies)\]/.test(line)) {
3554
+ inDeps = true;
3555
+ continue;
3556
+ }
3557
+ if (inDeps && line.startsWith("[")) {
3558
+ inDeps = false;
3559
+ }
3560
+ if (inDeps) {
3561
+ const match = line.match(/^([a-zA-Z0-9_\-]+)\s*=/);
3562
+ if (match) packages.push(match[1]);
3563
+ }
3564
+ }
3565
+ } catch {
3566
+ }
3567
+ return packages;
3568
+ }
3569
+ function extractGoPackages(projectRoot2) {
3570
+ const gomodPath = path.join(projectRoot2, "go.mod");
3571
+ if (!fs.existsSync(gomodPath)) return [];
3572
+ const packages = [];
3573
+ try {
3574
+ const content = fs.readFileSync(gomodPath, "utf8");
3575
+ let inRequire = false;
3576
+ for (const line of content.split("\n")) {
3577
+ if (/^require\s+\(/.test(line)) {
3578
+ inRequire = true;
3579
+ continue;
3580
+ }
3581
+ if (inRequire && line.trim() === ")") {
3582
+ inRequire = false;
3583
+ continue;
3584
+ }
3585
+ const singleMatch = line.match(/^require\s+(\S+)/);
3586
+ if (singleMatch) {
3587
+ packages.push(singleMatch[1]);
3588
+ continue;
3589
+ }
3590
+ if (inRequire) {
3591
+ const match = line.trim().match(/^(\S+)/);
3592
+ if (match && !match[1].startsWith("//")) packages.push(match[1]);
3593
+ }
3594
+ }
3595
+ } catch {
3596
+ }
3597
+ return packages;
3598
+ }
3599
+ function extractElixirPackages(projectRoot2) {
3600
+ const mixPath = path.join(projectRoot2, "mix.exs");
3601
+ if (!fs.existsSync(mixPath)) return [];
3602
+ const packages = [];
3603
+ try {
3604
+ const content = fs.readFileSync(mixPath, "utf8");
3605
+ for (const match of content.matchAll(/\{:([a-zA-Z0-9_]+)/g)) {
3606
+ packages.push(match[1]);
3607
+ }
3608
+ } catch {
3609
+ }
3610
+ return packages;
3611
+ }
3229
3612
  function signal(tier, filePath, filename) {
3230
3613
  return { tier, path: filePath, filename, exists: true };
3231
3614
  }
3232
3615
 
3233
3616
  // src/lookup-table.ts
3234
3617
  var FILENAME_TO_IDS = {
3618
+ // JavaScript / Node
3235
3619
  "package.json": ["nodejs", "javascript"],
3620
+ // Python
3236
3621
  "pyproject.toml": ["python"],
3237
- "Cargo.toml": ["rust"],
3622
+ "requirements.txt": ["python", "pip"],
3623
+ "Pipfile": ["python", "pipenv"],
3624
+ "setup.py": ["python", "pip"],
3625
+ "setup.cfg": ["python"],
3626
+ // Rust
3627
+ "Cargo.toml": ["rust", "cargo"],
3628
+ // Go
3238
3629
  "go.mod": ["golang"],
3630
+ // Java / Kotlin / JVM
3239
3631
  "pom.xml": ["java", "maven"],
3240
- "Gemfile": ["ruby"],
3241
- "composer.json": ["php"],
3632
+ "build.gradle": ["java", "gradle"],
3633
+ "build.gradle.kts": ["kotlin", "gradle"],
3634
+ "settings.gradle": ["java", "gradle"],
3635
+ "settings.gradle.kts": ["kotlin", "gradle"],
3636
+ // Ruby
3637
+ "Gemfile": ["ruby", "bundler"],
3638
+ // PHP
3639
+ "composer.json": ["php", "composer"],
3640
+ // .NET
3641
+ "global.json": ["dotnet"],
3642
+ "Directory.Build.props": ["dotnet"],
3643
+ // Swift / Apple
3644
+ "Package.swift": ["swift", "spm"],
3645
+ "Podfile": ["swift", "cocoapods"],
3646
+ "Cartfile": ["swift", "carthage"],
3647
+ // Dart / Flutter
3648
+ "pubspec.yaml": ["dart", "flutter"],
3649
+ // Elixir
3650
+ "mix.exs": ["elixir", "mix"],
3651
+ // Scala
3652
+ "build.sbt": ["scala", "sbt"],
3653
+ // Clojure
3654
+ "deps.edn": ["clojure"],
3655
+ "project.clj": ["clojure", "leiningen"],
3656
+ // C / C++
3657
+ "CMakeLists.txt": ["cmake", "cpp"],
3658
+ "conanfile.txt": ["conan", "cpp"],
3659
+ "conanfile.py": ["conan", "cpp"],
3660
+ "vcpkg.json": ["vcpkg", "cpp"],
3661
+ // Crystal
3662
+ "shard.yml": ["crystal"],
3663
+ // Zig
3664
+ "build.zig": ["zig"],
3665
+ // Perl
3666
+ "cpanfile": ["perl"],
3667
+ "Makefile.PL": ["perl"],
3668
+ // Terraform
3669
+ "main.tf": ["terraform", "infrastructure-as-code"],
3670
+ "terraform.tfvars": ["terraform"],
3671
+ // Containers
3242
3672
  "Dockerfile": ["docker"],
3243
3673
  "docker-compose.yml": ["docker-compose"],
3674
+ "docker-compose.yaml": ["docker-compose"],
3675
+ // CI/CD
3244
3676
  ".gitlab-ci.yml": ["gitlab-ci", "ci-cd"],
3245
- "pytest.ini": ["pytest"],
3677
+ ".travis.yml": ["travis-ci", "ci-cd"],
3678
+ "Jenkinsfile": ["jenkins", "ci-cd"],
3679
+ "azure-pipelines.yml": ["azure-devops", "ci-cd"],
3680
+ "bitbucket-pipelines.yml": ["bitbucket", "ci-cd"],
3681
+ "circle.yml": ["circleci", "ci-cd"],
3682
+ // Hosting / Deploy
3683
+ "netlify.toml": ["netlify"],
3684
+ "vercel.json": ["vercel"],
3685
+ "fly.toml": ["fly-io"],
3686
+ "render.yaml": ["render"],
3687
+ "heroku.yml": ["heroku"],
3688
+ "app.yaml": ["gcp-app-engine"],
3689
+ "appspec.yml": ["aws-codedeploy"],
3690
+ // Ops
3691
+ "Vagrantfile": ["vagrant"],
3692
+ "ansible.cfg": ["ansible"],
3693
+ ".envrc": ["direnv"],
3694
+ // API / Schema
3246
3695
  "openapi.yaml": ["openapi"],
3247
3696
  "openapi.yml": ["openapi"],
3248
3697
  "openapi.json": ["openapi"],
3249
- ".pre-commit-config.yaml": ["pre-commit"]
3698
+ "swagger.yaml": ["openapi", "swagger"],
3699
+ "swagger.yml": ["openapi", "swagger"],
3700
+ "swagger.json": ["openapi", "swagger"],
3701
+ // Quality
3702
+ ".pre-commit-config.yaml": ["pre-commit"],
3703
+ "sonar-project.properties": ["sonarqube"],
3704
+ // Python tooling
3705
+ "pytest.ini": ["pytest"],
3706
+ "tox.ini": ["tox"],
3707
+ "mypy.ini": ["mypy"],
3708
+ ".mypy.ini": ["mypy"],
3709
+ ".flake8": ["flake8"],
3710
+ ".pylintrc": ["pylint"],
3711
+ "ruff.toml": ["ruff"],
3712
+ // Ruby tooling
3713
+ "Rakefile": ["rake"],
3714
+ "Guardfile": ["guard"],
3715
+ // Version managers
3716
+ ".nvmrc": ["nodejs"],
3717
+ ".node-version": ["nodejs"],
3718
+ ".ruby-version": ["ruby"],
3719
+ ".python-version": ["python"],
3720
+ ".tool-versions": ["asdf"],
3721
+ ".java-version": ["java"],
3722
+ // Infra dirs (these are created as file signals from dir scans)
3723
+ "ci.yml": ["github-actions", "ci-cd"],
3724
+ "ci.yaml": ["github-actions", "ci-cd"],
3725
+ "release.yml": ["github-actions", "ci-cd"],
3726
+ "deploy.yml": ["github-actions", "ci-cd"]
3250
3727
  };
3251
3728
  var TIER2_DIR_PREFIX_TO_IDS = {
3252
3729
  ".github/workflows": ["github-actions", "ci-cd"],
3730
+ ".circleci": ["circleci", "ci-cd"],
3253
3731
  "terraform": ["terraform", "infrastructure-as-code"],
3254
- "k8s": ["kubernetes"]
3732
+ "k8s": ["kubernetes"],
3733
+ "ansible": ["ansible"],
3734
+ "charts": ["helm", "kubernetes"],
3735
+ "helm": ["helm", "kubernetes"],
3736
+ "pulumi": ["pulumi", "infrastructure-as-code"],
3737
+ "cdk": ["aws-cdk", "infrastructure-as-code"]
3255
3738
  };
3256
3739
  var FILENAME_PREFIX_TO_IDS = [
3740
+ // JS frameworks / tooling
3257
3741
  [/^jest\.config\./, ["jest", "unit-testing"]],
3258
3742
  [/^vitest\.config\./, ["vitest", "unit-testing"]],
3259
- [/^\.eslintrc/, ["eslint", "linting"]]
3743
+ [/^vite\.config\./, ["vite"]],
3744
+ [/^webpack\.config\./, ["webpack"]],
3745
+ [/^next\.config\./, ["nextjs"]],
3746
+ [/^nuxt\.config\./, ["nuxt"]],
3747
+ [/^astro\.config\./, ["astro"]],
3748
+ [/^svelte\.config\./, ["svelte"]],
3749
+ [/^remix\.config\./, ["remix"]],
3750
+ [/^tailwind\.config\./, ["tailwind"]],
3751
+ [/^postcss\.config\./, ["postcss"]],
3752
+ [/^\.eslintrc/, ["eslint", "linting"]],
3753
+ [/^eslint\.config\./, ["eslint", "linting"]],
3754
+ [/^\.babelrc/, ["babel"]],
3755
+ [/^babel\.config\./, ["babel"]],
3756
+ [/^drizzle\.config\./, ["drizzle", "orm"]],
3757
+ [/^tsconfig.*\.json$/, ["typescript"]],
3758
+ [/^\.prettierrc/, ["prettier"]],
3759
+ [/^prettier\.config\./, ["prettier"]],
3760
+ [/^playwright\.config\./, ["playwright", "e2e-testing"]],
3761
+ [/^cypress\.config\./, ["cypress", "e2e-testing"]],
3762
+ // Python
3763
+ [/^ruff\.toml$/, ["ruff", "linting"]],
3764
+ // Ruby
3765
+ [/^\.rubocop\.yml$/, ["rubocop", "linting"]],
3766
+ // Go
3767
+ [/^\.golangci\.ya?ml$/, ["golangci", "linting"]],
3768
+ // Java
3769
+ [/^gradlew$/, ["gradle"]],
3770
+ [/^mvnw$/, ["maven"]],
3771
+ [/^checkstyle\.xml$/, ["checkstyle", "linting"]],
3772
+ // .NET extensions
3773
+ [/\.sln$/i, ["dotnet", "csharp"]],
3774
+ [/\.csproj$/i, ["dotnet", "csharp", "nuget"]],
3775
+ [/\.fsproj$/i, ["dotnet", "fsharp", "nuget"]],
3776
+ [/\.vbproj$/i, ["dotnet", "vbnet", "nuget"]],
3777
+ // Swift / Apple
3778
+ [/\.xcodeproj$/i, ["swift", "xcode"]],
3779
+ [/\.xcworkspace$/i, ["swift", "xcode"]],
3780
+ // Nim
3781
+ [/\.nimble$/i, ["nim"]],
3782
+ // GraphQL
3783
+ [/^\.graphqlrc/, ["graphql"]],
3784
+ [/^graphql\.config\./, ["graphql"]],
3785
+ [/^schema\.graphql$/, ["graphql"]],
3786
+ [/^schema\.prisma$/, ["prisma", "orm"]],
3787
+ // Misc
3788
+ [/^\.editorconfig$/, ["editorconfig"]],
3789
+ [/^\.hadolint\.ya?ml$/, ["hadolint", "docker"]],
3790
+ [/^sonar-project\./, ["sonarqube"]]
3260
3791
  ];
3261
3792
  var PACKAGE_TO_IDS = {
3262
- // JS Frameworks
3793
+ // ─── JavaScript / TypeScript Frameworks ──────────────────────────────────
3263
3794
  "react": ["react"],
3264
3795
  "react-dom": ["react"],
3265
3796
  "next": ["nextjs"],
3266
3797
  "nuxt": ["nuxt"],
3798
+ "nuxt3": ["nuxt"],
3267
3799
  "vue": ["vue"],
3268
3800
  "@vue/core": ["vue"],
3269
3801
  "svelte": ["svelte"],
3270
3802
  "@sveltejs/kit": ["sveltekit"],
3271
3803
  "remix": ["remix"],
3272
3804
  "@remix-run/react": ["remix"],
3805
+ "@remix-run/node": ["remix"],
3273
3806
  "gatsby": ["gatsby"],
3274
3807
  "astro": ["astro"],
3275
- // Backend JS
3808
+ "qwik": ["qwik"],
3809
+ "@builder.io/qwik": ["qwik"],
3810
+ "solid-js": ["solidjs"],
3811
+ "@angular/core": ["angular"],
3812
+ "@angular/cli": ["angular"],
3813
+ "ember-cli": ["ember"],
3814
+ "ember-source": ["ember"],
3815
+ // Backend JS/TS
3276
3816
  "express": ["express"],
3277
3817
  "fastify": ["fastify"],
3278
3818
  "hono": ["hono"],
3279
3819
  "koa": ["koa"],
3280
- "nestjs": ["nestjs"],
3281
3820
  "@nestjs/core": ["nestjs"],
3821
+ "nestjs": ["nestjs"],
3822
+ "@hapi/hapi": ["hapi"],
3823
+ "restify": ["restify"],
3824
+ "feathers": ["feathers"],
3825
+ "@feathersjs/feathers": ["feathers"],
3826
+ "socket.io": ["socket-io", "websockets"],
3827
+ "ws": ["websockets"],
3282
3828
  // Database / ORM
3283
- "@prisma/client": ["prisma"],
3284
- "prisma": ["prisma"],
3285
- "drizzle-orm": ["drizzle"],
3286
- "typeorm": ["typeorm"],
3287
- "mongoose": ["mongoose"],
3288
- "sequelize": ["sequelize"],
3829
+ "@prisma/client": ["prisma", "orm"],
3830
+ "prisma": ["prisma", "orm"],
3831
+ "drizzle-orm": ["drizzle", "orm"],
3832
+ "typeorm": ["typeorm", "orm"],
3833
+ "mongoose": ["mongoose", "mongodb"],
3834
+ "sequelize": ["sequelize", "orm"],
3835
+ "knex": ["knex", "orm"],
3836
+ "mikro-orm": ["mikro-orm", "orm"],
3837
+ "@mikro-orm/core": ["mikro-orm", "orm"],
3838
+ "pg": ["postgresql"],
3839
+ "postgres": ["postgresql"],
3840
+ "@neondatabase/serverless": ["postgresql", "neon"],
3841
+ "mysql2": ["mysql"],
3842
+ "better-sqlite3": ["sqlite"],
3843
+ "@libsql/client": ["turso", "sqlite"],
3844
+ "ioredis": ["redis"],
3845
+ "redis": ["redis"],
3846
+ "mongodb": ["mongodb"],
3847
+ "@elastic/elasticsearch": ["elasticsearch"],
3289
3848
  // Testing JS
3290
- "vitest": ["vitest"],
3291
- "jest": ["jest"],
3292
- "@playwright/test": ["playwright"],
3293
- "playwright": ["playwright"],
3294
- "cypress": ["cypress"],
3849
+ "vitest": ["vitest", "unit-testing"],
3850
+ "jest": ["jest", "unit-testing"],
3851
+ "@jest/core": ["jest", "unit-testing"],
3852
+ "mocha": ["mocha", "unit-testing"],
3853
+ "chai": ["chai"],
3854
+ "jasmine": ["jasmine"],
3855
+ "@playwright/test": ["playwright", "e2e-testing"],
3856
+ "playwright": ["playwright", "e2e-testing"],
3857
+ "cypress": ["cypress", "e2e-testing"],
3858
+ "puppeteer": ["puppeteer", "e2e-testing"],
3295
3859
  "storybook": ["storybook"],
3296
3860
  "@storybook/react": ["storybook"],
3861
+ "msw": ["msw", "mocking"],
3862
+ "sinon": ["sinon", "mocking"],
3863
+ "@testing-library/react": ["testing-library"],
3864
+ "@testing-library/vue": ["testing-library"],
3297
3865
  // Build / Tooling
3298
3866
  "vite": ["vite"],
3299
3867
  "webpack": ["webpack"],
3300
3868
  "esbuild": ["esbuild"],
3869
+ "rollup": ["rollup"],
3870
+ "parcel": ["parcel"],
3301
3871
  "turbo": ["turborepo"],
3302
3872
  "nx": ["nx"],
3873
+ "lerna": ["lerna"],
3874
+ "@swc/core": ["swc"],
3875
+ "typescript": ["typescript"],
3876
+ "tsx": ["typescript"],
3877
+ "ts-node": ["typescript"],
3303
3878
  // Auth
3304
- "next-auth": ["next-auth"],
3305
- "@auth/core": ["auth-js"],
3306
- "lucia": ["lucia"],
3879
+ "next-auth": ["next-auth", "auth"],
3880
+ "@auth/core": ["auth-js", "auth"],
3881
+ "lucia": ["lucia", "auth"],
3882
+ "passport": ["passport", "auth"],
3883
+ "jsonwebtoken": ["jwt", "auth"],
3884
+ "jose": ["jwt", "auth"],
3885
+ "bcrypt": ["bcrypt", "auth"],
3886
+ "bcryptjs": ["bcrypt", "auth"],
3887
+ "@clerk/nextjs": ["clerk", "auth"],
3888
+ "@clerk/clerk-sdk-node": ["clerk", "auth"],
3889
+ "better-auth": ["auth"],
3307
3890
  // Styling
3308
3891
  "tailwindcss": ["tailwind"],
3309
3892
  "@tailwindcss/vite": ["tailwind"],
3310
3893
  "styled-components": ["styled-components"],
3894
+ "@emotion/react": ["emotion"],
3895
+ "sass": ["sass"],
3896
+ "less": ["less"],
3897
+ "postcss": ["postcss"],
3311
3898
  // State
3312
3899
  "zustand": ["zustand"],
3313
3900
  "jotai": ["jotai"],
3314
3901
  "@reduxjs/toolkit": ["redux"],
3315
3902
  "redux": ["redux"],
3316
- // Python frameworks (from pip, often in pyproject.toml — detected via name in packages)
3903
+ "mobx": ["mobx"],
3904
+ "recoil": ["recoil"],
3905
+ "xstate": ["xstate"],
3906
+ "pinia": ["pinia"],
3907
+ // Validation
3908
+ "zod": ["zod", "validation"],
3909
+ "yup": ["yup", "validation"],
3910
+ "joi": ["joi", "validation"],
3911
+ "valibot": ["valibot", "validation"],
3912
+ // API / Query
3913
+ "@tanstack/react-query": ["react-query"],
3914
+ "react-query": ["react-query"],
3915
+ "@tanstack/query-core": ["react-query"],
3916
+ "@trpc/server": ["trpc"],
3917
+ "@trpc/client": ["trpc"],
3918
+ "graphql": ["graphql"],
3919
+ "apollo-server": ["apollo", "graphql"],
3920
+ "@apollo/server": ["apollo", "graphql"],
3921
+ "@apollo/client": ["apollo", "graphql"],
3922
+ "urql": ["urql", "graphql"],
3923
+ "openapi-fetch": ["openapi"],
3924
+ // AI / LLM
3925
+ "@anthropic-ai/sdk": ["anthropic", "ai"],
3926
+ "openai": ["openai", "ai"],
3927
+ "@langchain/core": ["langchain", "ai"],
3928
+ "langchain": ["langchain", "ai"],
3929
+ "ai": ["vercel-ai", "ai"],
3930
+ "@vercel/ai": ["vercel-ai", "ai"],
3931
+ "@mistralai/mistralai": ["mistral", "ai"],
3932
+ // Infra / Cloud JS
3933
+ "serverless": ["serverless"],
3934
+ "@aws-sdk/client-s3": ["aws-sdk", "aws"],
3935
+ "@aws-sdk/client-dynamodb": ["aws-sdk", "aws", "dynamodb"],
3936
+ "aws-lambda": ["aws-lambda", "aws"],
3937
+ "@google-cloud/storage": ["gcp"],
3938
+ "@azure/storage-blob": ["azure"],
3939
+ // Observability
3940
+ "@opentelemetry/api": ["opentelemetry"],
3941
+ "pino": ["pino", "logging"],
3942
+ "winston": ["winston", "logging"],
3943
+ "dd-trace": ["datadog"],
3944
+ // ─── Python packages ─────────────────────────────────────────────────────
3317
3945
  "fastapi": ["fastapi"],
3318
3946
  "django": ["django"],
3319
3947
  "flask": ["flask"],
3320
- "sqlalchemy": ["sqlalchemy"],
3321
- "pydantic": ["pydantic"],
3322
- "alembic": ["alembic"]
3948
+ "starlette": ["starlette"],
3949
+ "tornado": ["tornado"],
3950
+ "aiohttp": ["aiohttp"],
3951
+ "sanic": ["sanic"],
3952
+ "litestar": ["litestar"],
3953
+ "falcon": ["falcon"],
3954
+ "bottle": ["bottle"],
3955
+ "pyramid": ["pyramid"],
3956
+ // Python ORM / DB
3957
+ "sqlalchemy": ["sqlalchemy", "orm"],
3958
+ "databases": ["databases"],
3959
+ "tortoise-orm": ["tortoise-orm", "orm"],
3960
+ "alembic": ["alembic", "migrations"],
3961
+ "pydantic": ["pydantic", "validation"],
3962
+ "pydantic-settings": ["pydantic"],
3963
+ "pymongo": ["mongodb"],
3964
+ "motor": ["mongodb", "async"],
3965
+ "redis": ["redis"],
3966
+ "aioredis": ["redis", "async"],
3967
+ "psycopg2": ["postgresql"],
3968
+ "psycopg2-binary": ["postgresql"],
3969
+ "asyncpg": ["postgresql", "async"],
3970
+ "aiomysql": ["mysql", "async"],
3971
+ "elasticsearch": ["elasticsearch"],
3972
+ "pymysql": ["mysql"],
3973
+ // Python ML / Data Science / AI
3974
+ "numpy": ["numpy", "data-science"],
3975
+ "pandas": ["pandas", "data-science"],
3976
+ "scipy": ["scipy", "data-science"],
3977
+ "matplotlib": ["matplotlib", "data-science"],
3978
+ "seaborn": ["seaborn", "data-science"],
3979
+ "plotly": ["plotly", "data-science"],
3980
+ "bokeh": ["bokeh"],
3981
+ "altair": ["altair"],
3982
+ "scikit-learn": ["scikit-learn", "ml"],
3983
+ "sklearn": ["scikit-learn", "ml"],
3984
+ "xgboost": ["xgboost", "ml"],
3985
+ "lightgbm": ["lightgbm", "ml"],
3986
+ "catboost": ["catboost", "ml"],
3987
+ "tensorflow": ["tensorflow", "deep-learning"],
3988
+ "tf-keras": ["tensorflow", "deep-learning"],
3989
+ "keras": ["keras", "deep-learning"],
3990
+ "torch": ["pytorch", "deep-learning"],
3991
+ "torchvision": ["pytorch", "deep-learning"],
3992
+ "torchaudio": ["pytorch", "deep-learning"],
3993
+ "jax": ["jax", "deep-learning"],
3994
+ "flax": ["jax", "deep-learning"],
3995
+ "transformers": ["huggingface", "nlp", "deep-learning"],
3996
+ "datasets": ["huggingface", "data-science"],
3997
+ "huggingface-hub": ["huggingface"],
3998
+ "diffusers": ["huggingface", "generative-ai"],
3999
+ "sentence-transformers": ["sentence-transformers", "nlp"],
4000
+ "spacy": ["spacy", "nlp"],
4001
+ "nltk": ["nltk", "nlp"],
4002
+ "gensim": ["gensim", "nlp"],
4003
+ "langchain": ["langchain", "ai"],
4004
+ "langchain-community": ["langchain", "ai"],
4005
+ "langchain-core": ["langchain", "ai"],
4006
+ "langchain-openai": ["langchain", "openai", "ai"],
4007
+ "langchain-anthropic": ["langchain", "anthropic", "ai"],
4008
+ "llama-index": ["llama-index", "ai"],
4009
+ "llama_index": ["llama-index", "ai"],
4010
+ "openai": ["openai", "ai"],
4011
+ "anthropic": ["anthropic", "ai"],
4012
+ "mistralai": ["mistral", "ai"],
4013
+ "google-generativeai": ["gemini", "ai"],
4014
+ "groq": ["groq", "ai"],
4015
+ "together": ["together-ai", "ai"],
4016
+ "chromadb": ["chromadb", "vector-db"],
4017
+ "pinecone-client": ["pinecone", "vector-db"],
4018
+ "weaviate-client": ["weaviate", "vector-db"],
4019
+ "qdrant-client": ["qdrant", "vector-db"],
4020
+ "faiss-cpu": ["faiss", "vector-db"],
4021
+ "pymilvus": ["milvus", "vector-db"],
4022
+ "opencv-python": ["opencv", "computer-vision"],
4023
+ "pillow": ["pillow", "image-processing"],
4024
+ "imageio": ["imageio"],
4025
+ "librosa": ["librosa", "audio"],
4026
+ // Python infra
4027
+ "celery": ["celery", "task-queue"],
4028
+ "dramatiq": ["dramatiq", "task-queue"],
4029
+ "rq": ["rq", "task-queue"],
4030
+ "boto3": ["aws-sdk", "aws"],
4031
+ "botocore": ["aws-sdk", "aws"],
4032
+ "google-cloud-storage": ["gcp"],
4033
+ "azure-storage-blob": ["azure"],
4034
+ "paramiko": ["ssh"],
4035
+ "cryptography": ["cryptography"],
4036
+ "pyjwt": ["jwt", "auth"],
4037
+ "passlib": ["passlib", "auth"],
4038
+ "python-jose": ["jwt", "auth"],
4039
+ "httpx": ["httpx"],
4040
+ "requests": ["requests"],
4041
+ "aiohttp": ["aiohttp"],
4042
+ "uvicorn": ["uvicorn", "asgi"],
4043
+ "gunicorn": ["gunicorn", "wsgi"],
4044
+ "hypercorn": ["hypercorn", "asgi"],
4045
+ "loguru": ["loguru", "logging"],
4046
+ "structlog": ["structlog", "logging"],
4047
+ "opentelemetry-api": ["opentelemetry"],
4048
+ "sentry-sdk": ["sentry"],
4049
+ "pytest": ["pytest", "unit-testing"],
4050
+ "pytest-asyncio": ["pytest", "unit-testing"],
4051
+ "pytest-cov": ["pytest", "coverage"],
4052
+ "mypy": ["mypy"],
4053
+ "ruff": ["ruff"],
4054
+ "black": ["black"],
4055
+ "isort": ["isort"],
4056
+ "click": ["click", "cli"],
4057
+ "typer": ["typer", "cli"],
4058
+ "rich": ["rich"],
4059
+ "pydantic-v1": ["pydantic"],
4060
+ // ─── Ruby gems ───────────────────────────────────────────────────────────
4061
+ "rails": ["rails"],
4062
+ "sinatra": ["sinatra"],
4063
+ "grape": ["grape"],
4064
+ "roda": ["roda"],
4065
+ "hanami": ["hanami"],
4066
+ "rspec-rails": ["rspec", "unit-testing"],
4067
+ "rspec-core": ["rspec", "unit-testing"],
4068
+ "minitest": ["minitest", "unit-testing"],
4069
+ "capybara": ["capybara", "e2e-testing"],
4070
+ "devise": ["devise", "auth"],
4071
+ "doorkeeper": ["doorkeeper", "auth", "oauth"],
4072
+ "sidekiq": ["sidekiq", "task-queue"],
4073
+ "delayed_job": ["delayed-job", "task-queue"],
4074
+ "active_record": ["activerecord", "orm"],
4075
+ "sequel": ["sequel", "orm"],
4076
+ "pg": ["postgresql"],
4077
+ "mysql2": ["mysql"],
4078
+ "redis": ["redis"],
4079
+ "mongoid": ["mongodb"],
4080
+ "factory_bot": ["factory-bot", "testing"],
4081
+ "factory_bot_rails": ["factory-bot", "testing"],
4082
+ "faker": ["faker", "testing"],
4083
+ "pundit": ["pundit", "authorization"],
4084
+ "cancancan": ["cancancan", "authorization"],
4085
+ "kaminari": ["kaminari", "pagination"],
4086
+ "pagy": ["pagy", "pagination"],
4087
+ "puma": ["puma", "web-server"],
4088
+ "unicorn": ["unicorn", "web-server"],
4089
+ "rubocop": ["rubocop", "linting"],
4090
+ "sorbet": ["sorbet", "types"],
4091
+ "dry-rb": ["dry-rb"],
4092
+ "rom-rb": ["rom-rb"],
4093
+ // ─── Java / Kotlin (Gradle group:artifact) ────────────────────────────────
4094
+ "org.springframework.boot:spring-boot-starter": ["spring-boot"],
4095
+ "org.springframework.boot:spring-boot-starter-web": ["spring-boot", "spring-web"],
4096
+ "org.springframework.boot:spring-boot-starter-data-jpa": ["spring-boot", "spring-data", "jpa"],
4097
+ "org.springframework.boot:spring-boot-starter-security": ["spring-boot", "spring-security"],
4098
+ "org.springframework.boot:spring-boot-starter-test": ["spring-boot", "junit"],
4099
+ "org.springframework:spring-core": ["spring"],
4100
+ "org.springframework:spring-web": ["spring-web"],
4101
+ "org.hibernate.orm:hibernate-core": ["hibernate", "orm"],
4102
+ "org.junit.jupiter:junit-jupiter": ["junit", "unit-testing"],
4103
+ "junit:junit": ["junit", "unit-testing"],
4104
+ "org.mockito:mockito-core": ["mockito", "mocking"],
4105
+ "org.assertj:assertj-core": ["assertj"],
4106
+ "com.fasterxml.jackson.core:jackson-databind": ["jackson", "json"],
4107
+ "org.slf4j:slf4j-api": ["slf4j", "logging"],
4108
+ "ch.qos.logback:logback-classic": ["logback", "logging"],
4109
+ "org.apache.logging.log4j:log4j-core": ["log4j", "logging"],
4110
+ "io.micrometer:micrometer-core": ["micrometer", "observability"],
4111
+ "org.flywaydb:flyway-core": ["flyway", "migrations"],
4112
+ "org.liquibase:liquibase-core": ["liquibase", "migrations"],
4113
+ "com.querydsl:querydsl-jpa": ["querydsl"],
4114
+ "org.mapstruct:mapstruct": ["mapstruct"],
4115
+ "io.quarkus:quarkus-core": ["quarkus"],
4116
+ "io.micronaut:micronaut-core": ["micronaut"],
4117
+ "io.ktor:ktor-server-core": ["ktor", "kotlin"],
4118
+ "org.jetbrains.kotlinx:kotlinx-coroutines-core": ["kotlin-coroutines"],
4119
+ "org.jetbrains.kotlinx:kotlinx-serialization-json": ["kotlinx-serialization"],
4120
+ "com.google.dagger:dagger": ["dagger", "di"],
4121
+ "io.insert-koin:koin-core": ["koin", "di"],
4122
+ // ─── Go modules (full module path) ───────────────────────────────────────
4123
+ "github.com/gin-gonic/gin": ["gin"],
4124
+ "github.com/labstack/echo/v4": ["echo"],
4125
+ "github.com/gofiber/fiber/v2": ["fiber"],
4126
+ "github.com/go-chi/chi/v5": ["chi"],
4127
+ "github.com/gorilla/mux": ["gorilla-mux"],
4128
+ "github.com/gin-gonic/gin/v2": ["gin"],
4129
+ "google.golang.org/grpc": ["grpc"],
4130
+ "github.com/grpc-ecosystem/grpc-gateway/v2": ["grpc-gateway", "grpc"],
4131
+ "gorm.io/gorm": ["gorm", "orm"],
4132
+ "github.com/jmoiern/sqlx": ["sqlx"],
4133
+ "github.com/go-sql-driver/mysql": ["mysql"],
4134
+ "github.com/lib/pq": ["postgresql"],
4135
+ "github.com/jackc/pgx/v5": ["postgresql"],
4136
+ "go.mongodb.org/mongo-driver": ["mongodb"],
4137
+ "github.com/go-redis/redis/v8": ["redis"],
4138
+ "github.com/redis/go-redis/v9": ["redis"],
4139
+ "github.com/spf13/cobra": ["cobra", "cli"],
4140
+ "github.com/spf13/viper": ["viper", "config"],
4141
+ "github.com/sirupsen/logrus": ["logrus", "logging"],
4142
+ "go.uber.org/zap": ["zap", "logging"],
4143
+ "github.com/rs/zerolog": ["zerolog", "logging"],
4144
+ "golang.org/x/oauth2": ["oauth2", "auth"],
4145
+ "github.com/golang-jwt/jwt/v5": ["jwt", "auth"],
4146
+ "github.com/stretchr/testify": ["testify", "unit-testing"],
4147
+ "github.com/onsi/ginkgo/v2": ["ginkgo", "bdd-testing"],
4148
+ "github.com/onsi/gomega": ["gomega"],
4149
+ "github.com/go-playground/validator/v10": ["validator", "validation"],
4150
+ "github.com/uber/fx": ["uber-fx", "di"],
4151
+ "go.uber.org/dig": ["dig", "di"],
4152
+ "github.com/nats-io/nats.go": ["nats", "messaging"],
4153
+ "github.com/segmentio/kafka-go": ["kafka", "messaging"],
4154
+ "go.opentelemetry.io/otel": ["opentelemetry"],
4155
+ "github.com/prometheus/client_golang": ["prometheus"],
4156
+ "cloud.google.com/go": ["gcp"],
4157
+ "github.com/aws/aws-sdk-go-v2": ["aws-sdk", "aws"],
4158
+ "github.com/hashicorp/terraform-plugin-sdk": ["terraform-plugin"],
4159
+ // ─── Dart / Flutter packages ─────────────────────────────────────────────
4160
+ "flutter": ["flutter"],
4161
+ "flutter_test": ["flutter", "unit-testing"],
4162
+ "provider": ["provider", "state-management"],
4163
+ "riverpod": ["riverpod", "state-management"],
4164
+ "flutter_riverpod": ["riverpod", "state-management"],
4165
+ "hooks_riverpod": ["riverpod", "state-management"],
4166
+ "bloc": ["bloc", "state-management"],
4167
+ "flutter_bloc": ["bloc", "state-management"],
4168
+ "get": ["getx", "state-management"],
4169
+ "mobx": ["mobx", "state-management"],
4170
+ "flutter_mobx": ["mobx", "state-management"],
4171
+ "dio": ["dio", "http"],
4172
+ "http": ["http"],
4173
+ "retrofit": ["retrofit"],
4174
+ "get_it": ["get-it", "di"],
4175
+ "injectable": ["injectable", "di"],
4176
+ "shared_preferences": ["shared-preferences", "storage"],
4177
+ "hive": ["hive", "storage"],
4178
+ "sqflite": ["sqflite", "sqlite"],
4179
+ "drift": ["drift", "orm"],
4180
+ "isar": ["isar", "storage"],
4181
+ "firebase_core": ["firebase"],
4182
+ "firebase_auth": ["firebase", "auth"],
4183
+ "cloud_firestore": ["firebase", "firestore"],
4184
+ "firebase_messaging": ["firebase", "fcm"],
4185
+ "google_sign_in": ["google-sign-in", "auth"],
4186
+ "flutter_secure_storage": ["secure-storage"],
4187
+ "go_router": ["go-router", "routing"],
4188
+ "auto_route": ["auto-route", "routing"],
4189
+ "freezed": ["freezed", "code-gen"],
4190
+ "json_annotation": ["json-serializable"],
4191
+ "mockito": ["mockito", "mocking"],
4192
+ "mocktail": ["mocktail", "mocking"],
4193
+ // ─── Elixir / Hex packages ───────────────────────────────────────────────
4194
+ "phoenix": ["phoenix"],
4195
+ "phoenix_live_view": ["phoenix", "liveview"],
4196
+ "ecto": ["ecto", "orm"],
4197
+ "ecto_sql": ["ecto", "orm"],
4198
+ "postgrex": ["postgresql"],
4199
+ "myxql": ["mysql"],
4200
+ "oban": ["oban", "task-queue"],
4201
+ "broadway": ["broadway", "messaging"],
4202
+ "absinthe": ["absinthe", "graphql"],
4203
+ "guardian": ["guardian", "auth"],
4204
+ "pow": ["pow", "auth"],
4205
+ "gettext": ["gettext", "i18n"],
4206
+ "ex_unit": ["exunit", "unit-testing"],
4207
+ "ex_machina": ["ex-machina", "testing"],
4208
+ "mox": ["mox", "mocking"],
4209
+ "credo": ["credo", "linting"],
4210
+ "dialyxir": ["dialyxir"],
4211
+ "telemetry": ["telemetry"],
4212
+ "swoosh": ["swoosh", "email"],
4213
+ "cachex": ["cachex", "cache"],
4214
+ // ─── Rust crates ─────────────────────────────────────────────────────────
4215
+ "tokio": ["tokio", "async"],
4216
+ "async-std": ["async-std", "async"],
4217
+ "actix-web": ["actix-web"],
4218
+ "axum": ["axum"],
4219
+ "warp": ["warp"],
4220
+ "rocket": ["rocket"],
4221
+ "poem": ["poem"],
4222
+ "hyper": ["hyper", "http"],
4223
+ "reqwest": ["reqwest", "http"],
4224
+ "serde": ["serde", "serialization"],
4225
+ "serde_json": ["serde", "json"],
4226
+ "sqlx": ["sqlx", "orm"],
4227
+ "diesel": ["diesel", "orm"],
4228
+ "sea-orm": ["sea-orm", "orm"],
4229
+ "clap": ["clap", "cli"],
4230
+ "anyhow": ["anyhow", "error-handling"],
4231
+ "thiserror": ["thiserror", "error-handling"],
4232
+ "tracing": ["tracing", "logging"],
4233
+ "log": ["log", "logging"],
4234
+ "env_logger": ["env-logger", "logging"],
4235
+ "rayon": ["rayon", "parallelism"],
4236
+ "tonic": ["tonic", "grpc"],
4237
+ "prost": ["prost", "protobuf"],
4238
+ "redis": ["redis"],
4239
+ "mongodb": ["mongodb"],
4240
+ "aws-sdk-s3": ["aws-sdk", "aws"],
4241
+ "opentelemetry": ["opentelemetry"],
4242
+ "prometheus": ["prometheus"],
4243
+ "testcontainers": ["testcontainers", "testing"],
4244
+ "mockall": ["mockall", "mocking"],
4245
+ "criterion": ["criterion", "benchmarking"],
4246
+ "wasm-bindgen": ["wasm"],
4247
+ "leptos": ["leptos"],
4248
+ "dioxus": ["dioxus"],
4249
+ "tauri": ["tauri"],
4250
+ // ─── .NET / NuGet packages ───────────────────────────────────────────────
4251
+ "xunit": ["xunit", "unit-testing"],
4252
+ "xunit.runner.visualstudio": ["xunit"],
4253
+ "NUnit": ["nunit", "unit-testing"],
4254
+ "NUnit3TestAdapter": ["nunit"],
4255
+ "MSTest.TestFramework": ["mstest", "unit-testing"],
4256
+ "MSTest.TestAdapter": ["mstest"],
4257
+ "Microsoft.NET.Test.Sdk": ["dotnet-test"],
4258
+ "Moq": ["moq", "mocking"],
4259
+ "NSubstitute": ["nsubstitute", "mocking"],
4260
+ "FakeItEasy": ["fakeiteasy", "mocking"],
4261
+ "FluentAssertions": ["fluent-assertions"],
4262
+ "Shouldly": ["shouldly"],
4263
+ "Bogus": ["bogus", "testing"],
4264
+ "AutoFixture": ["autofixture", "testing"],
4265
+ "Respawn": ["respawn", "testing"],
4266
+ "CommunityToolkit.Mvvm": ["wpf", "mvvm"],
4267
+ "MahApps.Metro": ["wpf", "ui-framework"],
4268
+ "MaterialDesignThemes": ["wpf", "ui-framework"],
4269
+ "Avalonia": ["avalonia"],
4270
+ "Uno.UI": ["uno-platform"],
4271
+ "Microsoft.Maui.Controls": ["maui"],
4272
+ "Blazorise": ["blazor"],
4273
+ "Microsoft.AspNetCore.Components": ["blazor"],
4274
+ "Microsoft.AspNetCore.OpenApi": ["aspnet", "openapi"],
4275
+ "Swashbuckle.AspNetCore": ["aspnet", "swagger"],
4276
+ "Microsoft.EntityFrameworkCore": ["ef-core", "orm"],
4277
+ "Microsoft.EntityFrameworkCore.SqlServer": ["ef-core", "sql-server"],
4278
+ "Npgsql.EntityFrameworkCore.PostgreSQL": ["ef-core", "postgresql"],
4279
+ "Pomelo.EntityFrameworkCore.MySql": ["ef-core", "mysql"],
4280
+ "Microsoft.EntityFrameworkCore.Sqlite": ["ef-core", "sqlite"],
4281
+ "MongoDB.Driver": ["mongodb"],
4282
+ "Dapper": ["dapper", "orm"],
4283
+ "StackExchange.Redis": ["redis"],
4284
+ "Elasticsearch.Net": ["elasticsearch"],
4285
+ "NEST": ["elasticsearch"],
4286
+ "Serilog": ["serilog", "logging"],
4287
+ "Serilog.AspNetCore": ["serilog", "logging"],
4288
+ "NLog": ["nlog", "logging"],
4289
+ "log4net": ["log4net", "logging"],
4290
+ "OpenTelemetry": ["opentelemetry"],
4291
+ "OpenTelemetry.Exporter.Prometheus": ["opentelemetry", "prometheus"],
4292
+ "AutoMapper": ["automapper"],
4293
+ "MediatR": ["mediatr", "cqrs"],
4294
+ "FluentValidation": ["fluent-validation", "validation"],
4295
+ "FluentValidation.AspNetCore": ["fluent-validation"],
4296
+ "Newtonsoft.Json": ["newtonsoft-json", "json"],
4297
+ "System.Text.Json": ["json"],
4298
+ "CsvHelper": ["csvhelper"],
4299
+ "EPPlus": ["epplus", "excel"],
4300
+ "ClosedXML": ["closedxml", "excel"],
4301
+ "Polly": ["polly", "resilience"],
4302
+ "Hangfire": ["hangfire", "background-jobs"],
4303
+ "Quartz": ["quartz", "scheduling"],
4304
+ "MassTransit": ["masstransit", "messaging"],
4305
+ "RabbitMQ.Client": ["rabbitmq", "messaging"],
4306
+ "Confluent.Kafka": ["kafka", "messaging"],
4307
+ "Azure.Identity": ["azure"],
4308
+ "Azure.Storage.Blobs": ["azure", "storage"],
4309
+ "AWSSDK.Core": ["aws-sdk", "aws"],
4310
+ "AWSSDK.S3": ["aws-sdk", "aws", "s3"],
4311
+ "Google.Cloud.Storage.V1": ["gcp", "storage"],
4312
+ "Microsoft.Identity.Web": ["azure", "auth"],
4313
+ "IdentityServer4": ["identityserver", "auth", "oauth"],
4314
+ "Duende.IdentityServer": ["identityserver", "auth", "oauth"],
4315
+ "Refit": ["refit", "http"],
4316
+ "RestSharp": ["restsharp", "http"],
4317
+ "Grpc.AspNetCore": ["grpc"],
4318
+ "MessagePack": ["messagepack", "serialization"],
4319
+ "protobuf-net": ["protobuf"],
4320
+ "BenchmarkDotNet": ["benchmark"],
4321
+ "Scrutor": ["scrutor", "di"],
4322
+ "Autofac": ["autofac", "di"],
4323
+ "Lamar": ["lamar", "di"],
4324
+ "Carter": ["carter", "aspnet"],
4325
+ "FastEndpoints": ["fastendpoints", "aspnet"],
4326
+ "Ardalis.Result": ["ardalis"],
4327
+ "ErrorOr": ["error-or"],
4328
+ "OneOf": ["oneof"]
3323
4329
  };
3324
4330
  function mapSignalsToCapabilities(input) {
3325
4331
  const seen = /* @__PURE__ */ new Set();
@@ -3337,7 +4343,7 @@ function mapSignalsToCapabilities(input) {
3337
4343
  for (const pkg of input.packages) {
3338
4344
  const ids = PACKAGE_TO_IDS[pkg];
3339
4345
  if (ids) {
3340
- for (const id of ids) add(id, "package.json");
4346
+ for (const id of ids) add(id, pkg);
3341
4347
  }
3342
4348
  }
3343
4349
  return { confirmed, inferred: [] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgehive",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Context-aware AI development environment — one binary, your stack.",
5
5
  "type": "module",
6
6
  "bin": {