forgehive 1.0.2 → 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 +1001 -87
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3149,82 +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",
3172
+ // PHP
3158
3173
  "composer.json",
3174
+ // .NET
3159
3175
  "global.json",
3160
- "Directory.Build.props"
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"
3161
3207
  ];
3162
3208
  var TIER2_FILES = [
3209
+ // Containers
3163
3210
  "Dockerfile",
3164
3211
  "docker-compose.yml",
3165
- ".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"
3166
3233
  ];
3167
3234
  var TIER2_DIRS = [
3168
3235
  ".github/workflows",
3169
3236
  "terraform",
3170
- "k8s"
3237
+ "k8s",
3238
+ ".circleci",
3239
+ "ansible",
3240
+ "charts",
3241
+ "helm",
3242
+ "pulumi",
3243
+ "cdk"
3171
3244
  ];
3172
3245
  var TIER3_PATTERNS = [
3246
+ // JavaScript tooling
3173
3247
  /^\.eslintrc(\.(json|js|yml|yaml|cjs))?$/,
3248
+ /^eslint\.config\.(js|mjs|cjs|ts)$/,
3174
3249
  /^jest\.config\.(js|ts|mjs|cjs|json)$/,
3175
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
3176
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
3177
3296
  /^openapi\.(yaml|yml|json)$/,
3178
- /^\.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$/
3179
3308
  ];
3180
3309
  var DOTNET_EXTENSIONS = [".sln", ".csproj", ".fsproj", ".vbproj"];
3310
+ var SWIFT_EXTENSIONS = [".xcodeproj", ".xcworkspace"];
3181
3311
  function scan(projectRoot2) {
3182
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
+ };
3183
3319
  for (const filename of TIER1) {
3184
3320
  if (fs.existsSync(path.join(projectRoot2, filename))) {
3185
- signals.push(signal(1, filename, filename));
3321
+ addSignal(1, filename, filename);
3186
3322
  }
3187
3323
  }
3188
3324
  for (const filename of TIER2_FILES) {
3189
3325
  if (fs.existsSync(path.join(projectRoot2, filename))) {
3190
- signals.push(signal(2, filename, path.basename(filename)));
3326
+ addSignal(2, filename, path.basename(filename));
3191
3327
  }
3192
3328
  }
3193
3329
  for (const dir of TIER2_DIRS) {
3194
3330
  const abs = path.join(projectRoot2, dir);
3195
3331
  if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) continue;
3196
- for (const child of fs.readdirSync(abs)) {
3197
- const rel = path.join(dir, child);
3198
- 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 {
3199
3338
  }
3200
3339
  }
3201
- for (const entry of fs.readdirSync(projectRoot2)) {
3202
- const abs = path.join(projectRoot2, entry);
3203
- if (!fs.statSync(abs).isFile()) continue;
3204
- for (const pattern of TIER3_PATTERNS) {
3205
- if (pattern.test(entry)) {
3206
- signals.push(signal(3, entry, entry));
3207
- 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
+ }
3208
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);
3209
3354
  }
3210
- const ext = path.extname(entry).toLowerCase();
3211
- if (DOTNET_EXTENSIONS.includes(ext)) {
3212
- signals.push(signal(1, entry, entry));
3213
- }
3355
+ } catch {
3214
3356
  }
3215
- for (const entry of fs.readdirSync(projectRoot2)) {
3216
- const abs = path.join(projectRoot2, entry);
3217
- if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) continue;
3218
- try {
3219
- for (const child of fs.readdirSync(abs)) {
3220
- const ext = path.extname(child).toLowerCase();
3221
- if ([".csproj", ".fsproj", ".vbproj"].includes(ext)) {
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();
3222
3365
  const rel = path.join(entry, child);
3223
- signals.push(signal(1, rel, 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
+ }
3224
3384
  }
3385
+ } catch {
3225
3386
  }
3226
- } catch {
3227
3387
  }
3388
+ } catch {
3228
3389
  }
3229
3390
  return {
3230
3391
  scanned_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3234,39 +3395,145 @@ function scan(projectRoot2) {
3234
3395
  };
3235
3396
  }
3236
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) {
3237
3414
  const pkgPath = path.join(projectRoot2, "package.json");
3238
- if (fs.existsSync(pkgPath)) {
3415
+ if (!fs.existsSync(pkgPath)) return [];
3416
+ try {
3417
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
3418
+ return [
3419
+ ...Object.keys(pkg.dependencies ?? {}),
3420
+ ...Object.keys(pkg.devDependencies ?? {}),
3421
+ ...Object.keys(pkg.peerDependencies ?? {})
3422
+ ];
3423
+ } catch {
3424
+ return [];
3425
+ }
3426
+ }
3427
+ function extractPythonPackages(projectRoot2) {
3428
+ const packages = [];
3429
+ const reqPath = path.join(projectRoot2, "requirements.txt");
3430
+ if (fs.existsSync(reqPath)) {
3239
3431
  try {
3240
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
3241
- const all = /* @__PURE__ */ new Set([
3242
- ...Object.keys(pkg.dependencies ?? {}),
3243
- ...Object.keys(pkg.devDependencies ?? {})
3244
- ]);
3245
- return [...all];
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
+ }
3246
3487
  } catch {
3247
- return [];
3248
3488
  }
3249
3489
  }
3250
- return extractDotnetPackages(projectRoot2);
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;
3251
3515
  }
3252
3516
  function extractDotnetPackages(projectRoot2) {
3253
3517
  const packages = /* @__PURE__ */ new Set();
3254
3518
  const pattern = /PackageReference\s+Include="([^"]+)"/gi;
3255
- const scanDir = (dir) => {
3519
+ const scanDir = (dir, depth = 0) => {
3520
+ if (depth > 3) return;
3256
3521
  try {
3257
3522
  for (const entry of fs.readdirSync(dir)) {
3523
+ if (entry.startsWith(".") || entry === "node_modules") continue;
3258
3524
  const abs = path.join(dir, entry);
3259
3525
  const ext = path.extname(entry).toLowerCase();
3260
3526
  if ([".csproj", ".fsproj", ".vbproj"].includes(ext)) {
3261
3527
  try {
3262
3528
  const content = fs.readFileSync(abs, "utf8");
3263
- for (const match of content.matchAll(pattern)) {
3264
- packages.add(match[1]);
3265
- }
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);
3266
3535
  } catch {
3267
3536
  }
3268
- } else if (fs.statSync(abs).isDirectory() && !entry.startsWith(".")) {
3269
- scanDir(abs);
3270
3537
  }
3271
3538
  }
3272
3539
  } catch {
@@ -3275,143 +3542,790 @@ function extractDotnetPackages(projectRoot2) {
3275
3542
  scanDir(projectRoot2);
3276
3543
  return [...packages];
3277
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
+ }
3278
3612
  function signal(tier, filePath, filename) {
3279
3613
  return { tier, path: filePath, filename, exists: true };
3280
3614
  }
3281
3615
 
3282
3616
  // src/lookup-table.ts
3283
3617
  var FILENAME_TO_IDS = {
3618
+ // JavaScript / Node
3284
3619
  "package.json": ["nodejs", "javascript"],
3620
+ // Python
3285
3621
  "pyproject.toml": ["python"],
3286
- "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
3287
3629
  "go.mod": ["golang"],
3630
+ // Java / Kotlin / JVM
3288
3631
  "pom.xml": ["java", "maven"],
3289
- "Gemfile": ["ruby"],
3290
- "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
3291
3641
  "global.json": ["dotnet"],
3292
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
3293
3672
  "Dockerfile": ["docker"],
3294
3673
  "docker-compose.yml": ["docker-compose"],
3674
+ "docker-compose.yaml": ["docker-compose"],
3675
+ // CI/CD
3295
3676
  ".gitlab-ci.yml": ["gitlab-ci", "ci-cd"],
3296
- "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
3297
3695
  "openapi.yaml": ["openapi"],
3298
3696
  "openapi.yml": ["openapi"],
3299
3697
  "openapi.json": ["openapi"],
3300
- ".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"]
3301
3727
  };
3302
3728
  var TIER2_DIR_PREFIX_TO_IDS = {
3303
3729
  ".github/workflows": ["github-actions", "ci-cd"],
3730
+ ".circleci": ["circleci", "ci-cd"],
3304
3731
  "terraform": ["terraform", "infrastructure-as-code"],
3305
- "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"]
3306
3738
  };
3307
3739
  var FILENAME_PREFIX_TO_IDS = [
3740
+ // JS frameworks / tooling
3308
3741
  [/^jest\.config\./, ["jest", "unit-testing"]],
3309
3742
  [/^vitest\.config\./, ["vitest", "unit-testing"]],
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"]],
3310
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
3311
3773
  [/\.sln$/i, ["dotnet", "csharp"]],
3312
3774
  [/\.csproj$/i, ["dotnet", "csharp", "nuget"]],
3313
3775
  [/\.fsproj$/i, ["dotnet", "fsharp", "nuget"]],
3314
- [/\.vbproj$/i, ["dotnet", "vbnet", "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"]]
3315
3791
  ];
3316
3792
  var PACKAGE_TO_IDS = {
3317
- // JS Frameworks
3793
+ // ─── JavaScript / TypeScript Frameworks ──────────────────────────────────
3318
3794
  "react": ["react"],
3319
3795
  "react-dom": ["react"],
3320
3796
  "next": ["nextjs"],
3321
3797
  "nuxt": ["nuxt"],
3798
+ "nuxt3": ["nuxt"],
3322
3799
  "vue": ["vue"],
3323
3800
  "@vue/core": ["vue"],
3324
3801
  "svelte": ["svelte"],
3325
3802
  "@sveltejs/kit": ["sveltekit"],
3326
3803
  "remix": ["remix"],
3327
3804
  "@remix-run/react": ["remix"],
3805
+ "@remix-run/node": ["remix"],
3328
3806
  "gatsby": ["gatsby"],
3329
3807
  "astro": ["astro"],
3330
- // 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
3331
3816
  "express": ["express"],
3332
3817
  "fastify": ["fastify"],
3333
3818
  "hono": ["hono"],
3334
3819
  "koa": ["koa"],
3335
- "nestjs": ["nestjs"],
3336
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"],
3337
3828
  // Database / ORM
3338
- "@prisma/client": ["prisma"],
3339
- "prisma": ["prisma"],
3340
- "drizzle-orm": ["drizzle"],
3341
- "typeorm": ["typeorm"],
3342
- "mongoose": ["mongoose"],
3343
- "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"],
3344
3848
  // Testing JS
3345
- "vitest": ["vitest"],
3346
- "jest": ["jest"],
3347
- "@playwright/test": ["playwright"],
3348
- "playwright": ["playwright"],
3349
- "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"],
3350
3859
  "storybook": ["storybook"],
3351
3860
  "@storybook/react": ["storybook"],
3861
+ "msw": ["msw", "mocking"],
3862
+ "sinon": ["sinon", "mocking"],
3863
+ "@testing-library/react": ["testing-library"],
3864
+ "@testing-library/vue": ["testing-library"],
3352
3865
  // Build / Tooling
3353
3866
  "vite": ["vite"],
3354
3867
  "webpack": ["webpack"],
3355
3868
  "esbuild": ["esbuild"],
3869
+ "rollup": ["rollup"],
3870
+ "parcel": ["parcel"],
3356
3871
  "turbo": ["turborepo"],
3357
3872
  "nx": ["nx"],
3873
+ "lerna": ["lerna"],
3874
+ "@swc/core": ["swc"],
3875
+ "typescript": ["typescript"],
3876
+ "tsx": ["typescript"],
3877
+ "ts-node": ["typescript"],
3358
3878
  // Auth
3359
- "next-auth": ["next-auth"],
3360
- "@auth/core": ["auth-js"],
3361
- "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"],
3362
3890
  // Styling
3363
3891
  "tailwindcss": ["tailwind"],
3364
3892
  "@tailwindcss/vite": ["tailwind"],
3365
3893
  "styled-components": ["styled-components"],
3894
+ "@emotion/react": ["emotion"],
3895
+ "sass": ["sass"],
3896
+ "less": ["less"],
3897
+ "postcss": ["postcss"],
3366
3898
  // State
3367
3899
  "zustand": ["zustand"],
3368
3900
  "jotai": ["jotai"],
3369
3901
  "@reduxjs/toolkit": ["redux"],
3370
3902
  "redux": ["redux"],
3371
- // 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 ─────────────────────────────────────────────────────
3372
3945
  "fastapi": ["fastapi"],
3373
3946
  "django": ["django"],
3374
3947
  "flask": ["flask"],
3375
- "sqlalchemy": ["sqlalchemy"],
3376
- "pydantic": ["pydantic"],
3377
- "alembic": ["alembic"],
3378
- // .NET / NuGet packages
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 ───────────────────────────────────────────────
3379
4251
  "xunit": ["xunit", "unit-testing"],
4252
+ "xunit.runner.visualstudio": ["xunit"],
3380
4253
  "NUnit": ["nunit", "unit-testing"],
4254
+ "NUnit3TestAdapter": ["nunit"],
3381
4255
  "MSTest.TestFramework": ["mstest", "unit-testing"],
4256
+ "MSTest.TestAdapter": ["mstest"],
3382
4257
  "Microsoft.NET.Test.Sdk": ["dotnet-test"],
3383
4258
  "Moq": ["moq", "mocking"],
3384
4259
  "NSubstitute": ["nsubstitute", "mocking"],
4260
+ "FakeItEasy": ["fakeiteasy", "mocking"],
3385
4261
  "FluentAssertions": ["fluent-assertions"],
4262
+ "Shouldly": ["shouldly"],
4263
+ "Bogus": ["bogus", "testing"],
4264
+ "AutoFixture": ["autofixture", "testing"],
4265
+ "Respawn": ["respawn", "testing"],
3386
4266
  "CommunityToolkit.Mvvm": ["wpf", "mvvm"],
3387
- "Microsoft.Extensions.DependencyInjection": ["aspnet-di"],
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"],
3388
4274
  "Microsoft.AspNetCore.OpenApi": ["aspnet", "openapi"],
3389
4275
  "Swashbuckle.AspNetCore": ["aspnet", "swagger"],
3390
4276
  "Microsoft.EntityFrameworkCore": ["ef-core", "orm"],
3391
- "Npgsql.EntityFrameworkCore.PostgreSQL": ["ef-core", "postgresql"],
3392
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"],
3393
4282
  "Dapper": ["dapper", "orm"],
4283
+ "StackExchange.Redis": ["redis"],
4284
+ "Elasticsearch.Net": ["elasticsearch"],
4285
+ "NEST": ["elasticsearch"],
3394
4286
  "Serilog": ["serilog", "logging"],
4287
+ "Serilog.AspNetCore": ["serilog", "logging"],
3395
4288
  "NLog": ["nlog", "logging"],
4289
+ "log4net": ["log4net", "logging"],
4290
+ "OpenTelemetry": ["opentelemetry"],
4291
+ "OpenTelemetry.Exporter.Prometheus": ["opentelemetry", "prometheus"],
3396
4292
  "AutoMapper": ["automapper"],
3397
4293
  "MediatR": ["mediatr", "cqrs"],
3398
- "FluentValidation": ["fluent-validation"],
3399
- "Newtonsoft.Json": ["newtonsoft-json"],
4294
+ "FluentValidation": ["fluent-validation", "validation"],
4295
+ "FluentValidation.AspNetCore": ["fluent-validation"],
4296
+ "Newtonsoft.Json": ["newtonsoft-json", "json"],
4297
+ "System.Text.Json": ["json"],
3400
4298
  "CsvHelper": ["csvhelper"],
4299
+ "EPPlus": ["epplus", "excel"],
4300
+ "ClosedXML": ["closedxml", "excel"],
3401
4301
  "Polly": ["polly", "resilience"],
3402
4302
  "Hangfire": ["hangfire", "background-jobs"],
4303
+ "Quartz": ["quartz", "scheduling"],
3403
4304
  "MassTransit": ["masstransit", "messaging"],
3404
- "StackExchange.Redis": ["redis"],
3405
- "MongoDB.Driver": ["mongodb"],
3406
- "AWSSDK.Core": ["aws-sdk"],
4305
+ "RabbitMQ.Client": ["rabbitmq", "messaging"],
4306
+ "Confluent.Kafka": ["kafka", "messaging"],
3407
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"],
3408
4312
  "Microsoft.Identity.Web": ["azure", "auth"],
3409
- "Blazorise": ["blazor"],
3410
- "Microsoft.AspNetCore.Components": ["blazor"],
3411
- "Avalonia": ["avalonia"],
3412
- "Uno.UI": ["uno-platform"],
3413
- "MAUI": ["maui"],
3414
- "Microsoft.Maui.Controls": ["maui"]
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"]
3415
4329
  };
3416
4330
  function mapSignalsToCapabilities(input) {
3417
4331
  const seen = /* @__PURE__ */ new Set();
@@ -3429,7 +4343,7 @@ function mapSignalsToCapabilities(input) {
3429
4343
  for (const pkg of input.packages) {
3430
4344
  const ids = PACKAGE_TO_IDS[pkg];
3431
4345
  if (ids) {
3432
- for (const id of ids) add(id, "package.json");
4346
+ for (const id of ids) add(id, pkg);
3433
4347
  }
3434
4348
  }
3435
4349
  return { confirmed, inferred: [] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgehive",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Context-aware AI development environment — one binary, your stack.",
5
5
  "type": "module",
6
6
  "bin": {