thuban 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +187 -0
- package/dist/cli.js +2 -0
- package/dist/packages/crucible/.golden/golden-master.json +414 -0
- package/dist/packages/crucible/badge-generator.js +1 -0
- package/dist/packages/crucible/banner.js +1 -0
- package/dist/packages/crucible/ci-integration.js +1 -0
- package/dist/packages/crucible/golden-master.js +1 -0
- package/dist/packages/crucible/index.js +1 -0
- package/dist/packages/crucible/kenny-mode.js +1 -0
- package/dist/packages/crucible/leaderboard.js +1 -0
- package/dist/packages/crucible/mutation-engine.js +1 -0
- package/dist/packages/crucible/pattern-learner.js +1 -0
- package/dist/packages/crucible/report-generator.js +1 -0
- package/dist/packages/crucible/rule-loader.js +1 -0
- package/dist/packages/crucible/seeding-engine.js +1 -0
- package/dist/packages/crucible/seeds/csharp/seed-001.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-002.cs +24 -0
- package/dist/packages/crucible/seeds/csharp/seed-003.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-004.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-005.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-006.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-007.cs +34 -0
- package/dist/packages/crucible/seeds/csharp/seed-008.cs +23 -0
- package/dist/packages/crucible/seeds/csharp/seed-009.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-010.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-011.cs +32 -0
- package/dist/packages/crucible/seeds/csharp/seed-012.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-013.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-014.cs +26 -0
- package/dist/packages/crucible/seeds/csharp/seed-015.cs +33 -0
- package/dist/packages/crucible/seeds/csharp/seed-016.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-017.cs +22 -0
- package/dist/packages/crucible/seeds/csharp/seed-018.cs +26 -0
- package/dist/packages/crucible/seeds/csharp/seed-019.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-020.cs +22 -0
- package/dist/packages/crucible/seeds/csharp/seed-021.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-022.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-023.cs +33 -0
- package/dist/packages/crucible/seeds/csharp/seed-024.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-025.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-026.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-027.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-028.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-029.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-030.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-031.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-032.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-033.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-034.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-035.cs +32 -0
- package/dist/packages/crucible/seeds/csharp/seed-036.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-037.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-038.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-039.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-040.cs +28 -0
- package/dist/packages/crucible/seeds/csharp/seed-041.cs +33 -0
- package/dist/packages/crucible/seeds/csharp/seed-042.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-043.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-044.cs +25 -0
- package/dist/packages/crucible/seeds/csharp/seed-045.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-046.cs +29 -0
- package/dist/packages/crucible/seeds/csharp/seed-047.cs +26 -0
- package/dist/packages/crucible/seeds/csharp/seed-048.cs +31 -0
- package/dist/packages/crucible/seeds/csharp/seed-049.cs +27 -0
- package/dist/packages/crucible/seeds/csharp/seed-050.cs +30 -0
- package/dist/packages/crucible/seeds/csharp/seed-051.cs +34 -0
- package/dist/packages/crucible/seeds/csharp/seed-052.cs +36 -0
- package/dist/packages/crucible/seeds/go/seed-001.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-002.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-003.go +31 -0
- package/dist/packages/crucible/seeds/go/seed-004.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-005.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-006.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-007.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-008.go +25 -0
- package/dist/packages/crucible/seeds/go/seed-009.go +30 -0
- package/dist/packages/crucible/seeds/go/seed-010.go +35 -0
- package/dist/packages/crucible/seeds/go/seed-011.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-012.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-013.go +31 -0
- package/dist/packages/crucible/seeds/go/seed-014.go +35 -0
- package/dist/packages/crucible/seeds/go/seed-015.go +25 -0
- package/dist/packages/crucible/seeds/go/seed-016.go +19 -0
- package/dist/packages/crucible/seeds/go/seed-017.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-018.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-019.go +22 -0
- package/dist/packages/crucible/seeds/go/seed-020.go +31 -0
- package/dist/packages/crucible/seeds/go/seed-021.go +22 -0
- package/dist/packages/crucible/seeds/go/seed-022.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-023.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-024.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-025.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-026.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-027.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-028.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-029.go +28 -0
- package/dist/packages/crucible/seeds/go/seed-030.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-031.go +28 -0
- package/dist/packages/crucible/seeds/go/seed-032.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-033.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-034.go +22 -0
- package/dist/packages/crucible/seeds/go/seed-035.go +32 -0
- package/dist/packages/crucible/seeds/go/seed-036.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-037.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-038.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-039.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-040.go +37 -0
- package/dist/packages/crucible/seeds/go/seed-041.go +23 -0
- package/dist/packages/crucible/seeds/go/seed-042.go +32 -0
- package/dist/packages/crucible/seeds/go/seed-043.go +35 -0
- package/dist/packages/crucible/seeds/go/seed-044.go +25 -0
- package/dist/packages/crucible/seeds/go/seed-045.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-046.go +34 -0
- package/dist/packages/crucible/seeds/go/seed-047.go +26 -0
- package/dist/packages/crucible/seeds/go/seed-048.go +29 -0
- package/dist/packages/crucible/seeds/go/seed-049.go +24 -0
- package/dist/packages/crucible/seeds/go/seed-050.go +27 -0
- package/dist/packages/crucible/seeds/go/seed-051.go +38 -0
- package/dist/packages/crucible/seeds/go/seed-052.go +27 -0
- package/dist/packages/crucible/seeds/java/seed-001.java +23 -0
- package/dist/packages/crucible/seeds/java/seed-002.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-003.java +28 -0
- package/dist/packages/crucible/seeds/java/seed-004.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-005.java +33 -0
- package/dist/packages/crucible/seeds/java/seed-006.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-007.java +21 -0
- package/dist/packages/crucible/seeds/java/seed-008.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-009.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-010.java +30 -0
- package/dist/packages/crucible/seeds/java/seed-011.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-012.java +20 -0
- package/dist/packages/crucible/seeds/java/seed-013.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-014.java +23 -0
- package/dist/packages/crucible/seeds/java/seed-015.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-016.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-017.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-018.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-019.java +38 -0
- package/dist/packages/crucible/seeds/java/seed-020.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-021.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-022.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-023.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-024.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-025.java +27 -0
- package/dist/packages/crucible/seeds/java/seed-026.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-027.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-028.java +21 -0
- package/dist/packages/crucible/seeds/java/seed-029.java +28 -0
- package/dist/packages/crucible/seeds/java/seed-030.java +27 -0
- package/dist/packages/crucible/seeds/java/seed-031.java +23 -0
- package/dist/packages/crucible/seeds/java/seed-032.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-033.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-034.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-035.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-036.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-037.java +30 -0
- package/dist/packages/crucible/seeds/java/seed-038.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-039.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-040.java +31 -0
- package/dist/packages/crucible/seeds/java/seed-041.java +20 -0
- package/dist/packages/crucible/seeds/java/seed-042.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-043.java +31 -0
- package/dist/packages/crucible/seeds/java/seed-044.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-045.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-046.java +22 -0
- package/dist/packages/crucible/seeds/java/seed-047.java +26 -0
- package/dist/packages/crucible/seeds/java/seed-048.java +24 -0
- package/dist/packages/crucible/seeds/java/seed-049.java +28 -0
- package/dist/packages/crucible/seeds/java/seed-050.java +29 -0
- package/dist/packages/crucible/seeds/java/seed-051.java +25 -0
- package/dist/packages/crucible/seeds/java/seed-052.java +32 -0
- package/dist/packages/crucible/seeds/js/seed-001.js +27 -0
- package/dist/packages/crucible/seeds/js/seed-002.js +28 -0
- package/dist/packages/crucible/seeds/js/seed-003.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-004.js +28 -0
- package/dist/packages/crucible/seeds/js/seed-005.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-006.js +28 -0
- package/dist/packages/crucible/seeds/js/seed-007.js +26 -0
- package/dist/packages/crucible/seeds/js/seed-008.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-009.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-010.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-011.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-012.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-013.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-014.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-015.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-016.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-017.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-018.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-019.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-020.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-021.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-022.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-023.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-024.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-025.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-026.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-027.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-028.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-029.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-030.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-031.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-032.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-033.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-034.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-035.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-036.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-037.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-038.js +31 -0
- package/dist/packages/crucible/seeds/js/seed-039.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-040.js +35 -0
- package/dist/packages/crucible/seeds/js/seed-041.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-042.js +32 -0
- package/dist/packages/crucible/seeds/js/seed-043.js +27 -0
- package/dist/packages/crucible/seeds/js/seed-044.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-045.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-046.js +33 -0
- package/dist/packages/crucible/seeds/js/seed-047.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-048.js +29 -0
- package/dist/packages/crucible/seeds/js/seed-049.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-050.js +34 -0
- package/dist/packages/crucible/seeds/js/seed-051.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-052.js +30 -0
- package/dist/packages/crucible/seeds/js/seed-053.js +26 -0
- package/dist/packages/crucible/seeds/js/seed-054.js +35 -0
- package/dist/packages/crucible/seeds/js/seed-055.js +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-001.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-002.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-003.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-004.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-005.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-006.kt +21 -0
- package/dist/packages/crucible/seeds/kotlin/seed-007.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-008.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-009.kt +21 -0
- package/dist/packages/crucible/seeds/kotlin/seed-010.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-011.kt +22 -0
- package/dist/packages/crucible/seeds/kotlin/seed-012.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-013.kt +30 -0
- package/dist/packages/crucible/seeds/kotlin/seed-014.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-015.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-016.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-017.kt +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-018.kt +31 -0
- package/dist/packages/crucible/seeds/kotlin/seed-019.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-020.kt +31 -0
- package/dist/packages/crucible/seeds/kotlin/seed-021.kt +34 -0
- package/dist/packages/crucible/seeds/kotlin/seed-022.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-023.kt +20 -0
- package/dist/packages/crucible/seeds/kotlin/seed-024.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-025.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-026.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-027.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-028.kt +24 -0
- package/dist/packages/crucible/seeds/kotlin/seed-029.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-030.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-031.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-032.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-033.kt +30 -0
- package/dist/packages/crucible/seeds/kotlin/seed-034.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-035.kt +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-036.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-037.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-038.kt +25 -0
- package/dist/packages/crucible/seeds/kotlin/seed-039.kt +29 -0
- package/dist/packages/crucible/seeds/kotlin/seed-040.kt +28 -0
- package/dist/packages/crucible/seeds/kotlin/seed-041.kt +31 -0
- package/dist/packages/crucible/seeds/kotlin/seed-042.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-043.kt +26 -0
- package/dist/packages/crucible/seeds/kotlin/seed-044.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-045.kt +27 -0
- package/dist/packages/crucible/seeds/kotlin/seed-046.kt +33 -0
- package/dist/packages/crucible/seeds/kotlin/seed-047.kt +32 -0
- package/dist/packages/crucible/seeds/kotlin/seed-048.kt +20 -0
- package/dist/packages/crucible/seeds/kotlin/seed-049.kt +23 -0
- package/dist/packages/crucible/seeds/kotlin/seed-050.kt +19 -0
- package/dist/packages/crucible/seeds/php/seed-001.php +23 -0
- package/dist/packages/crucible/seeds/php/seed-002.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-003.php +25 -0
- package/dist/packages/crucible/seeds/php/seed-004.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-005.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-006.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-007.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-008.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-009.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-010.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-011.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-012.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-013.php +23 -0
- package/dist/packages/crucible/seeds/php/seed-014.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-015.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-016.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-017.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-018.php +17 -0
- package/dist/packages/crucible/seeds/php/seed-019.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-020.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-021.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-022.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-023.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-024.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-025.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-026.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-027.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-028.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-029.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-030.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-031.php +23 -0
- package/dist/packages/crucible/seeds/php/seed-032.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-033.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-034.php +24 -0
- package/dist/packages/crucible/seeds/php/seed-035.php +22 -0
- package/dist/packages/crucible/seeds/php/seed-036.php +17 -0
- package/dist/packages/crucible/seeds/php/seed-037.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-038.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-039.php +15 -0
- package/dist/packages/crucible/seeds/php/seed-040.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-041.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-042.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-043.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-044.php +25 -0
- package/dist/packages/crucible/seeds/php/seed-045.php +25 -0
- package/dist/packages/crucible/seeds/php/seed-046.php +20 -0
- package/dist/packages/crucible/seeds/php/seed-047.php +21 -0
- package/dist/packages/crucible/seeds/php/seed-048.php +19 -0
- package/dist/packages/crucible/seeds/php/seed-049.php +18 -0
- package/dist/packages/crucible/seeds/php/seed-050.php +20 -0
- package/dist/packages/crucible/seeds/python/seed-001.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-002.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-003.py +31 -0
- package/dist/packages/crucible/seeds/python/seed-004.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-005.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-006.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-007.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-008.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-009.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-010.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-011.py +30 -0
- package/dist/packages/crucible/seeds/python/seed-012.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-013.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-014.py +40 -0
- package/dist/packages/crucible/seeds/python/seed-015.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-016.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-017.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-018.py +30 -0
- package/dist/packages/crucible/seeds/python/seed-019.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-020.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-021 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-021 3.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-021.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-022 2.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-022 3.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-022.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-023 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-023 3.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-023.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-024 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-024 3.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-024.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-025 2.py +40 -0
- package/dist/packages/crucible/seeds/python/seed-025 3.py +40 -0
- package/dist/packages/crucible/seeds/python/seed-025.py +40 -0
- package/dist/packages/crucible/seeds/python/seed-026 2.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-026 3.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-026.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-027 2.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-027 3.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-027.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-028 2.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-028 3.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-028.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-029.py +42 -0
- package/dist/packages/crucible/seeds/python/seed-030 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-030 3.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-030.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-031 2.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-031 3.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-031.py +34 -0
- package/dist/packages/crucible/seeds/python/seed-032.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-033.py +32 -0
- package/dist/packages/crucible/seeds/python/seed-034.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-035.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-036 2.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-036 3.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-036.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-037 2.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-037 3.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-037.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-038 2.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-038 3.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-038.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-039 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-039 3.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-039.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-040 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-040 3.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-040.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-041 2.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-041 3.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-041.py +37 -0
- package/dist/packages/crucible/seeds/python/seed-042 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-042 3.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-042.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-043 2.py +32 -0
- package/dist/packages/crucible/seeds/python/seed-043 3.py +32 -0
- package/dist/packages/crucible/seeds/python/seed-043.py +32 -0
- package/dist/packages/crucible/seeds/python/seed-044 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-044 3.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-044.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-045 2.py +36 -0
- package/dist/packages/crucible/seeds/python/seed-045 3.py +36 -0
- package/dist/packages/crucible/seeds/python/seed-045.py +36 -0
- package/dist/packages/crucible/seeds/python/seed-046 2.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-046 3.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-046.py +33 -0
- package/dist/packages/crucible/seeds/python/seed-047 2.py +44 -0
- package/dist/packages/crucible/seeds/python/seed-047 3.py +44 -0
- package/dist/packages/crucible/seeds/python/seed-047.py +44 -0
- package/dist/packages/crucible/seeds/python/seed-048 2.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-048 3.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-048.py +35 -0
- package/dist/packages/crucible/seeds/python/seed-049 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-049 3.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-049.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-050 2.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-050 3.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-050.py +39 -0
- package/dist/packages/crucible/seeds/python/seed-051 2.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-051 3.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-051.py +38 -0
- package/dist/packages/crucible/seeds/python/seed-052 2.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-052 3.py +41 -0
- package/dist/packages/crucible/seeds/python/seed-052.py +41 -0
- package/dist/packages/crucible/seeds/ruby/seed-001 2.rb +15 -0
- package/dist/packages/crucible/seeds/ruby/seed-001 3.rb +15 -0
- package/dist/packages/crucible/seeds/ruby/seed-001.rb +15 -0
- package/dist/packages/crucible/seeds/ruby/seed-002 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-002 3.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-002.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-003 2.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-003 3.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-003.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-004 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-004 3.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-004.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-005 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-005 3.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-005.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-006 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-006 3.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-006.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-007 2.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-007 3.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-007.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-008 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-008 3.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-008.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-009 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-009 3.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-009.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-010 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-010 3.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-010.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-011 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-011 3.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-011.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-012 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-012 3.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-012.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-013 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-013 3.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-013.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-014 2.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-014 3.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-014.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-015 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-015 3.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-015.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-016 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-016 3.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-016.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-017 2.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-017 3.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-017.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-018 2.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-018 3.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-018.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-019 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-019 3.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-019.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-020 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-020 3.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-020.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-021 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-021 3.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-021.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-022 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-022 3.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-022.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-023 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-023 3.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-023.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-024 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-024 3.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-024.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-025 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-025 3.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-025.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-026 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-026 3.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-026.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-027 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-027 3.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-027.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-028 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-028 3.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-028.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-029 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-029 3.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-029.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-030 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-030 3.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-030.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-031 2.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-031 3.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-031.rb +17 -0
- package/dist/packages/crucible/seeds/ruby/seed-032 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-032 3.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-032.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-033 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-033 3.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-033.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-034 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-034 3.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-034.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-035 2.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-035 3.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-035.rb +19 -0
- package/dist/packages/crucible/seeds/ruby/seed-036 2.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-036 3.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-036.rb +18 -0
- package/dist/packages/crucible/seeds/ruby/seed-037 2.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-037 3.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-037.rb +21 -0
- package/dist/packages/crucible/seeds/ruby/seed-038 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-038 3.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-038.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-039 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-039 3.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-039.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-040 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-040 3.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-040.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-041 2.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-041 3.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-041.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-042 2.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-042 3.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-042.rb +25 -0
- package/dist/packages/crucible/seeds/ruby/seed-043 2.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-043 3.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-043.rb +23 -0
- package/dist/packages/crucible/seeds/ruby/seed-044 2.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-044 3.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-044.rb +16 -0
- package/dist/packages/crucible/seeds/ruby/seed-045 2.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-045 3.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-045.rb +22 -0
- package/dist/packages/crucible/seeds/ruby/seed-046 2.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-046 3.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-046.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-047 2.rb +26 -0
- package/dist/packages/crucible/seeds/ruby/seed-047 3.rb +26 -0
- package/dist/packages/crucible/seeds/ruby/seed-047.rb +26 -0
- package/dist/packages/crucible/seeds/ruby/seed-048 2.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-048 3.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-048.rb +24 -0
- package/dist/packages/crucible/seeds/ruby/seed-049 2.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-049 3.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-049.rb +20 -0
- package/dist/packages/crucible/seeds/ruby/seed-050 2.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-050 3.rb +27 -0
- package/dist/packages/crucible/seeds/ruby/seed-050.rb +27 -0
- package/dist/packages/crucible/seeds/rust/seed-001 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-001 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-001.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-002 2.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-002 3.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-002.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-003 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-003 3.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-003.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-004 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-004 3.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-004.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-005 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-005 3.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-005.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-006 2.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-006 3.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-006.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-007 2.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-007 3.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-007.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-008 2.rs +19 -0
- package/dist/packages/crucible/seeds/rust/seed-008 3.rs +19 -0
- package/dist/packages/crucible/seeds/rust/seed-008.rs +19 -0
- package/dist/packages/crucible/seeds/rust/seed-009 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-009 3.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-009.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-010 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-010 3.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-010.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-011 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-011 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-011.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-012 2.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-012 3.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-012.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-013 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-013 3.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-013.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-014 2.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-014 3.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-014.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-015 2.rs +33 -0
- package/dist/packages/crucible/seeds/rust/seed-015 3.rs +33 -0
- package/dist/packages/crucible/seeds/rust/seed-015.rs +33 -0
- package/dist/packages/crucible/seeds/rust/seed-016 2.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-016 3.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-016.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-017 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-017 3.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-017.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-018 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-018 3.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-018.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-019 2.rs +36 -0
- package/dist/packages/crucible/seeds/rust/seed-019 3.rs +36 -0
- package/dist/packages/crucible/seeds/rust/seed-019.rs +36 -0
- package/dist/packages/crucible/seeds/rust/seed-020 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-020 3.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-020.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-021 2.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-021 3.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-021.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-022 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-022 3.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-022.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-023 2.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-023 3.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-023.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-024 2.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-024 3.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-024.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-025 2.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-025 3.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-025.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-026 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-026 3.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-026.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-027 2.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-027 3.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-027.rs +24 -0
- package/dist/packages/crucible/seeds/rust/seed-028 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-028 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-028.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-029 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-029 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-029.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-030 2.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-030 3.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-030.rs +30 -0
- package/dist/packages/crucible/seeds/rust/seed-031 2.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-031 3.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-031.rs +22 -0
- package/dist/packages/crucible/seeds/rust/seed-032 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-032 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-032.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-033 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-033 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-033.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-034 2.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-034 3.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-034.rs +20 -0
- package/dist/packages/crucible/seeds/rust/seed-035 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-035 3.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-035.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-036 2.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-036 3.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-036.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-037 2.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-037 3.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-037.rs +31 -0
- package/dist/packages/crucible/seeds/rust/seed-038 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-038 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-038.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-039 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-039 3.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-039.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-040 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-040 3.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-040.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-041 2.rs +32 -0
- package/dist/packages/crucible/seeds/rust/seed-041 3.rs +32 -0
- package/dist/packages/crucible/seeds/rust/seed-041.rs +32 -0
- package/dist/packages/crucible/seeds/rust/seed-042 2.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-042 3.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-042.rs +27 -0
- package/dist/packages/crucible/seeds/rust/seed-043 2.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-043 3.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-043.rs +29 -0
- package/dist/packages/crucible/seeds/rust/seed-044 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-044 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-044.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-045 2.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-045 3.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-045.rs +28 -0
- package/dist/packages/crucible/seeds/rust/seed-046 2.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-046 3.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-046.rs +25 -0
- package/dist/packages/crucible/seeds/rust/seed-047 2.rs +34 -0
- package/dist/packages/crucible/seeds/rust/seed-047 3.rs +34 -0
- package/dist/packages/crucible/seeds/rust/seed-047.rs +34 -0
- package/dist/packages/crucible/seeds/rust/seed-048 2.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-048 3.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-048.rs +21 -0
- package/dist/packages/crucible/seeds/rust/seed-049 2.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-049 3.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-049.rs +26 -0
- package/dist/packages/crucible/seeds/rust/seed-050 2.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-050 3.rs +23 -0
- package/dist/packages/crucible/seeds/rust/seed-050.rs +23 -0
- package/dist/packages/crucible/seeds/ts/seed-001 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-001 3.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-001.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-002 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-002 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-002.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-003 2.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-003 3.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-003.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-004 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-004 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-004.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-005 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-005 3.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-005.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-006 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-006 3.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-006.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-007 2.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-007 3.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-007.ts +28 -0
- package/dist/packages/crucible/seeds/ts/seed-008 2.ts +40 -0
- package/dist/packages/crucible/seeds/ts/seed-008 3.ts +40 -0
- package/dist/packages/crucible/seeds/ts/seed-008.ts +40 -0
- package/dist/packages/crucible/seeds/ts/seed-009 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-009 3.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-009.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-010 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-010 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-010.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-011 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-011 3.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-011.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-012 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-012 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-012.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-013 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-013 3.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-013.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-014 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-014 3.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-014.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-015 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-015 3.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-015.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-016 2.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-016 3.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-016.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-017 2.ts +44 -0
- package/dist/packages/crucible/seeds/ts/seed-017 3.ts +44 -0
- package/dist/packages/crucible/seeds/ts/seed-017.ts +44 -0
- package/dist/packages/crucible/seeds/ts/seed-018 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-018 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-018.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-019 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-019 3.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-019.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-020 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-020 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-020.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-021 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-021 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-021.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-022 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-022 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-022.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-023 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-023 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-023.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-024 2.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-024 3.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-024.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-025 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-025 3.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-025.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-026 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-026 3.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-026.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-027 2.ts +30 -0
- package/dist/packages/crucible/seeds/ts/seed-027 3.ts +30 -0
- package/dist/packages/crucible/seeds/ts/seed-027.ts +30 -0
- package/dist/packages/crucible/seeds/ts/seed-028 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-028 3.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-028.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-029 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-029 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-029.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-030 2.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-030 3.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-030.ts +37 -0
- package/dist/packages/crucible/seeds/ts/seed-031 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-031 3.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-031.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-032 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-032 3.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-032.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-033 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-033 3.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-033.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-034 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-034 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-034.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-035 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-035 3.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-035.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-036 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-036 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-036.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-037 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-037 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-037.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-038 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-038 3.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-038.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-039 2.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-039 3.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-039.ts +35 -0
- package/dist/packages/crucible/seeds/ts/seed-040 2.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-040 3.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-040.ts +31 -0
- package/dist/packages/crucible/seeds/ts/seed-041 2.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-041 3.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-041.ts +29 -0
- package/dist/packages/crucible/seeds/ts/seed-042 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-042 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-042.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-043 2.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-043 3.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-043.ts +32 -0
- package/dist/packages/crucible/seeds/ts/seed-044 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-044 3.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-044.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-045 2.ts +39 -0
- package/dist/packages/crucible/seeds/ts/seed-045 3.ts +39 -0
- package/dist/packages/crucible/seeds/ts/seed-045.ts +39 -0
- package/dist/packages/crucible/seeds/ts/seed-046 2.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-046 3.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-046.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-047 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-047 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-047.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-048 2.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-048 3.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-048.ts +33 -0
- package/dist/packages/crucible/seeds/ts/seed-049 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-049 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-049.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-050 2.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-050 3.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-050.ts +41 -0
- package/dist/packages/crucible/seeds/ts/seed-051 2.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-051 3.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-051.ts +34 -0
- package/dist/packages/crucible/seeds/ts/seed-052 2.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-052 3.ts +36 -0
- package/dist/packages/crucible/seeds/ts/seed-052.ts +36 -0
- package/dist/packages/crucible/self-attack.js +1 -0
- package/dist/packages/scanner/ai-confidence-scorer.js +1 -0
- package/dist/packages/scanner/alert-manager.js +1 -0
- package/dist/packages/scanner/ast-analyzer.js +1 -0
- package/dist/packages/scanner/baseline-manager.js +1 -0
- package/dist/packages/scanner/cfg-analyzer.js +1 -0
- package/dist/packages/scanner/code-scanner.js +1 -0
- package/dist/packages/scanner/codebase-passport.js +1 -0
- package/dist/packages/scanner/copy-paste-detector.js +1 -0
- package/dist/packages/scanner/dependency-graph.js +1 -0
- package/dist/packages/scanner/drift-detector.js +1 -0
- package/dist/packages/scanner/executive-report.js +1 -0
- package/dist/packages/scanner/export-verifier.js +1 -0
- package/dist/packages/scanner/file-collector.js +1 -0
- package/dist/packages/scanner/file-watcher.js +1 -0
- package/dist/packages/scanner/ghost-code-detector.js +1 -0
- package/dist/packages/scanner/go-ast-analyzer.js +1 -0
- package/dist/packages/scanner/hallucination-detector.js +1 -0
- package/dist/packages/scanner/health-checker.js +1 -0
- package/dist/packages/scanner/html-report.js +1 -0
- package/dist/packages/scanner/index.js +1 -0
- package/dist/packages/scanner/license-manager.js +1 -0
- package/dist/packages/scanner/master-health-checker.js +1 -0
- package/dist/packages/scanner/monitor-notifier.js +1 -0
- package/dist/packages/scanner/monitor-service.js +1 -0
- package/dist/packages/scanner/monitor-store.js +1 -0
- package/dist/packages/scanner/pre-commit-gate.js +1 -0
- package/dist/packages/scanner/python-ast-analyzer.js +1 -0
- package/dist/packages/scanner/scan-diff.js +1 -0
- package/dist/packages/scanner/scan-runner.js +1 -0
- package/dist/packages/scanner/secret-scanner.js +1 -0
- package/dist/packages/scanner/sentinel-core.js +1 -0
- package/dist/packages/scanner/sentinel-knowledge.js +1 -0
- package/dist/packages/scanner/taint-tracker.js +1 -0
- package/dist/packages/scanner/tech-debt-analyzer.js +1 -0
- package/dist/packages/scanner/tech-debt-cost.js +1 -0
- package/dist/packages/scanner/widget-generator.js +1 -0
- package/package.json +15 -7
- package/cli.js +0 -2627
- package/packages/scanner/ai-confidence-scorer.js +0 -260
- package/packages/scanner/alert-manager.js +0 -398
- package/packages/scanner/baseline-manager.js +0 -109
- package/packages/scanner/code-scanner.js +0 -758
- package/packages/scanner/codebase-passport.js +0 -299
- package/packages/scanner/copy-paste-detector.js +0 -276
- package/packages/scanner/dependency-graph.js +0 -541
- package/packages/scanner/drift-detector.js +0 -423
- package/packages/scanner/executive-report.js +0 -774
- package/packages/scanner/file-collector.js +0 -64
- package/packages/scanner/file-watcher.js +0 -323
- package/packages/scanner/ghost-code-detector.js +0 -301
- package/packages/scanner/hallucination-detector.js +0 -822
- package/packages/scanner/health-checker.js +0 -586
- package/packages/scanner/html-report.js +0 -634
- package/packages/scanner/index.js +0 -100
- package/packages/scanner/license-manager.js +0 -331
- package/packages/scanner/master-health-checker.js +0 -513
- package/packages/scanner/monitor-notifier.js +0 -64
- package/packages/scanner/monitor-service.js +0 -103
- package/packages/scanner/monitor-store.js +0 -117
- package/packages/scanner/pre-commit-gate.js +0 -216
- package/packages/scanner/scan-diff.js +0 -50
- package/packages/scanner/scan-runner.js +0 -172
- package/packages/scanner/secret-scanner.js +0 -612
- package/packages/scanner/secret-scanner.test.js +0 -103
- package/packages/scanner/sentinel-core.js +0 -616
- package/packages/scanner/sentinel-knowledge.js +0 -322
- package/packages/scanner/tech-debt-analyzer.js +0 -583
- package/packages/scanner/tech-debt-cost.js +0 -194
- package/packages/scanner/widget-generator.js +0 -415
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Thuban is an independent AI software assurance platform for pull requests, releases, and codebase trust. It combines codebase intelligence, scanner-driven risk detection, and Forge-style verification so teams can decide whether AI-assisted changes are safe to merge.
|
|
4
4
|
|
|
5
|
+
**Capability boundary:** Thuban is an AI-code-specific triage layer. Deprecated API detection, phantom/hallucinated API detection, and AI code-smell detection are a curated set of common patterns frequently generated by AI coding tools — not an exhaustive or dynamically-learned catalog. The exception is named-export verification, which is real AST-based analysis (via `@babel/parser`, not pattern matching): it checks whether `import { foo } from 'bar'` actually resolves to a real export of `bar`. Thuban's taint tracker (`packages/scanner/taint-tracker.js`) traces user-input sources (`req.query`/`body`/`params`, `process.argv`/`env`, `sys.argv`, `request.args`, etc.) through variable assignment, concatenation, and template interpolation to dangerous SQL/XSS sinks — for JS/TS this now follows taint **across file boundaries** too: if file A exports a tainted value (`module.exports`/`export`) and file B imports it (`require()`/`import`, including destructured imports and re-exports), uses in file B are flagged with `crossFile: true` and a `sourceFile` pointing back to the origin. It does not yet track taint through function call/return boundaries within a file, or across Python module imports. Thuban is not a substitute for deep security auditing. For full interprocedural data-flow assurance, pair Thuban with tools like Semgrep or CodeQL.
|
|
6
|
+
|
|
5
7
|
## Product wedge
|
|
6
8
|
|
|
7
9
|
Thuban is built around a PR assurance wedge:
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Silverwings Benefits Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Thuban
|
|
2
|
+
|
|
3
|
+
Thuban is an independent AI software assurance platform for pull requests, releases, and codebase trust. It combines codebase intelligence, scanner-driven risk detection, and Forge-style verification so teams can decide whether AI-assisted changes are safe to merge.
|
|
4
|
+
|
|
5
|
+
**Capability boundary:** Thuban is an AI-code-specific triage layer. Deprecated API detection, phantom/hallucinated API detection, and AI code-smell detection are a curated set of common patterns frequently generated by AI coding tools — not an exhaustive or dynamically-learned catalog. The exception is named-export verification, which is real AST-based analysis (via `@babel/parser`, not pattern matching): it checks whether `import { foo } from 'bar'` actually resolves to a real export of `bar`. Thuban's taint tracker (`packages/scanner/taint-tracker.js`) traces user-input sources (`req.query`/`body`/`params`, `process.argv`/`env`, `sys.argv`, `request.args`, etc.) through variable assignment, concatenation, and template interpolation to dangerous SQL/XSS sinks — for JS/TS this now follows taint **across file boundaries** too: if file A exports a tainted value (`module.exports`/`export`) and file B imports it (`require()`/`import`, including destructured imports and re-exports), uses in file B are flagged with `crossFile: true` and a `sourceFile` pointing back to the origin. It does not yet track taint through function call/return boundaries within a file, or across Python module imports. Thuban is not a substitute for deep security auditing. For full interprocedural data-flow assurance, pair Thuban with tools like Semgrep or CodeQL.
|
|
6
|
+
|
|
7
|
+
## Product wedge
|
|
8
|
+
|
|
9
|
+
Thuban is built around a PR assurance wedge:
|
|
10
|
+
|
|
11
|
+
- connect a GitHub repository through a future GitHub App
|
|
12
|
+
- analyze changed files and architectural blast radius
|
|
13
|
+
- run assurance checks and evidence collection
|
|
14
|
+
- issue a clear verdict with remediation guidance
|
|
15
|
+
|
|
16
|
+
This standalone extraction is based on the Thuban product strategy and the prior CODEX specifications inside `orion-main`.
|
|
17
|
+
|
|
18
|
+
## Repository layout
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
apps/
|
|
22
|
+
api/ Express placeholder API for ingestion, assurance, and attestations
|
|
23
|
+
web/ Next.js placeholder operator UI
|
|
24
|
+
packages/
|
|
25
|
+
scanner/ Extracted Sentinel scanner and monitoring substrate
|
|
26
|
+
forge/ Extracted Forge verifier and verification data
|
|
27
|
+
docs/
|
|
28
|
+
source/ Original CODEX and Orion intelligence specs
|
|
29
|
+
strategy/ Product strategy and viability docs
|
|
30
|
+
schema/ Thuban-only database schema extract
|
|
31
|
+
venture/ Original venture README source
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What is real today
|
|
35
|
+
|
|
36
|
+
- `packages/scanner/` contains extracted working Sentinel code from Orion
|
|
37
|
+
- `packages/forge/forge-verifier.js` contains extracted Forge verification logic
|
|
38
|
+
- `packages/forge/data/forge-verifications/` contains historical verification artifacts
|
|
39
|
+
- `docs/` contains the original strategy, viability, and CODEX-era source materials
|
|
40
|
+
|
|
41
|
+
## What is placeholder today
|
|
42
|
+
|
|
43
|
+
- `apps/api/` is an Express starter aligned to the target product shape
|
|
44
|
+
- `apps/web/` is a minimal Next.js starter for the future assurance dashboard
|
|
45
|
+
- Postgres integration, GitHub App auth, webhook ingestion, PR check-runs, and production orchestration are planned but not yet implemented here
|
|
46
|
+
|
|
47
|
+
See `ARCHITECTURE.md` for a clear real-vs-placeholder breakdown.
|
|
48
|
+
|
|
49
|
+
## Architecture overview
|
|
50
|
+
|
|
51
|
+
### Apps
|
|
52
|
+
|
|
53
|
+
- `apps/api`: future control plane and integration surface for repos, pull requests, audits, policies, and attestations
|
|
54
|
+
- `apps/web`: future UI for onboarding repos, reviewing audit evidence, and tracking trust history
|
|
55
|
+
|
|
56
|
+
### Packages
|
|
57
|
+
|
|
58
|
+
- `packages/scanner`: repository scanning, dependency graphing, drift detection, health checks, alerting, and secret/credential exposure scanning for hardcoded API keys, passwords, secrets in source code, `.env` files not gitignored, database connection strings with passwords, private keys, high-entropy strings, and secrets still exposed in git history, and secret/credential exposure scanning for hardcoded API keys, passwords, secrets in source code, `.env` files not gitignored, database connection strings with passwords, private keys, high-entropy strings, and secrets still exposed in git history
|
|
59
|
+
- `packages/forge`: attestation and verification workflow plus verification history
|
|
60
|
+
|
|
61
|
+
### Data
|
|
62
|
+
|
|
63
|
+
- Postgres is the intended system of record
|
|
64
|
+
- the included schema extract in `docs/schema/ORION-ECOSYSTEM-SCHEMA.thuban.json` contains only the `thuban` tables from Orion
|
|
65
|
+
- packaged JSON artifacts are historical examples, not the final persistence model
|
|
66
|
+
|
|
67
|
+
## Getting started
|
|
68
|
+
|
|
69
|
+
### Prerequisites
|
|
70
|
+
|
|
71
|
+
- Node.js 20+
|
|
72
|
+
- npm 10+
|
|
73
|
+
- Postgres 15+ for future API work
|
|
74
|
+
|
|
75
|
+
### Install
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm install
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Run the placeholder apps
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm run dev:api
|
|
85
|
+
npm run dev:web
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Explore the extracted code
|
|
89
|
+
|
|
90
|
+
- scanner entrypoint: `packages/scanner/index.js`
|
|
91
|
+
- secret scan utility: `quickSecretScan([...files], { rootPath })` or `new SecretScanner({ rootPath }).scanAll()` with output including file path, line number, secret type, severity, and fix recommendation
|
|
92
|
+
- forge verifier: `packages/forge/forge-verifier.js`
|
|
93
|
+
- product strategy: `docs/strategy/THUBAN-PRODUCT-STRATEGY.md`
|
|
94
|
+
- architecture notes: `ARCHITECTURE.md`
|
|
95
|
+
|
|
96
|
+
## Thuban Pro recurring scans
|
|
97
|
+
|
|
98
|
+
Thuban Pro adds scheduled recurring scans for local repositories with change detection, local history, and notification stubs.
|
|
99
|
+
|
|
100
|
+
### What it does
|
|
101
|
+
|
|
102
|
+
- stores monitor configuration per repo in `~/.thuban/monitor/config.json`
|
|
103
|
+
- runs the existing scanner pipeline on a schedule
|
|
104
|
+
- saves each run as JSON history in `~/.thuban/monitor/runs/<repo-id>/`
|
|
105
|
+
- compares each run to the previous run to surface:
|
|
106
|
+
- new issues
|
|
107
|
+
- resolved issues
|
|
108
|
+
- issue-count trend
|
|
109
|
+
- hallucination / secret / tech-debt metric deltas
|
|
110
|
+
- writes notification records to `~/.thuban/monitor/notifications.json`
|
|
111
|
+
- gates monitor/history/trend commands to Pro and above
|
|
112
|
+
|
|
113
|
+
### Commands
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx thuban monitor . --once
|
|
117
|
+
npx thuban monitor . --frequency daily
|
|
118
|
+
npx thuban monitor . --frequency weekly
|
|
119
|
+
npx thuban monitor . --frequency custom --interval-ms 3600000
|
|
120
|
+
npx thuban history .
|
|
121
|
+
npx thuban trend .
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Notification channels
|
|
125
|
+
|
|
126
|
+
Current implementation supports:
|
|
127
|
+
|
|
128
|
+
- `inbox` — local notification inbox persisted to disk
|
|
129
|
+
- `console` — console alert via the existing alert manager
|
|
130
|
+
- `email` — stubbed for future delivery integration
|
|
131
|
+
- `webhook` — stubbed for future delivery integration
|
|
132
|
+
|
|
133
|
+
Example:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npx thuban monitor . --once --notify inbox,console
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### How scheduling works
|
|
140
|
+
|
|
141
|
+
- `daily` = every 24 hours
|
|
142
|
+
- `weekly` = every 7 days
|
|
143
|
+
- `custom` = any interval via `--interval-ms`
|
|
144
|
+
- `npx thuban monitor .` starts a foreground daemon-like process until stopped
|
|
145
|
+
- `npx thuban monitor . --once` performs one scheduled-style run immediately and stores history
|
|
146
|
+
|
|
147
|
+
### Diff detection
|
|
148
|
+
|
|
149
|
+
Each issue is fingerprinted from file, category, id, line, and message. Thuban compares the latest run against the previous run and records:
|
|
150
|
+
|
|
151
|
+
- `added`: issues not seen in the previous run
|
|
152
|
+
- `resolved`: issues that disappeared
|
|
153
|
+
- `metricsDelta`: changes in issue count, hallucinations, secrets, and tech debt metrics
|
|
154
|
+
|
|
155
|
+
This makes recurring scans useful for “what changed since yesterday?” rather than just “scan again.”
|
|
156
|
+
|
|
157
|
+
## Website deployment
|
|
158
|
+
|
|
159
|
+
The public site at `https://thuban.dev` is deployed from the repository root `docs/` folder via GitHub Pages.
|
|
160
|
+
|
|
161
|
+
- workflow: `.github/workflows/deploy-website.yml`
|
|
162
|
+
- trigger: pushes to `main` that change `docs/**`, or manual `workflow_dispatch`
|
|
163
|
+
- deploy artifact: the `docs/` directory uploaded directly to GitHub Pages
|
|
164
|
+
- custom domain: `docs/CNAME`
|
|
165
|
+
|
|
166
|
+
Important deployment notes:
|
|
167
|
+
|
|
168
|
+
- `apps/web/` is a placeholder Next.js app and is not part of the live GitHub Pages deployment
|
|
169
|
+
- there is currently no build/export pipeline from `apps/web/` into `docs/`
|
|
170
|
+
- updating `apps/web/` alone will not change `thuban.dev`
|
|
171
|
+
- to update the live site, edit the static files in `docs/` or add a future export step that writes static output into `docs/`
|
|
172
|
+
|
|
173
|
+
Current practical workflow:
|
|
174
|
+
|
|
175
|
+
1. make website content changes in `docs/`
|
|
176
|
+
2. commit and push to `main`
|
|
177
|
+
3. GitHub Actions runs `Deploy Website to GitHub Pages`
|
|
178
|
+
4. GitHub Pages publishes the uploaded `docs/` artifact to `https://thuban.dev`
|
|
179
|
+
|
|
180
|
+
## Planned next steps
|
|
181
|
+
|
|
182
|
+
1. implement GitHub App installation and webhook ingestion
|
|
183
|
+
2. persist repos, analyses, issues, and fixes in Postgres
|
|
184
|
+
3. convert Sentinel and Forge flows into API-driven services
|
|
185
|
+
4. connect PR check-runs and release attestation exports
|
|
186
|
+
5. build the dashboard for audit runs, verdicts, and trust history
|
|
187
|
+
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const path=require("path"),fs=require("fs"),os=require("os"),CodeScanner=require("./packages/scanner/code-scanner.js"),DependencyGraph=require("./packages/scanner/dependency-graph.js"),CIIntegration=require("./packages/crucible/ci-integration.js"),BadgeGenerator=require("./packages/crucible/badge-generator.js"),Leaderboard=require("./packages/crucible/leaderboard.js"),Crucible=require("./packages/crucible/index.js"),DriftDetector=require("./packages/scanner/drift-detector.js"),WidgetGenerator=require("./packages/scanner/widget-generator.js"),AlertManager=require("./packages/scanner/alert-manager.js"),TechDebtAnalyzer=require("./packages/scanner/tech-debt-analyzer.js"),HallucinationDetector=require("./packages/scanner/hallucination-detector.js"),HtmlReportGenerator=require("./packages/scanner/html-report.js"),FileWatcher=require("./packages/scanner/file-watcher.js"),LicenseManager=require("./packages/scanner/license-manager.js"),PreCommitGate=require("./packages/scanner/pre-commit-gate.js"),TechDebtCostCalculator=require("./packages/scanner/tech-debt-cost.js"),GhostCodeDetector=require("./packages/scanner/ghost-code-detector.js"),AIConfidenceScorer=require("./packages/scanner/ai-confidence-scorer.js"),CopyPasteDriftDetector=require("./packages/scanner/copy-paste-detector.js"),CodebasePassport=require("./packages/scanner/codebase-passport.js"),ExecutiveReport=require("./packages/scanner/executive-report.js"),BaselineManager=require("./packages/scanner/baseline-manager.js"),MonitorStore=require("./packages/scanner/monitor-store.js"),{MonitorService:MonitorService,resolveIntervalMs:resolveIntervalMs}=require("./packages/scanner/monitor-service.js"),{collectFiles:collectFiles}=require("./packages/scanner/file-collector.js");function parseFlag(e,o,n){const c=e.find(e=>e.startsWith(`--${o}=`));return c?c.split("=").slice(1).join("="):!!e.includes(`--${o}`)||n}function parseIntFlag(e,o,n){const c=parseFlag(e,o,null);if(null===c)return n;const l=parseInt(c,10);return isNaN(l)?n:l}const COLORS={reset:"[0m",bold:"[1m",red:"[31m",green:"[32m",yellow:"[33m",blue:"[34m",cyan:"[36m",gray:"[90m",white:"[37m",bgRed:"[41m",bgGreen:"[42m",bgYellow:"[43m"};function c(e,o){return`${COLORS[e]}${o}${COLORS.reset}`}function banner(){console.log(""),console.log(c("cyan"," ╔══════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold"," THUBAN Code Health Engine ")+c("cyan","║")),console.log(c("cyan"," ║")+c("gray"," v0.4.0 · Public Beta · thuban.dev ")+c("cyan","║")),console.log(c("cyan"," ╚══════════════════════════════════════╝")),console.log("")}function printHelp(){banner();const e=(new LicenseManager).getStatus(),o=JSON.parse(fs.readFileSync(path.join(__dirname,"package.json"),"utf-8"));console.log(c("gray",` v${o.version} · ${e.tierName} tier`)+(e.licensed?c("green"," ✓"):"")+c("gray"," · https://thuban.dev")),console.log(""),console.log(c("bold"," QUICK START")),console.log(""),console.log(c("gray"," Run these in order to see what Thuban does:")),console.log(""),console.log(` ${c("cyan","npx thuban scan .")} Scan your project`),console.log(` ${c("cyan","npx thuban fix .")} Preview what can be fixed`),console.log(` ${c("cyan","npx thuban fix . --fix")} Apply all safe fixes`),console.log(` ${c("cyan","npx thuban dashboard .")} Open visual HTML report`),console.log(""),console.log(c("bold"," SCAN & DETECT")),console.log(""),console.log(` ${c("cyan","scan")} [path|url] Full health scan — score, grade, all issues`),console.log(` ${c("cyan","compare")} [a] [b] Compare two codebases side by side`),console.log(` ${c("cyan","hallucinate")} [path] Find phantom APIs and invented imports`),console.log(` ${c("cyan","ghosts")} [path] Dead functions nobody calls`),console.log(` ${c("cyan","ai-score")} [path] Probability each function is AI-generated`),console.log(` ${c("cyan","clones")} [path] Copy-pasted code that has drifted apart`),console.log(` ${c("cyan","drift")} [path] Files that changed since Mother Code was set`),console.log(` ${c("cyan","deps")} [path] Dependency map — circular, orphan, critical`),console.log(` ${c("cyan","diff")} [path] Scan only git-changed files`),console.log(` ${c("cyan","debt")} [path] Detailed tech debt breakdown`),console.log(` ${c("cyan","cost")} [path] Tech debt translated to £ and hours`),console.log(""),console.log(c("bold"," FIX & PROTECT")),console.log(""),console.log(` ${c("cyan","fix")} [path] Preview fixable issues ${c("gray","(safe, no changes)")}`),console.log(` ${c("cyan","fix")} [path] ${c("gray","--fix")} Apply all safe fixes`),console.log(` ${c("cyan","fix")} [path] ${c("gray","--fix --commit")} Each fix = 1 git commit ${c("gray","(revert any)")}`),console.log(` ${c("cyan","inject")} [path] Add Mother Code DNA to every file`),console.log(` ${c("cyan","gate")} Install pre-commit hook ${c("gray","(blocks hallucinations)")}`),console.log(` ${c("cyan","watch")} [path] Live sentinel — scans files as you save`),console.log(` ${c("cyan","monitor")} [path] Recurring scans with saved history and alerts ${c("gray","(Pro)")}`),console.log(` ${c("cyan","history")} [path] View recurring scan history for a repo ${c("gray","(Pro)")}`),console.log(` ${c("cyan","trend")} [path] Show issue trends across recurring scans ${c("gray","(Pro)")}`),console.log(` ${c("cyan","baseline")} [path] Snapshot issues so future scans show only NEW ones`),console.log(""),console.log(c("bold"," REPORTS")),console.log(""),console.log(` ${c("cyan","dashboard")} [path] Interactive HTML report ${c("gray","(share with your team)")}`),console.log(` ${c("cyan","executive")} [path] CTO-ready report ${c("gray","(print to PDF from browser)")}`),console.log(` ${c("cyan","report")} [path] Combined scan + deps + drift summary`),console.log(` ${c("cyan","passport")} [path] Codebase identity card ${c("gray","(for new team members)")}`),console.log(""),console.log(c("bold"," LICENSE")),console.log(""),console.log(` ${c("cyan","activate")} <key> Activate a license key`),console.log(` ${c("cyan","status")} Show license, usage, and features`),console.log(` ${c("cyan","upgrade")} Open pricing page`),console.log(""),console.log(c("bold"," OPTIONS")),console.log(""),console.log(` ${c("gray","--fix")} Apply changes ${c("gray","(default is dry-run preview)")}`),console.log(` ${c("gray","--commit")} Auto-commit each fix for easy rollback`),console.log(` ${c("gray","--unsafe")} Include fixes that change runtime behaviour`),console.log(` ${c("gray","--json")} Machine-readable JSON output`),console.log(` ${c("gray","--baseline")} Only show NEW issues vs saved baseline`),console.log(` ${c("gray","--verbose")} Show detailed output`),console.log(` ${c("gray","--ignore <pat>")} Skip files matching pattern`),console.log(` ${c("gray","--max-issues <n>")} Limit displayed issues ${c("gray","(default: 50)")}`),console.log(""),console.log(c("bold"," EXAMPLES")),console.log(""),console.log(c("gray"," # Scan the current project")),console.log(` ${c("white","npx thuban scan .")}`),console.log(""),console.log(c("gray"," # Find and fix all AI hallucinations")),console.log(` ${c("white","npx thuban hallucinate .")}`),console.log(` ${c("white","npx thuban fix . --fix")}`),console.log(""),console.log(c("gray"," # Generate a report for your CTO")),console.log(` ${c("white","npx thuban executive .")}`),console.log(""),console.log(c("gray"," # Block hallucinated code on every commit")),console.log(` ${c("white","npx thuban gate --fix")}`),console.log(""),console.log(c("gray"," # Scan a specific folder, ignore tests")),console.log(` ${c("white",'npx thuban scan ./src --ignore "**/*.test.js"')}`),console.log(""),console.log(c("gray"," Report a bug or request a feature:")),console.log(` ${c("cyan","https://github.com/SilverwingsBenefitsGit/thuban/issues")}`),console.log("")}function parseArgs(e){const o={command:null,targetPath:process.cwd(),json:!1,fix:!1,dryRun:!1,safe:!0,gitCommit:!1,verbose:!1,ignore:[],maxIssues:50,licenseKey:null,baseline:!1,baselineCreate:!1,frequency:"daily",intervalMs:null,notify:"inbox",once:!1},n=["activate","status","upgrade","help","version"];let c=0;for(;c<e.length;){const l=e[c];"--json"===l?o.json=!0:"--fix"===l?o.fix=!0:"--dry-run"===l||"--dryrun"===l?o.dryRun=!0:"--unsafe"===l?o.safe=!1:"--git-commit"===l||"--commit"===l?o.gitCommit=!0:"--baseline"===l?o.baseline=!0:"--baseline-create"===l?o.baselineCreate=!0:"--frequency"===l&&e[c+1]?o.frequency=e[++c]:"--interval-ms"===l&&e[c+1]?o.intervalMs=parseInt(e[++c],10):"--notify"===l&&e[c+1]?o.notify=e[++c]:"--once"===l?o.once=!0:"--verbose"===l?o.verbose=!0:"--ignore"===l&&e[c+1]?o.ignore.push(e[++c]):"--max-issues"===l&&e[c+1]?o.maxIssues=parseInt(e[++c],10):"--help"===l||"-h"===l?o.command="help":"--version"===l||"-v"===l?o.command="version":o.command?"activate"!==o.command||o.licenseKey?n.includes(o.command)||(l.match(/^(https?:\/\/|git@)/)?o.targetPath=l:o.targetPath=path.resolve(l)):o.licenseKey=l:o.command=l,c++}return o}function summarizeRemainingFiles(e,o,n){const c=new Set(e),l=o.filter(e=>!c.has(e)),s=new Map;for(const e of l){const o=path.relative(n,e).split(path.sep).filter(Boolean),c=o.length>1?o[0]:"(root)";s.set(c,(s.get(c)||0)+1)}const t=Array.from(s.entries()).sort((e,o)=>o[1]-e[1]||e[0].localeCompare(o[0])).slice(0,3).map(([e,o])=>({directory:e,count:o}));return{remainingFiles:l,remainingCount:l.length,topDirectories:t,previewFiles:l.slice(0,5).map(e=>path.relative(n,e))}}function requireProFeature(e){const o=new LicenseManager;if(!o.canUseProFeature(e).allowed){const o="https://thuban.dev/pricing";console.log(""),console.log(c("yellow"," ╔══════════════════════════════════════════════════════════════╗")),console.log(c("yellow"," ║")+c("bold"," PRO FEATURE REQUIRED ")+c("yellow","║")),console.log(c("yellow"," ╠══════════════════════════════════════════════════════════════╣")),console.log(c("yellow"," ║")+` ${e} is available on Thuban Pro.`.padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" Free Thuban gives you a one-off checkup. Pro gives you".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" a pair of eyes on your codebase all day every day with".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" recurring scans, saved history, trends, and alerts.".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("yellow","║")),console.log(c("yellow"," ║")+` Upgrade now: ${o}`.padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" CLI shortcut: thuban upgrade".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ╚══════════════════════════════════════════════════════════════╝")),console.log(""),process.exit(0)}return o}function resolveRepoConfigOrExit(e,o){const n=e.getRepo(o);return n||(console.log(""),console.log(c("yellow"," No monitor configuration found for this repo.")),console.log(c("gray"," Run `thuban monitor <path> --once` or `thuban monitor <path>` first.")),console.log(""),process.exit(0)),n}function printFileCapUpgradePrompt({scannedCount:e,totalCount:o,remainingSummary:n,upgradeUrl:l}){const s=n.topDirectories.length;if(console.log(c("yellow"," ╔══════════════════════════════════════════════════════════════╗")),console.log(c("yellow"," ║")+c("bold"," FREE TIER LIMIT REACHED ")+c("yellow","║")),console.log(c("yellow"," ╠══════════════════════════════════════════════════════════════╣")),console.log(c("yellow"," ║")+` You have scanned ${e} of ${o} files.`.padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" Upgrade to Thuban Pro for continuous monitoring —".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" a pair of eyes on your codebase, all day, every day.".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" Your always-on guardian with unlimited scans.".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+` ${n.remainingCount} more files remaining including ${s}`.padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+` critical director${1===s?"y":"ies"}.`.padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("yellow","║")),console.log(c("yellow"," ║")+` Upgrade now: ${l}`.padEnd(62)+c("yellow","║")),console.log(c("yellow"," ║")+" CLI shortcut: thuban upgrade".padEnd(62)+c("yellow","║")),console.log(c("yellow"," ╚══════════════════════════════════════════════════════════════╝")),console.log(""),n.topDirectories.length>0){console.log(c("bold"," Remaining scan preview"));for(const e of n.topDirectories)console.log(` ${c("yellow","•")} ${c("cyan",e.directory)} ${c("gray",`(${e.count} files)`)}`);if(n.previewFiles.length>0){console.log(""),console.log(c("gray"," Next files that would be scanned:"));for(const e of n.previewFiles)console.log(` ${c("gray","·")} ${e}`)}console.log("")}}async function cmdScan(e){const o=Date.now(),n=/^(https?:\/\/|git@)/.test(e.targetPath);let l=n?e.targetPath:path.resolve(e.targetPath),s=null;if(n){e.json||(console.log(""),console.log(c("cyan"," Cloning repository...")),console.log(c("gray",` ${e.targetPath}`)));const o=path.join(os.tmpdir(),"thuban-scan-"+Date.now()),{execFileSync:n}=require("child_process");try{n("git",["clone","--depth","1",e.targetPath,o],{stdio:"pipe",timeout:6e4}),l=o,s=o,e.json||(console.log(c("cyan"," Cloned successfully")),console.log(""))}catch(e){console.error(c("red",` Failed to clone repository: ${e.message}`)),console.error(c("gray"," Check the URL is correct and the repo is accessible")),process.exit(1)}}const t=new LicenseManager,a=t.getTierConfig(),r=t.canScan(),i="https://thuban.dev/pricing";r.allowed||e.json||(console.log(""),console.log(c("red"," ╔══════════════════════════════════════════════════╗")),console.log(c("red"," ║")+c("bold"," Monthly scan limit reached ")+c("red","║")),console.log(c("red"," ╚══════════════════════════════════════════════════╝")),console.log(""),console.log(` You've used ${c("bold",r.used+"/"+r.limit)} free scans this month.`),console.log(` Resets on ${c("cyan",r.resetsOn)}.`),console.log(""),console.log(` ${c("cyan","Upgrade to Pro")} for unlimited scans, full reports, auto-fix, and an always-on pair of eyes via thuban monitor:`),console.log(` ${c("bold",i)}`),console.log(""),console.log(` Or activate a key: ${c("cyan","thuban activate <your-key>")}`),console.log(""),process.exit(0)),e.json||(banner(),0===t.usage.totalScans&&(console.log(c("cyan"," ┌──────────────────────────────────────────────────────┐")),console.log(c("cyan"," │")+c("bold"," Welcome to Thuban! ")+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("gray","Thuban scans your codebase for AI hallucinations,")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("gray","dead code, tech debt, and architecture drift.")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("gray","After this scan, try:")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban fix .")+" "+c("gray","Preview fixes")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban dashboard .")+" "+c("gray","Visual report")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban --help")+" "+c("gray","All commands")+" "+c("cyan","│")),console.log(c("cyan"," └──────────────────────────────────────────────────────┘")),console.log("")),console.log(c("bold"," SCANNING: ")+c("cyan",l)),console.log(""));const g=collectFiles(l,e.ignore),d=g.length,h=a.maxFiles<1/0?g.slice(0,a.maxFiles):g,u=d>a.maxFiles,y=u?summarizeRemainingFiles(h,g,l):null;!e.json&&u?(console.log(c("yellow",` Free tier: scanning ${a.maxFiles} of ${d} files`)),console.log(c("gray"," Partial results below. Upgrade to scan your entire codebase.")),console.log("")):e.json||(console.log(c("gray",` Found ${h.length} files to scan...`)),console.log(""));const p=new CodeScanner({rootPath:l,ignorePatterns:["node_modules/**",".git/**","dist/**",...e.ignore]}),f=new HallucinationDetector({rootPath:l}),[m,b]=await Promise.all([p.scanFiles(h),f.scan(h)]),$=Date.now()-o;t.recordScan();const w=[];for(const e of m.issues||[])w.push({file:path.relative(l,e.file),...e});for(const e of b.phantomAPIs)w.push({file:e.file,line:e.line,severity:"critical",category:"hallucination",id:"HALL_API",message:`${e.name} — this API does not exist`,suggestion:e.suggestion,crash:!0});for(const e of b.phantomImports)w.push({file:e.file,line:e.line,severity:"critical",category:"hallucination",id:"HALL_IMPORT",message:`${e.module} — ${e.reason}`,crash:!0});for(const e of b.deprecatedAPIs)w.push({file:e.file,line:e.line,severity:"high",category:"deprecated",id:"DEPR_API",message:`${e.name} — deprecated since ${e.since}`,suggestion:e.suggestion});for(const e of b.aiSmells)w.push({file:e.file,line:e.line,severity:"warning",category:"ai_smell",id:e.id,message:e.message});if(e.json)return void console.log(JSON.stringify({files:d,filesScanned:h.length,elapsed_ms:$,tier:t.getTier(),issues:a.showFullDetails?w:w.slice(0,a.teaserIssues),totalIssues:w.length,gated:!a.showFullDetails,fileLimitReached:u,upgradeUrl:u?i:null,remainingFiles:y?y.remainingCount:0,remainingDirectories:y?y.topDirectories:[],remainingPreview:y?y.previewFiles:[]},null,2));const v={critical:0,high:1,error:2,medium:3,warning:4,low:5,info:6};w.sort((e,o)=>(v[e.severity]||99)-(v[o.severity]||99));const S=w.filter(e=>"critical"===e.severity),C=w.filter(e=>"high"===e.severity||"error"===e.severity),x=w.filter(e=>"medium"===e.severity||"warning"===e.severity),E=w.filter(e=>"low"===e.severity||"info"===e.severity),P=w.filter(e=>"hallucination"===e.category),I=w.filter(e=>"deprecated"===e.category),A=w.filter(e=>"ai_smell"===e.category),D=x.filter(e=>"ai_smell"!==e.category),N=Math.max(0,100-15*S.length-5*C.length-2*D.length-.5*A.length-.25*E.length),T=N>=90?"A":N>=80?"B":N>=70?"C+":N>=60?"C":N>=50?"D+":N>=40?"D":"F",R=N>=80?"green":N>=60?"yellow":"red",F=w.filter(e=>!1!==e.fixable).length;if(console.log(c("cyan"," ╔══════════════════════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold"," THUBAN SCAN RESULTS ")+c("cyan","║")),console.log(c("cyan"," ║")+c("gray"," v0.4.0 · Public Beta ")+c("cyan","║")),console.log(c("cyan"," ╠══════════════════════════════════════════════════════╣")),console.log(c("cyan"," ║")+` Files scanned: ${c("bold",String(h.length).padEnd(6))}`+(u?c("yellow",` of ${d}`):" ")+c("cyan"," ║")),console.log(c("cyan"," ║")+` Health score: ${c(R,(T+" ("+Math.round(N)+"/100)").padEnd(20))}`+c("cyan"," ║")),console.log(c("cyan"," ║")+` Issues found: ${c(w.length>0?"yellow":"green",String(w.length).padEnd(20))}`+c("cyan"," ║")),console.log(c("cyan"," ║")+` Auto-fixable: ${c("green",String(F).padEnd(20))}`+c("cyan"," ║")),console.log(c("cyan"," ║")+` Scan time: ${c("gray",($+"ms").padEnd(20))}`+c("cyan"," ║")),console.log(c("cyan"," ╚══════════════════════════════════════════════════════╝")),console.log(""),h.some(e=>!(e.endsWith(".js")||e.endsWith(".ts")||e.endsWith(".jsx")||e.endsWith(".tsx")||e.endsWith(".mjs")))){const e=[...new Set(h.filter(e=>!/\.(js|ts|jsx|tsx|mjs)$/.test(e)).map(e=>path.extname(e)).filter(Boolean))];console.log(c("gray"," Note: Score includes Security + Hallucination + Code Quality categories.")),console.log(c("gray",` Architecture + Dependency analysis evaluated for JS/TS only. Detected non-JS: ${e.join(", ")}`)),console.log("")}if(P.length>0){console.log(c("bgRed"," CRITICAL ")+c("red",c("bold",` ${P.length} Hallucinated API${P.length>1?"s":""}`))),console.log(c("gray"," These imports or method calls do not exist. Your code WILL crash when it hits them.")),console.log("");const e=a.showFullDetails?P.length:Math.min(a.teaserIssues,P.length);for(let o=0;o<e;o++){const e=P[o],n=e.line?`:${e.line}`:"";console.log(` ${c("cyan",e.file+n)}`);try{const o=path.resolve(l,e.file),n=fs.readFileSync(o,"utf-8").split("\n");e.line&&n[e.line-1]&&console.log(` ${c("red",n[e.line-1].trim())}`)}catch(e){}console.log(` ${c("yellow","^^^")} ${e.message}`),e.suggestion&&console.log(` ${c("green","Fix:")} ${e.suggestion}`),console.log("")}P.length>e&&(console.log(c("gray",` ... ${P.length-e} more hallucinations hidden`)),console.log(c("cyan"," Upgrade to Pro to see all: ")+c("bold","thuban upgrade")),console.log(""))}if(I.length>0){console.log(c("red",c("bold",` DEPRECATED: ${I.length} API${I.length>1?"s":""} that will break on upgrade`))),console.log(c("gray"," These work NOW but will stop working when you upgrade Node.js or your dependencies.")),console.log(c("gray"," Fix: ")+c("cyan","npx thuban fix . --fix --unsafe")),console.log("");const e=a.showFullDetails?I.length:Math.min(a.teaserIssues,I.length);for(let o=0;o<e;o++){const e=I[o],n=e.line?`:${e.line}`:"";console.log(` ${c("cyan",e.file+n)}`),console.log(` ${c("yellow",e.message)}`),e.suggestion&&console.log(` ${c("green","→")} ${e.suggestion}`),console.log("")}I.length>e&&(console.log(c("gray",` ... ${I.length-e} more hidden`)),console.log(""))}const O=w.filter(e=>"security"===e.category),j=w.filter(e=>"quality"===e.category||"performance"===e.category||"ai"===e.category||"ai_smell"===e.category);if(O.length>0){console.log(c("red",c("bold",` SECURITY: ${O.length} issue${O.length>1?"s":""}`)));const e=a.showFullDetails?Math.min(O.length,10):Math.min(a.teaserIssues,O.length);for(let o=0;o<e;o++){const e=O[o],n=e.line?`:${e.line}`:"";console.log(` ${c("red","✗")} ${c("cyan",e.file+n)} ${c("gray",e.message)}`)}O.length>e&&console.log(c("gray",` ... ${O.length-e} more hidden`)),console.log("")}if(j.length>0){const e={};for(const o of j){const n=(o.message||o.type||"other").replace(/\s*—.*$/,"").trim();e[n]||(e[n]=[]),e[n].push(o)}const o=Object.entries(e).sort((e,o)=>o[1].length-e[1].length);console.log(c("yellow",c("bold",` CODE QUALITY: ${j.length} issue${j.length>1?"s":""}`))),console.log(c("gray"," Patterns that reduce code quality, maintainability, or production readiness.")),console.log("");const n=a.showFullDetails?o.length:Math.min(3,o.length);for(let e=0;e<n;e++){const[n,l]=o[e],s="high"===l[0].severity||"error"===l[0].severity?"red":"yellow";if(console.log(` ${c(s,"!")} ${c("bold",String(l.length))} x ${n}`),l[0].file){const e=l[0].line?`:${l[0].line}`:"";console.log(` ${c("gray","e.g.")} ${c("cyan",l[0].file+e)}`)}}o.length>n&&console.log(c("gray",` ... ${o.length-n} more issue types`)),console.log("");const l=j.filter(e=>!1!==e.fixable).length;l>0&&(console.log(c("gray",` ${l} of these can be auto-fixed: `)+c("cyan","npx thuban fix . --fix --unsafe")),console.log(""))}if(console.log(c("bold"," ┌──────────────────────────────────────────────────────┐")),N<60?console.log(c("bold"," │ ")+c("red","YOUR CODEBASE HAS A SERIOUS HEALTH PROBLEM ")+c("bold"," │")):N<80?console.log(c("bold"," │ ")+c("yellow","YOUR CODEBASE NEEDS ATTENTION ")+c("bold"," │")):console.log(c("bold"," │ ")+c("green","YOUR CODEBASE IS IN GOOD SHAPE ")+c("bold"," │")),console.log(c("bold"," │")+` Score: ${c(R,T+" ("+Math.round(N)+"/100)")} `+c("bold","│")),console.log(c("bold"," └──────────────────────────────────────────────────────┘")),console.log(""),S.length>0){console.log(c("red",` ${S.length} function${S.length>1?"s":""} will crash in production.`));const e=S.length<=3?"30 seconds":S.length<=10?"2 minutes":"10 minutes";console.log(c("gray",` Estimated cleanup: ${e} with Thuban auto-fix.`)),console.log(c("gray"," Estimated cost if shipped: your weekend.")),console.log("")}if(a.showFullDetails)w.length>0&&(w.filter(e=>!1!==e.fixable).length,console.log(c("cyan"," ┌──────────────────────────────────────────────────────┐")),console.log(c("cyan"," │")+c("bold"," WHAT TO DO NEXT ")+c("cyan","│")),console.log(c("cyan"," ├──────────────────────────────────────────────────────┤")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("bold","1. See what would be fixed (safe preview):")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban fix . ")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("bold","2. Apply all safe fixes:")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban fix . --fix")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("bold","3. Apply fixes with git rollback:")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban fix . --fix --commit")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("gray","Each fix = 1 git commit. Undo any with git revert.")+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("bold","4. Generate visual report (HTML):")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban dashboard .")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("gray","Opens a dashboard you can share with your team.")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("bold","5. Show tech debt cost in £:")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban cost .")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("bold","6. Block bad code on every commit:")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","npx thuban gate")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("gray","Installs a pre-commit hook. Set once, forget.")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("cyan","│")),console.log(c("cyan"," │")+" "+c("gray","All commands: npx thuban --help")+" "+c("cyan","│")),console.log(c("cyan"," └──────────────────────────────────────────────────────┘")),console.log(""));else{const e=w.length-a.teaserIssues;e>0&&(console.log(c("cyan"," ╔══════════════════════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold",` ${e} more issues hidden `)+c("cyan","║")),console.log(c("cyan"," ║")+c("gray"," Upgrade to see every issue, fix them automatically,")+c("cyan","║")),console.log(c("cyan"," ║")+c("gray"," and get the full HTML dashboard report. ")+c("cyan","║")),console.log(c("cyan"," ╠══════════════════════════════════════════════════════╣")),console.log(c("cyan"," ║")+` ${c("bold","thuban upgrade")} Open pricing page `+c("cyan","║")),console.log(c("cyan"," ║")+` ${c("bold","thuban activate")} <key> Activate a license key `+c("cyan","║")),console.log(c("cyan"," ╚══════════════════════════════════════════════════════╝")),console.log(""));const o=t.canScan(),n=o.remaining;console.log(c("gray",` Free scans remaining this month: ${n}/${o.limit}`)),console.log("")}u&&printFileCapUpgradePrompt({scannedCount:h.length,totalCount:d,remainingSummary:y,upgradeUrl:i}),w.length>0&&!u&&(console.log(c("gray"," ─────────────────────────────────────────────────────")),console.log(c("gray"," Thuban runs 100% on your machine. No data leaves.")),console.log(c("gray"," No cloud costs. As your codebase grows, Thuban grows with it.")),console.log(""),console.log(c("gray"," Keep your codebase healthy continuously:")),console.log(c("gray"," ")+c("cyan","npx thuban gate --fix")+c("gray"," Block bad code on every commit")),console.log(c("gray"," ")+c("cyan","npx thuban watch .")+c("gray"," Scan files as you save them")),console.log(c("gray"," ")+c("cyan","npx thuban baseline .")+c("gray"," Only alert on NEW issues")),console.log(""))}async function cmdDeps(e){const o=Date.now(),n=path.resolve(e.targetPath);e.json||(banner(),console.log(c("bold"," MAPPING DEPENDENCIES: ")+c("cyan",n)),console.log(""));const l=collectFiles(n,e.ignore),s=new DependencyGraph({rootPath:n});await s.build(l);const t=Date.now()-o,a=s.getModuleSummary(),r=s.getMostCriticalFiles(10),i=s.getOrphanFiles(),g=s.circularDeps||[];if(e.json)console.log(JSON.stringify({elapsed_ms:t,summary:a,critical:r,orphans:i,circular:g,graph:s.toJSON()},null,2));else{if(console.log(c("gray",` Analysed ${l.length} files in ${t}ms`)),console.log(""),console.log(c("bold"," DEPENDENCY SUMMARY")),console.log(` Files: ${a.totalFiles||l.length}`),console.log(` Import links: ${a.totalImports||0}`),console.log(` Circular deps: ${g.length>0?c("red",g.length):c("green","0")}`),console.log(` Orphan files: ${i.length>0?c("yellow",i.length):c("green","0")}`),console.log(""),r.length>0){console.log(c("bold"," MOST CRITICAL FILES")+c("gray"," (most dependents)"));for(const e of r){const o="string"==typeof e?e:e.file||e.path||String(e),l=path.relative(n,o),s="object"==typeof e&&(e.dependents||e.score||e.count)||"?";console.log(` ${c("cyan",l)} ${c("gray","→ "+s+" dependents")}`)}console.log("")}if(g.length>0){console.log(c("red"," CIRCULAR DEPENDENCIES"));for(const e of g.slice(0,5)){const o=Array.isArray(e)?e.map(e=>path.relative(n,e)).join(" → "):String(e);console.log(` ${c("yellow","⟲")} ${o}`)}console.log("")}if(i.length>0){console.log(c("yellow"," ORPHAN FILES")+c("gray"," (no imports, no exports consumed)"));for(const e of i.slice(0,10)){const o="string"==typeof e?e:e.file||e.path||String(e);console.log(` ${c("gray","○")} ${path.relative(n,o)}`)}i.length>10&&console.log(c("gray",` ... and ${i.length-10} more`)),console.log("")}}}async function cmdMonitor(e){requireProFeature("Scheduled monitoring");const o=path.resolve(e.targetPath),n=new MonitorService,l=n.configureRepo({repoPath:o,frequency:e.frequency,intervalMs:resolveIntervalMs(e.frequency,e.intervalMs),notification:{channels:String(e.notify||"inbox").split(",").map(e=>e.trim()).filter(Boolean)}});if(e.once){const o=await n.runRepoScan(l);return e.json?void console.log(JSON.stringify(o.run,null,2)):(console.log(""),console.log(c("bold"," THUBAN MONITOR RUN")),console.log(` Repo: ${l.repoPath}`),console.log(` New issues: ${o.diff.added.length}`),console.log(` Resolved issues: ${o.diff.resolved.length}`),console.log(` History saved: ${o.runPath}`),void console.log(""))}console.log(""),console.log(c("bold"," THUBAN MONITOR ACTIVE")),console.log(` Repo: ${l.repoPath}`),console.log(` Frequency: ${l.frequency} (${l.intervalMs}ms)`),console.log(` Notifications: ${(l.notification.channels||[]).join(", ")}`),console.log(c("gray"," Press Ctrl+C to stop.")),console.log(""),n.start(l),process.on("SIGINT",()=>{n.stopAll(),process.exit(0)})}async function cmdHistory(e){requireProFeature("Scan history");const o=new MonitorStore,n=resolveRepoConfigOrExit(o,e.targetPath),l=o.listRuns(n.repoId);if(e.json)return void console.log(JSON.stringify({repo:n,runs:l},null,2));console.log(""),console.log(c("bold"," THUBAN HISTORY")),console.log(` Repo: ${n.repoPath}`),console.log(` Runs: ${l.length}`),console.log("");for(const e of l.slice(-10).reverse())console.log(` ${c("cyan",e.timestamp)} issues=${e.metrics.issueCount} new=${e.diff?.added?.length||0} resolved=${e.diff?.resolved?.length||0}`);const s=o.getNotifications(10).filter(e=>e.repoId===n.repoId);if(s.length){console.log(""),console.log(c("bold"," RECENT ALERTS"));for(const e of s)console.log(` ${c("yellow",e.timestamp)} ${e.summary}`)}console.log("")}async function cmdTrend(e){requireProFeature("Trend reporting");const o=new MonitorStore,n=resolveRepoConfigOrExit(o,e.targetPath),l=o.listRuns(n.repoId).map(e=>({timestamp:e.timestamp,issueCount:e.metrics.issueCount,hallucinations:e.metrics.hallucinations,secrets:e.metrics.secrets,techDebtScore:e.metrics.techDebtScore,techDebtHours:e.metrics.techDebtHours}));if(e.json)console.log(JSON.stringify({repo:n,trend:l},null,2));else{console.log(""),console.log(c("bold"," THUBAN TREND")),console.log(` Repo: ${n.repoPath}`),console.log("");for(const e of l.slice(-12))console.log(` ${c("cyan",e.timestamp)} issues=${e.issueCount} hallucinations=${e.hallucinations} secrets=${e.secrets} debtScore=${e.techDebtScore??"n/a"} debtHours=${e.techDebtHours??"n/a"}`);console.log("")}}async function cmdDrift(e){const o=Date.now(),n=path.resolve(e.targetPath);e.json||(banner(),console.log(c("bold"," DETECTING DRIFT: ")+c("cyan",n)),console.log(""));const l=collectFiles(n,e.ignore),s=new DriftDetector({rootPath:n}),t=[];let a=0,r=0;for(const e of l)try{const o=await s.analyzeFile(e);o&&o.hasWidget&&(a++,o.drifts&&o.drifts.length>0&&(r++,t.push({file:path.relative(n,e),...o})))}catch(e){}const i=Date.now()-o;if(e.json)return void console.log(JSON.stringify({elapsed_ms:i,total:l.length,annotated:a,drifted:r,results:t},null,2));if(console.log(c("gray",` Checked ${l.length} files in ${i}ms`)),console.log(""),console.log(` Files with Mother Code: ${c("cyan",a)}`),console.log(` Files without: ${c("yellow",l.length-a)}`),console.log(` Files with drift: ${r>0?c("red",r):c("green","0")}`),console.log(""),t.length>0){console.log(c("bold"," DRIFT DETECTED"));for(const e of t.slice(0,20)){console.log(` ${c("yellow","⚠")} ${c("cyan",e.file)}`);for(const o of e.drifts)console.log(` ${c("gray","→")} ${o.type}: ${o.message||o.detail||JSON.stringify(o)}`)}console.log("")}const g=l.length>0?Math.round(a/l.length*100):0,d=g>=80?"green":g>=40?"yellow":"red";console.log(` Mother Code coverage: ${c(d,g+"%")}`),console.log("")}async function cmdInject(e){const o=path.resolve(e.targetPath);e.json||(banner(),console.log(c("bold"," INJECTING MOTHER CODE: ")+c("cyan",o)),console.log(""));const n=collectFiles(o,e.ignore).filter(e=>e.endsWith(".js")||e.endsWith(".ts")||e.endsWith(".jsx")||e.endsWith(".tsx")||e.endsWith(".py")||e.endsWith(".java")||e.endsWith(".cs")||e.endsWith(".go")||e.endsWith(".kt")||e.endsWith(".rs")||e.endsWith(".php")||e.endsWith(".rb")),l=new DependencyGraph({rootPath:o});await l.build(n);const s=new WidgetGenerator({rootPath:o,dependencyGraph:l});let t=0,a=0;const r=[];for(const l of n)try{const n=fs.readFileSync(l,"utf-8");if(n.includes("@purpose")&&n.includes("@module")){a++;continue}const i=await s.generateWidget(l,n);if(!i){a++;continue}const g=i&&i.widgetString?i.widgetString:String(i),d=path.extname(l).toLowerCase();let h;if(h=".py"===d||".rb"===d?g.replace(/^\/\*\*\n/,"").replace(/\s*\*\/\s*$/,"").split("\n").map(e=>e.replace(/^\s*\*\s?/,"# ")).join("\n"):".go"===d||".rs"===d?g.replace(/^\/\*\*\n/,"").replace(/\s*\*\/\s*$/,"").split("\n").map(e=>e.replace(/^\s*\*\s?/,"// ")).join("\n"):g,e.fix){const s=h+"\n\n"+n;fs.writeFileSync(l,s,"utf-8"),t++,e.json||console.log(` ${c("green","✓")} ${path.relative(o,l)}`)}else r.push({file:path.relative(o,l),widget:h}),t++}catch(e){a++}if(e.json)console.log(JSON.stringify({injected:t,skipped:a,dryRun:!e.fix,previews:r},null,2));else{if(console.log(""),e.fix)console.log(c("green",` ✓ Injected Mother Code into ${t} files`));else if(console.log(c("yellow",` DRY RUN — ${t} files would be annotated. Use --fix to apply.`)),e.verbose&&r.length>0){console.log("");for(const e of r.slice(0,5))console.log(` ${c("cyan",e.file)}:`),console.log(c("gray",e.widget.split("\n").map(e=>" "+e).join("\n"))),console.log("")}console.log(` ${c("gray",`Skipped: ${a} (already annotated or unsupported)`)}`),console.log("")}}async function cmdReport(e){const o=Date.now(),n=path.resolve(e.targetPath);e.json||(banner(),console.log(c("bold"," FULL REPORT: ")+c("cyan",n)),console.log(""));const l=collectFiles(n,e.ignore),s=new CodeScanner({rootPath:n}),t=new DependencyGraph({rootPath:n}),a=new DriftDetector({rootPath:n}),[r]=await Promise.all([s.scanFiles(l),t.build(l)]);let i=0,g=0;for(const e of l)try{const o=await a.analyzeFile(e);o&&o.hasWidget&&(g++,o.drifts&&o.drifts.length>0&&i++)}catch(e){}const d=Date.now()-o;let h=0,u=0,y=0;for(const e of r.issues||[])h++,"critical"===e.severity&&u++,"high"===e.severity&&y++;const p=t.getOrphanFiles(),f=t.circularDeps||[],m=l.length>0?Math.round(g/l.length*100):0,b=Math.max(0,Math.round(100-15*u-5*y-10*f.length-1*p.length-.1*(100-m)-3*i));if(e.json)return void console.log(JSON.stringify({elapsed_ms:d,files:l.length,health_score:b,issues:{total:h,critical:u,high:y},dependencies:{circular:f.length,orphans:p.length},mother_code:{annotated:g,coverage_pct:m,drifted:i}},null,2));const $=b>=80?"green":b>=60?"yellow":"red";console.log(c("bold"," ╔══════════════════════════════════════╗")),console.log(c("bold"," ║ THUBAN HEALTH REPORT ║")),console.log(c("bold"," ╚══════════════════════════════════════╝")),console.log(""),console.log(` ${c("bold","Health Score:")} ${c($,b+"/100")}`),console.log(` ${c("bold","Files Scanned:")} ${l.length}`),console.log(` ${c("bold","Time:")} ${d}ms`),console.log(""),console.log(c("bold"," ── Code Quality ──────────────────────")),console.log(` Total issues: ${h}`),console.log(` Critical: ${u>0?c("red",u):c("green","0")}`),console.log(` High: ${y>0?c("red",y):c("green","0")}`),console.log(""),console.log(c("bold"," ── Dependencies ─────────────────────")),console.log(` Circular deps: ${f.length>0?c("red",f.length):c("green","0")}`),console.log(` Orphan files: ${p.length>0?c("yellow",p.length):c("green","0")}`),console.log(""),console.log(c("bold"," ── Mother Code ──────────────────────")),console.log(` Annotated files: ${g}`),console.log(` Coverage: ${c(m>=80?"green":m>=40?"yellow":"red",m+"%")}`),console.log(` Drifted files: ${i>0?c("yellow",i):c("green","0")}`),console.log("");const w=b>=90?"A":b>=80?"B":b>=70?"C":b>=60?"D":"F",v=b>=80?"green":b>=60?"yellow":"red";console.log(` ${c("bold","Grade:")} ${c(v,w)}`),console.log(""),b<80&&(console.log(c("bold"," RECOMMENDATIONS:")),u>0&&console.log(` ${c("red","→")} Fix ${u} critical issues immediately`),f.length>0&&console.log(` ${c("yellow","→")} Resolve ${f.length} circular dependencies`),m<50&&console.log(` ${c("yellow","→")} Run ${c("cyan","thuban inject --fix")} to improve Mother Code coverage`),i>0&&console.log(` ${c("yellow","→")} ${i} files have drifted from their annotations`),p.length>5&&console.log(` ${c("gray","→")} Consider removing ${p.length} orphan files`),console.log(""))}async function cmdDebt(e){const o=path.resolve(e.targetPath),n=collectFiles(o,e.ignore);e.json||(banner(),console.log(c("bold"," TECH DEBT ANALYSIS: ")+c("cyan",o)),console.log(c("gray",` Scanning ${n.length} files...`)),console.log(""));const l=new TechDebtAnalyzer({rootPath:o}),s=await l.analyze(n);e.json?console.log(JSON.stringify(l.toJSON(s),null,2)):console.log(l.formatReport(s))}async function cmdFix(e){const o=path.resolve(e.targetPath),n=collectFiles(o,e.ignore),{execSync:l}=require("child_process");e.json||(banner(),console.log(c("bold"," AUTO-FIX TECH DEBT: ")+c("cyan",o)),console.log(""));const s=new TechDebtAnalyzer({rootPath:o});if(!e.fix){const o=await s.fix(n,{dryRun:!0});if(e.json)console.log(JSON.stringify(o,null,2));else{console.log(c("cyan"," ╔══════════════════════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold"," DRY RUN — no files will be changed ")+c("cyan","║")),console.log(c("cyan"," ╚══════════════════════════════════════════════════════╝")),console.log(""),console.log(` Fixable items: ${c("bold",o.totalFixable)}`),console.log("");const e={},n=["break_circular","extract_to_env","update_deprecated_api","wrap_localhost_url"];let l=0,s=0;for(const c of o.fixes){const o=c.fixAction||"unknown";e[o]||(e[o]=0),e[o]++,n.includes(o)?s++:l++}console.log(c("green",c("bold",` SAFE FIXES (${l})`))+c("gray"," — no runtime behaviour change"));for(const[o,l]of Object.entries(e).sort((e,o)=>o[1]-e[1])){if(n.includes(o))continue;const e={inject_widget:"Inject Mother Code DNA annotations",regenerate_widget:"Update stale annotations",remove_console_log:"Remove debug console.logs",flag_for_removal:"Confirm orphan files for removal"}[o]||o;console.log(` ${c("green","→")} ${e}: ${c("bold",l)}`)}if(console.log(""),s>0){console.log(c("yellow",c("bold",` UNSAFE FIXES (${s})`))+c("gray"," — may change runtime behaviour"));for(const[o,l]of Object.entries(e).sort((e,o)=>o[1]-e[1])){if(!n.includes(o))continue;const e={break_circular:"Restructure circular dependencies",extract_to_env:"Extract hardcoded secrets to env vars",update_deprecated_api:"Replace deprecated API calls with modern equivalents",wrap_localhost_url:"Wrap hardcoded localhost URLs in env var fallback"}[o]||o;console.log(` ${c("yellow","!")} ${e}: ${c("bold",l)}`)}console.log(""),console.log(c("gray"," Unsafe fixes require --unsafe flag:")),console.log(` ${c("cyan","thuban fix [path] --fix --unsafe")}`),console.log("")}console.log(c("bold"," TO APPLY:")),console.log(` ${c("cyan","thuban fix [path] --fix")} Apply safe fixes only`),console.log(` ${c("cyan","thuban fix [path] --fix --unsafe")} Apply all fixes`),console.log(` ${c("cyan","thuban fix [path] --fix --commit")} Each fix = separate git commit`),console.log("")}return}e.json||(e.safe?console.log(c("green"," SAFE MODE")+c("gray"," — only non-runtime-changing fixes will be applied")):console.log(c("yellow"," UNSAFE MODE")+c("gray"," — all fixes including runtime changes")),console.log(""));const t=await s.fix(n,{dryRun:!1,safeOnly:e.safe});if(e.gitCommit&&t.fixed>0)try{l("git rev-parse --git-dir",{cwd:o,stdio:"pipe"}),l("git add -A",{cwd:o,stdio:"pipe"});const n=`fix(thuban): auto-fix ${t.fixed} issues [safe=${e.safe}]`;l(`git commit -m "${n}"`,{cwd:o,stdio:"pipe"}),e.json||(console.log(c("green",` ✓ Changes committed: "${n}"`)),console.log(c("gray"," Revert with: git revert HEAD")),console.log(""))}catch(o){e.json||(console.log(c("yellow"," ⚠ Could not auto-commit: "+(o.message||"not a git repo"))),console.log(""))}if(e.json)console.log(JSON.stringify(t,null,2));else{console.log(c("cyan"," ╔══════════════════════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold"," FIX RESULTS ")+c("cyan","║")),console.log(c("cyan"," ╠══════════════════════════════════════════════════════╣"));const o=(t.fixes||[]).filter(e=>"fixed"===e.status&&("inject_widget"===e.fixAction||"regenerate_widget"===e.fixAction)).length,n=t.fixed-o;o>0&&console.log(c("cyan"," ║")+` Annotations added: ${c("green",String(o).padEnd(19))}`+c("cyan"," ║")),n>0&&console.log(c("cyan"," ║")+` Issues fixed: ${c("green",String(n).padEnd(20))}`+c("cyan"," ║")),0===o&&0===n&&console.log(c("cyan"," ║")+` Fixed: ${c("green",String(t.fixed).padEnd(20))}`+c("cyan"," ║")),console.log(c("cyan"," ║")+` Flagged for review: ${c("yellow",String(t.flagged).padEnd(19))}`+c("cyan"," ║")),t.failed>0&&console.log(c("cyan"," ║")+` Failed: ${c("red",String(t.failed).padEnd(20))}`+c("cyan"," ║")),t.skipped>0&&console.log(c("cyan"," ║")+` Skipped: ${c("gray",String(t.skipped).padEnd(20))}`+c("cyan"," ║")),console.log(c("cyan"," ╚══════════════════════════════════════════════════════╝")),console.log(""),t.fixed>0&&(console.log(c("green"," Your files have been updated. Changes are saved to disk.")),e.gitCommit||console.log(c("gray"," Tip: use --commit next time to auto-commit each fix for easy rollback.")),console.log(""),console.log(c("gray"," Verify the changes:")),console.log(c("gray"," ")+c("cyan","npx thuban scan .")+c("gray"," Re-scan to see your new score")),console.log(c("gray"," ")+c("cyan","npx thuban dashboard .")+c("gray"," Generate updated report")),console.log("")),t.skipped>0&&(console.log(c("gray",` ${t.skipped} items were skipped (no auto-fix available or pattern not matched).`)),console.log(c("gray"," Review them manually or run: ")+c("cyan","npx thuban dashboard .")),console.log("")),t.flagged>0&&(console.log(c("gray",` ${t.flagged} items need human review (secrets, orphan files, complex patterns).`)),console.log(c("gray"," See details: ")+c("cyan","npx thuban dashboard .")),console.log(""))}}async function cmdHallucinate(e){const o=path.resolve(e.targetPath),n=collectFiles(o,e.ignore);e.json||(banner(),console.log(c("bold"," HALLUCINATION SCAN: ")+c("cyan",o)),console.log(c("gray",` Scanning ${n.length} files for AI hallucinations...`)),console.log(""));const l=new HallucinationDetector({rootPath:o}),s=await l.scan(n);e.json?console.log(JSON.stringify(s,null,2)):console.log(l.formatReport(s))}async function cmdWatch(e){const o=path.resolve(e.targetPath),n=new CodeScanner({rootPath:o,ignorePatterns:["node_modules/**",".git/**","dist/**",...e.ignore]}),c=new HallucinationDetector({rootPath:o}),l=new FileWatcher({rootPath:o,ignorePatterns:["node_modules",".git","dist",".next","__pycache__",...e.ignore]});process.on("SIGINT",()=>{l.stop(),process.exit(0)}),l.start(async e=>{const o=[],l=await n.scanFile(e);l&&o.push(...l);const s=await c.scan([e]);if(s.phantomAPIs.length>0)for(const e of s.phantomAPIs)o.push({severity:"high",message:`Phantom API: ${e.name} — ${e.suggestion}`,line:e.line});if(s.phantomImports.length>0)for(const e of s.phantomImports)o.push({severity:"critical",message:`Phantom import: ${e.module} — ${e.reason}`,line:e.line});if(s.aiSmells.length>0)for(const e of s.aiSmells)o.push({severity:"warning",message:`AI smell: ${e.message}`,line:e.line});return o})}async function cmdDashboard(e){const o=path.resolve(e.targetPath),n=collectFiles(o,e.ignore);e.json||(banner(),console.log(c("bold"," GENERATING DASHBOARD: ")+c("cyan",o)),console.log(c("gray",` Scanning ${n.length} files...`)),console.log(""));const l=new TechDebtAnalyzer({rootPath:o}),s=await l.analyze(n),t=new DependencyGraph({rootPath:o});await t.build(n);const a={circular:t.circularDeps||[],orphans:t.getOrphanFiles()||[],critical:t.getMostCriticalFiles(5)||[]},r=new HallucinationDetector({rootPath:o}),i=await r.scan(n),g=new HtmlReportGenerator({rootPath:o,outputDir:o}),d=path.basename(o),h=await g.writeReport(s,a,{projectName:d,hallucinations:i});e.json?console.log(JSON.stringify({outputPath:h,scores:s.scores,stats:s.stats},null,2)):(console.log(c("green"," ✓ Dashboard generated:")),console.log(` ${c("cyan",h)}`),console.log(""),console.log(c("gray"," Open in your browser to view the interactive report")),console.log(""))}async function cmdDiff(e){const o=path.resolve(e.targetPath),{execSync:n}=require("child_process");e.json||(banner(),console.log(c("bold"," DIFF SCAN: ")+c("cyan",o)));let l=[];try{let e="main";try{n("git rev-parse --verify main",{cwd:o,stdio:"pipe"})}catch{try{n("git rev-parse --verify master",{cwd:o,stdio:"pipe"}),e="master"}catch{e="HEAD~1"}}const c=n(`git diff --name-only ${e}...HEAD`,{cwd:o,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),s=n("git diff --name-only HEAD",{cwd:o,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),t=n("git ls-files --others --exclude-standard",{cwd:o,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),a=new Set([...c.split("\n").filter(Boolean),...s.split("\n").filter(Boolean),...t.split("\n").filter(Boolean)]);for(const e of a){const n=path.resolve(o,e),c=path.extname(e).toLowerCase();[".js",".ts",".jsx",".tsx",".mjs",".cjs",".json"].includes(c)&&fs.existsSync(n)&&l.push(n)}}catch(o){e.json||console.log(c("red",` ✗ Not a git repository or git error: ${o.message}`)),process.exit(1)}if(0===l.length)return void(e.json?console.log(JSON.stringify({changedFiles:0,issues:0})):console.log(c("green"," ✓ No changed files to scan")));e.json||console.log(c("gray",` Scanning ${l.length} changed file${1===l.length?"":"s"}...\n`));const s=new CodeScanner({rootPath:o}),t=new HallucinationDetector({rootPath:o}),a=await s.scanFiles(l),r=await t.scan(l);let i=0;const g={};for(const e of a.issues||[]){const n=path.relative(o,e.file);g[n]||(g[n]=[]),g[n].push(e),i++}if(i+=r.stats.totalIssues,e.json)console.log(JSON.stringify({changedFiles:l.length,totalIssues:i,codeIssues:g,hallucinations:r},null,2));else{for(const[e,o]of Object.entries(g)){console.log(` ${c("cyan",e)}`);for(const e of o.slice(0,5)){const o="critical"===e.severity||"high"===e.severity?"red":"warning"===e.severity?"yellow":"gray";console.log(` ${c(o,"✗")} ${c("gray",e.message||e.id||"")}`)}o.length>5&&console.log(` ${c("gray",`... and ${o.length-5} more`)}`),console.log("")}r.stats.totalIssues>0&&console.log(t.formatReport(r));const e=0===i?"green":"yellow";console.log(` ${c(e,`${l.length} files changed, ${i} new issues introduced`)}\n`)}}async function cmdActivate(e){banner();const o=new LicenseManager,n=e.licenseKey;if(!n)return console.log(c("red"," Usage: thuban activate <license-key>")),console.log(""),console.log(c("gray"," Get a key at: ")+c("cyan","https://thuban.dev/pricing")),void console.log("");const l=o.activate(n);l.success?(console.log(c("green"," ╔══════════════════════════════════════╗")),console.log(c("green"," ║")+c("bold"," License activated! ")+c("green","║")),console.log(c("green"," ╚══════════════════════════════════════╝")),console.log(""),console.log(` Tier: ${c("bold",l.tierName)}`),console.log(` Status: ${c("green","Active")}`),console.log(""),console.log(c("gray"," All features unlocked. Run ")+c("cyan","thuban scan .")+c("gray"," to get started.")),console.log("")):(console.log(c("red"," Invalid license key.")),console.log(""),console.log(c("gray"," Check for typos or get a new key at: ")+c("cyan","https://thuban.dev/pricing")),console.log(""))}async function cmdStatus(e){banner();const o=(new LicenseManager).getStatus();console.log(c("bold"," LICENSE STATUS")),console.log(""),console.log(` Tier: ${c("bold",o.tierName)}${o.licensed?c("green"," (active)"):""}`),console.log(` Machine ID: ${c("gray",o.machineId)}`),console.log(` Scans this month: ${c("bold",o.scansUsed)}${o.scansLimit<1/0?c("gray"," / "+o.scansLimit):""}`),console.log(` Lifetime scans: ${c("gray",o.totalScans)}`),console.log(""),console.log(c("bold"," FEATURES")),console.log(` Full scan details: ${o.features.fullDetails?c("green","Yes"):c("red","No")}`),console.log(` HTML dashboard: ${o.features.dashboard?c("green","Yes"):c("red","No")}`),console.log(` Auto-fix: ${o.features.autoFix?c("green","Yes"):c("red","No")}`),console.log(` CI Action: ${o.features.ciAction?c("green","Yes"):c("red","No")}`),console.log(""),o.licensed||(console.log(c("cyan"," Upgrade at: ")+c("bold","https://thuban.dev/pricing")),console.log(""))}function cmdUpgrade(){banner(),console.log(c("bold"," THUBAN PRICING")),console.log(""),console.log(` ${c("gray","FREE")} ${c("bold","£0/mo")}`),console.log(" 5 scans/month, 100 files, summary only"),console.log(""),console.log(` ${c("cyan","PRO")} ${c("bold","£19/mo")} ${c("gray","(or £149/year — save 35%)")}`),console.log(" Unlimited scans, full details, auto-fix, HTML dashboard"),console.log(""),console.log(` ${c("cyan","TEAM")} ${c("bold","£99/mo")}`),console.log(" Everything in Pro + 5 seats, CI Action, team reports"),console.log(""),console.log(` ${c("cyan","ENTERPRISE")} ${c("bold","£299/mo")}`),console.log(" Everything in Team + unlimited seats, priority support, SLA"),console.log(""),console.log(c("bold"," Subscribe at: ")+c("cyan","https://thuban.dev/pricing")),console.log("");try{const{exec:e}=require("child_process"),o=process.platform;e(("win32"===o?"start":"darwin"===o?"open":"xdg-open")+" https://thuban.dev/pricing")}catch(e){}}async function cmdGate(e){const o=path.resolve(e.targetPath);if(e.fix){const e=PreCommitGate.install(o);return banner(),e.success?(console.log(c("green"," ✓ Pre-commit gate installed!")),console.log(""),console.log(c("gray"," Every commit will now be checked for hallucinated APIs.")),console.log(c("gray"," Commits with phantom APIs will be blocked automatically.")),console.log(""),console.log(` To remove: ${c("cyan","thuban gate --uninstall")}`)):console.log(c("red",` Error: ${e.error}`)),void console.log("")}if(process.argv.includes("--uninstall")){const e=PreCommitGate.uninstall(o);return banner(),console.log(c("green",` ✓ ${e.message}`)),void console.log("")}const n=new PreCommitGate({rootPath:o,strict:!process.argv.includes("--warn")}).run();if(e.json)return void console.log(JSON.stringify(n,null,2));const l=process.argv.includes("--ci");if(l||banner(),0===n.files)return console.log(c("gray"," No staged files to check.")),console.log(""),console.log(` Install the gate: ${c("cyan","thuban gate --fix")}`),void console.log("");if(n.passed)console.log(c("green",` ✓ ${n.message}`)),console.log(c("gray",` ${n.elapsed}ms`)),l||console.log(""),process.exit(0);else{console.log(c("red",` ✗ ${n.message}`)),console.log("");for(const e of n.issues)console.log(` ${c("red",e.file)}:${e.line}`),console.log(` ${c("yellow",e.code)}`),console.log(` ${c("red","^^^")} ${e.message}`),e.fix&&console.log(` ${c("green","Fix:")} ${e.fix}`),console.log("");process.exit(1)}}async function cmdCost(e){const o=path.resolve(e.targetPath);banner(),console.log(c("bold"," SCANNING: ")+c("cyan",o)),console.log("");const n=collectFiles(o,e.ignore),l=new CodeScanner({rootPath:o,ignorePatterns:["node_modules/**",".git/**","dist/**",...e.ignore]}),s=new HallucinationDetector({rootPath:o}),[t,a]=await Promise.all([l.scanFiles(n),s.scan(n)]),r=[];for(const e of t.issues||[])r.push({file:path.relative(o,e.file),...e});for(const e of a.phantomAPIs)r.push({category:"hallucination",severity:"critical",message:e.name});for(const e of a.deprecatedAPIs)r.push({category:"deprecated",severity:"high",message:e.name});const i=new TechDebtCostCalculator,g=i.calculate(r,n.length);e.json?console.log(JSON.stringify(g,null,2)):console.log(i.formatCLI(g))}async function cmdGhosts(e){const o=path.resolve(e.targetPath);banner(),console.log(c("bold"," SCANNING FOR GHOST CODE: ")+c("cyan",o)),console.log("");const n=collectFiles(o,e.ignore),l=new GhostCodeDetector({rootPath:o}).scan(n);if(e.json)console.log(JSON.stringify(l,null,2));else{if(0===l.ghosts.length)return console.log(c("green"," No ghost code detected. Every function is referenced.")),void console.log("");console.log(c("yellow",c("bold",` GHOST CODE: ${l.totalGhosts} function${l.totalGhosts>1?"s":""} exist but are never called`))),console.log("");for(const o of l.ghosts.slice(0,e.maxIssues)){const e="high"===o.severity?"red":"yellow";console.log(` ${c(e,"⊘")} ${c("cyan",o.file)}:${o.line}`),console.log(` ${c("bold",o.name+"()")} — ${o.wastedLines} lines, ${o.references} references`),console.log("")}console.log(c("bold"," ┌──────────────────────────────────────────────────────┐")),console.log(c("bold"," │")+` Wasted code: ${c("red",l.totalWastedLines+" lines")} (${l.wastedPercent}% of codebase) `+c("bold","│")),console.log(c("bold"," └──────────────────────────────────────────────────────┘")),console.log("")}}async function cmdAIScore(e){const o=path.resolve(e.targetPath);banner(),console.log(c("bold"," AI CONFIDENCE SCORING: ")+c("cyan",o)),console.log("");const n=collectFiles(o,e.ignore),l=new AIConfidenceScorer({rootPath:o}).scan(n);if(e.json)console.log(JSON.stringify(l,null,2));else{if(0===l.highConfidence.length&&0===l.mediumConfidence.length)return console.log(c("green"," No AI-generated code patterns detected.")),void console.log("");console.log(c("red",c("bold",` HIGH CONFIDENCE AI-GENERATED (${l.highConfidence.length} functions)`))),console.log("");for(const e of l.highConfidence.slice(0,15)){console.log(` ${c("red",e.confidence+"%")} AI ${c("cyan",e.file)}:${e.line}`),console.log(` ${c("bold",e.name+"()")} — ${e.lineCount} lines | Test coverage: ${e.testCoverage}`);for(const o of e.signals.slice(0,2))console.log(` ${c("gray","• "+o)}`);console.log("")}if(l.mediumConfidence.length>0){console.log(c("yellow",c("bold",` POSSIBLE AI-GENERATED (${l.mediumConfidence.length} functions)`))),console.log("");for(const e of l.mediumConfidence.slice(0,10))console.log(` ${c("yellow",e.confidence+"%")} AI ${c("cyan",e.file)}:${e.line} ${c("gray",e.name+"()")}`);console.log("")}console.log(c("bold"," ┌──────────────────────────────────────────────────────┐")),console.log(c("bold"," │")+` ${c("red",l.aiPercentage+"%")} of functions are likely AI-generated `+c("bold","│")),console.log(c("bold"," │")+` ${c("yellow",l.aiLikelyCount)} high confidence | ${l.aiPossibleCount} possible `+c("bold","│")),console.log(c("bold"," └──────────────────────────────────────────────────────┘")),console.log("")}}async function cmdClones(e){const o=path.resolve(e.targetPath);banner(),console.log(c("bold"," COPY-PASTE DRIFT DETECTION: ")+c("cyan",o)),console.log("");const n=collectFiles(o,e.ignore),l=new CopyPasteDriftDetector({rootPath:o}).scan(n);if(e.json)console.log(JSON.stringify(l,null,2));else{if(0===l.clusters.length)return console.log(c("green"," No copy-paste drift detected.")),void console.log("");console.log(c("yellow",c("bold",` COPY-PASTE CLUSTERS: ${l.totalClusters} found`))),console.log("");for(const e of l.clusters.slice(0,10)){const o="high"===e.severity?"red":"yellow";console.log(` ${c(o,"◈")} ${c("bold",e.pattern+" pattern")} — ${e.totalInstances} instances`);for(const o of e.members){const e=o.similarity<100?c("gray",` (${o.similarity}% similar)`):"";console.log(` ${c("cyan",o.file)}:${o.line} ${c("gray",o.name+"()")}${e}`)}console.log(` ${c("green","→")} ${e.recommendation}`),console.log("")}console.log(c("bold",` Total duplicate lines: ${c("red",l.totalDuplicateLines)}`)),console.log(c("gray",` ${l.recommendation}`)),console.log("")}}async function cmdPassport(e){const o=path.resolve(e.targetPath);banner(),console.log(c("bold"," GENERATING CODEBASE PASSPORT: ")+c("cyan",o)),console.log("");const n=collectFiles(o,e.ignore),l=new CodebasePassport({rootPath:o}),s=l.generate(n);if(e.json)return void console.log(JSON.stringify(s,null,2));const t=l.save(s),a=s.project,r=s.onboarding;console.log(c("green",` ✓ Passport generated: ${c("bold",path.relative(o,t))}`)),console.log(""),console.log(c("bold"," PROJECT IDENTITY")),console.log(` Name: ${c("cyan",a.name)}`),console.log(` Files: ${c("bold",a.totalFiles)}`),console.log(` Lines: ${c("bold",a.totalLines.toLocaleString())}`),console.log(` Architecture: ${c("bold",a.architecture)}`),console.log(` Frameworks: ${a.frameworks.join(", ")||"vanilla"}`),console.log(""),console.log(c("bold"," LANGUAGES"));for(const e of a.languages.slice(0,5)){const o="█".repeat(Math.max(1,Math.round(e.percentage/5)));console.log(` ${e.extension.padEnd(6)} ${c("cyan",o)} ${e.percentage}% (${e.lines} lines)`)}if(console.log(""),console.log(c("bold"," ONBOARDING")),console.log(` Read time: ~${r.estimatedReadTimeMinutes} minutes`),console.log(` Start here: ${r.startHere.slice(0,3).join(", ")}`),r.doNotTouch.length>0&&console.log(` Do not touch: ${c("red",r.doNotTouch.join(", "))}`),console.log(` Summary: ${r.quickSummary}`),console.log(""),s.sacred.length>0){console.log(c("bold"," SACRED FILES (high impact if changed)"));for(const e of s.sacred.slice(0,5))console.log(` ${c("red","!")} ${c("cyan",e.file)} — imported by ${e.importedBy} files`);console.log("")}console.log(c("gray",` Full passport: ${t}`)),console.log(c("gray"," Share with new team members for instant onboarding.")),console.log("")}async function cmdExecutive(e){const o=path.resolve(e.targetPath);banner(),console.log(c("bold"," GENERATING EXECUTIVE REPORT: ")+c("cyan",o)),console.log("");const n=collectFiles(o,e.ignore);console.log(c("gray",` Scanning ${n.length} files...`));const l=new CodeScanner({rootPath:o,ignorePatterns:["node_modules/**",".git/**","dist/**",...e.ignore]}),s=new HallucinationDetector({rootPath:o}),t=new GhostCodeDetector({rootPath:o}),a=new AIConfidenceScorer({rootPath:o}),r=new CopyPasteDriftDetector({rootPath:o}),[i,g,d,h,u]=await Promise.all([l.scanFiles(n),s.scan(n),t.scan(n),a.scan(n),r.scan(n)]);let y=0;for(const e of n)try{y+=fs.readFileSync(e,"utf-8").split("\n").length}catch{}const p=[];for(const e of i.issues||[])p.push({file:path.relative(o,e.file),...e});for(const e of g.phantomAPIs)p.push({category:"hallucination",severity:"critical",message:e.name});for(const e of g.deprecatedAPIs)p.push({category:"deprecated",severity:"high",message:e.name});const f=(new TechDebtCostCalculator).calculate(p,n.length),m=new ExecutiveReport({rootPath:o,companyName:e.companyName||void 0}),b=m.generate({scanResults:i,hallResults:g,debtCost:f,ghostResults:d,aiScoreResults:h,cloneResults:u,fileCount:n.length,lineCount:y}),$=m.save(b,o);console.log(c("green"," ✓ Executive report generated!")),console.log(""),console.log(` ${c("bold","Report:")} ${c("cyan",$)}`),console.log(""),console.log(c("gray"," Open in browser → Ctrl+P → Save as PDF")),console.log(c("gray",' Or click the "Save as PDF" button in the report.')),console.log("");try{const{exec:e}=require("child_process"),o=process.platform;e(`${"win32"===o?"start":"darwin"===o?"open":"xdg-open"} "${$}"`),console.log(c("green"," ✓ Opened in your default browser.")),console.log("")}catch(e){}}async function cmdBaseline(e){const o=path.resolve(e.targetPath),n=new BaselineManager(o);if(banner(),e.baselineCreate||!n.exists()){console.log(c("bold"," CREATING BASELINE: ")+c("cyan",o)),console.log("");const l=collectFiles(o,e.ignore),s=new CodeScanner({rootPath:o,ignorePatterns:["node_modules/**",".git/**","dist/**",...e.ignore]}),t=new HallucinationDetector({rootPath:o}),[a,r]=await Promise.all([s.scanFiles(l),t.scan(l)]),i=[];for(const e of a.issues||[])i.push({file:path.relative(o,e.file),...e});for(const e of r.phantomAPIs)i.push({file:e.file,category:"hallucination",severity:"critical",id:e.id,message:e.name});for(const e of r.deprecatedAPIs)i.push({file:e.file,category:"deprecated",severity:"high",id:e.id,message:e.name});for(const e of r.aiSmells)i.push({file:e.file,category:"ai_smell",severity:"warning",id:e.id,message:e.message});const g=n.create(i);console.log(c("green",` ✓ Baseline created: ${c("bold",g.count)} known issues recorded`)),console.log(` ${c("cyan",g.path)}`),console.log(""),console.log(c("gray"," Future scans with --baseline will only report NEW issues.")),console.log(c("gray"," Commit .thuban-baseline.json to share baseline with your team.")),console.log("")}else{const e=n.load();console.log(c("bold"," BASELINE STATUS")),console.log(""),console.log(` Created: ${c("cyan",e.created)}`),console.log(` Known issues: ${c("bold",e.issueCount)}`),console.log(""),console.log(c("gray"," Use --baseline-create to update the baseline")),console.log(c("gray"," Use --baseline with scan to only see new issues")),console.log("")}}async function cmdCrucible(e){const o=process.argv.slice(2),n=o[1]||"",l=path.resolve(e.targetPath);if("ci"===n){const e=o[2]||"",n=CIIntegration.listPlatforms();if(!e||!n.includes(e))return console.log(""),console.log(c("bold"," CRUCIBLE CI INTEGRATION")),console.log(""),console.log(c("gray"," Usage:")),console.log(` ${c("cyan","thuban crucible ci github")} → .github/workflows/thuban-crucible.yml`),console.log(` ${c("cyan","thuban crucible ci gitlab")} → .gitlab-ci.yml`),console.log(` ${c("cyan","thuban crucible ci bitbucket")} → bitbucket-pipelines.yml`),console.log(""),e&&(console.log(c("red",` Unknown platform: ${e}`)),console.log(c("gray",` Supported: ${n.join(", ")}`))),void console.log("");const s=o.find(e=>e.startsWith("--threshold=")),t=o.find(e=>e.startsWith("--level=")),a=o.find(e=>e.startsWith("--node=")),r=s?parseInt(s.split("=")[1],10):70,i=t?t.split("=")[1]:"gentle",g=a?a.split("=")[1]:"20";try{const o=CIIntegration.generateCIConfig(e,l,{threshold:r,level:i,nodeVersion:g});console.log(""),console.log(c("green"," ✓ CI config generated")),console.log(` ${c("cyan",o.filename)}`),console.log(""),console.log(c("gray",` Config: threshold=${o.threshold}, level=${o.level}`)),console.log(c("gray"," Commit this file and Crucible will run on every PR.")),console.log("")}catch(e){console.error(c("red",` Error: ${e.message}`))}return}if("badge"===n){const e=o.find(e=>e.startsWith("--score="));let n=e?parseInt(e.split("=")[1],10):null;if(null===n&&(n=BadgeGenerator.readLastScore(l)),null===n)return console.log(""),console.log(c("yellow"," No Crucible report found.")),console.log(c("gray"," Run `thuban crucible run .` first, or pass --score=<n>")),void console.log("");const s=o.find(e=>e.startsWith("--style=")),t=o.find(e=>e.startsWith("--threshold=")),a=s?s.split("=")[1]:"score",r=t?parseInt(t.split("=")[1],10):70,i=BadgeGenerator.generateBadge({score:n,targetPath:l,style:a,threshold:r});return console.log(""),console.log(c("green",` ✓ Badge generated: ${c("cyan",path.relative(l,i.outputPath))}`)),console.log(` Score: ${c("green"===i.color?"green":"yellow"===i.color?"yellow":"red",n+"/100")} (${i.verdict})`),console.log(""),console.log(c("bold"," Add to README.md:")),console.log(` ${c("cyan",i.markdown)}`),void console.log("")}if("leaderboard"!==n&&"lb"!==n){if("run"===n||"seed"===n){const n=parseFlag(o,"level","gentle"),s=parseIntFlag(o,"seed",42),t=parseFlag(o,"lang",null),a=parseFlag(o,"category",null);console.log(Crucible.banner.fullBanner({level:n,version:"0.4.0"})),console.log(c("bold"," Running adversarial seed tests...")),console.log(c("gray",` Level: ${n} · PRNG seed: ${s}`)),console.log("");let r=0,i=0,g=0;const d=await Crucible.run({targetPath:l,level:n,seed:s,languages:t?t.split(","):void 0,categories:a?a.split(","):void 0,onProgress(e,o,n){g++,"seed"===e&&(n.detected?(r++,process.stdout.write(c("green","."))):(i++,process.stdout.write(c("red","x"))),g%50==0&&process.stdout.write("\n"))}});process.stdout.write("\n\n"),console.log(c("bold"," Results:")+` ${c("green",d.seedResults.detected+" detected")} ${c("red",d.seedResults.missed+" missed")} (${d.seedResults.total} seeds)`),console.log(Crucible.banner.scoreBanner(d.score));const h=Crucible.compareGolden(d);return h.hasMaster?console.log(h.passed?c("green"," ✓ No regressions vs golden master"):c("red",` ✗ ${h.regressions} regression(s) vs golden master`)):console.log(c("gray"," (No golden master — run `thuban crucible approve` to set one)")),console.log(""),e.json&&console.log(JSON.stringify(d,null,2)),BadgeGenerator.writeLastScore&&BadgeGenerator.writeLastScore(l,d.score),void(Leaderboard.addEntry&&Leaderboard.addEntry(l,{score:d.score,level:n,timestamp:d.timestamp}))}if("approve"===n){console.log(""),console.log(c("bold"," Approving current results as golden master..."));const e=await Crucible.run({targetPath:l,level:"gentle",seed:42}),o=Crucible.approve(e);return console.log(c("green",` ✓ Golden master saved: ${o.count} findings, score ${o.meta.score}`)),console.log(c("gray"," File: .golden/golden-master.json")),void console.log("")}if("kenny"===n){console.log(Crucible.banner.compactBanner("KENNY MODE")),console.log(c("bold",` Kenny's 7-report test battery (${Crucible.KennyMode.testCount} tests)`)),console.log("");const o=await Crucible.kenny({onProgress(e,o){const n=o.passed?c("green","✓"):o.crashed?c("yellow","⚡"):c("red","✗"),l=c("gray",e.id)+" "+e.name,s=o.missingDetections&&o.missingDetections.length?c("red"," missing: "+o.missingDetections.join(", ")):"";console.log(` ${n} ${l}${s}`)}});return console.log(Crucible.banner.summaryLine(o.passed,o.total-o.skipped,o.score)),void(e.json&&console.log(JSON.stringify(o,null,2)))}if("self-test"===n||"selftest"===n){console.log(Crucible.banner.compactBanner("SELF-ATTACK")),console.log(c("bold",` Adversarial self-attack (${Crucible.SelfAttack.payloadCount} payloads)`)),console.log("");const o=await Crucible.selfTest({onProgress(e,o){const n="pass"===o.type?c("green","✓"):"crash"===o.type?c("red","⚡ CRASH"):"hang"===o.type?c("yellow","⏱ HANG"):c("yellow","? MISSED");console.log(` ${n} ${c("gray",e.name)} ${e.description}`)}});console.log("");const n=o.crashes.length,l=o.hangs.length;return 0===n&&0===l?console.log(c("green",` ✓ All ${o.payloadCount} payloads handled gracefully`)):(n&&console.log(c("red",` ✗ ${n} crash(es) detected`)),l&&console.log(c("yellow",` ⚠ ${l} hang(s) detected`))),console.log(Crucible.banner.scoreBanner(o.score)),void(e.json&&console.log(JSON.stringify(o,null,2)))}if("report"===n){console.log(""),console.log(c("bold"," Generating Crucible report..."));const o=await Crucible.run({targetPath:l,level:"gentle",seed:42}),n=await Crucible.kenny(),s=Crucible.compareGolden(o),t={title:"Thuban Crucible Report",level:"gentle",score:o.score,seedResults:o.seedResults,mutationResults:o.mutationResults,kennyResults:n,goldenComparison:s.hasMaster?s:null},a=e.output?path.resolve(e.output):l,{htmlPath:r,jsonPath:i}=Crucible.report(t,{outputDir:a});return console.log(c("green",` ✓ HTML report: ${c("cyan",r)}`)),console.log(c("green",` ✓ JSON summary: ${c("cyan",i)}`)),void console.log(Crucible.banner.scoreBanner(o.score))}if("golden"===n){const e=(new Crucible.GoldenMaster).loadMaster();return console.log(""),e?(console.log(c("bold"," Golden Master Status")),console.log(` Score: ${null!=e.meta.score?e.meta.score:"N/A"}`),console.log(` Findings: ${e.count}`),console.log(` Saved: ${e.timestamp}`),console.log(` Hash: ${e.hash}`)):console.log(c("yellow"," No golden master. Run `thuban crucible approve` to create one.")),void console.log("")}console.log(""),console.log(c("bold"," CRUCIBLE — Adversarial Testing Engine")),console.log(""),console.log(c("gray"," Core commands:")),console.log(` ${c("cyan","thuban crucible run")} [path] [--level gentle|medium|hell]`),console.log(` ${c("cyan","thuban crucible seed")} [path]`),console.log(` ${c("cyan","thuban crucible mutate")} [path]`),console.log(` ${c("cyan","thuban crucible golden")} [path]`),console.log(` ${c("cyan","thuban crucible approve")}`),console.log(` ${c("cyan","thuban crucible self-test")}`),console.log(` ${c("cyan","thuban crucible kenny")}`),console.log(` ${c("cyan","thuban crucible report")}`),console.log(""),console.log(c("gray"," CI/CD & badges:")),console.log(` ${c("cyan","thuban crucible ci github")} Generate GitHub Actions workflow`),console.log(` ${c("cyan","thuban crucible ci gitlab")} Generate GitLab CI config`),console.log(` ${c("cyan","thuban crucible ci bitbucket")} Generate Bitbucket Pipelines config`),console.log(` ${c("cyan","thuban crucible badge")} Generate SVG score badge for README`),console.log(` ${c("cyan","thuban crucible leaderboard")} View score history & trend`),console.log(""),console.log(c("gray"," Options:")),console.log(` ${c("gray","--threshold=<n>")} Fail CI if score drops below n (default 70)`),console.log(` ${c("gray","--level=<l>")} gentle | medium | hell`),console.log(` ${c("gray","--score=<n>")} Explicit score for badge (else reads last report)`),console.log(` ${c("gray","--style=score|verdict")} Badge text style`),console.log("")}else{if(e.json){const e=Leaderboard.getSummary(l);return void console.log(JSON.stringify(e,null,2))}Leaderboard.printLeaderboard(l,{color:!0})}}function getTelemetryConfigPath(){const e=process.env.HOME||process.env.USERPROFILE||os.homedir();return path.join(e,".thuban-telemetry.json")}function isTelemetryEnabled(){try{return!0===JSON.parse(fs.readFileSync(getTelemetryConfigPath(),"utf-8")).enabled}catch{return!1}}function sendAnonymousTelemetry(e){if(isTelemetryEnabled())try{const o=JSON.stringify({v:e.version||"0.4.0",cmd:e.command,files:e.fileCount,score:e.score,grade:e.grade,langs:e.languages,issues:e.issueCount,duration:e.duration,os:process.platform,node:process.version,ts:(new Date).toISOString()}),n=require("https").request({hostname:"thuban-telemetry.silverwingsbenefits.workers.dev",path:"/report",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(o)},timeout:3e3});n.on("error",()=>{}),n.write(o),n.end()}catch{}}async function cmdTelemetry(e){const o=getTelemetryConfigPath(),n=process.argv.slice(2);if(n.includes("--on"))fs.writeFileSync(o,JSON.stringify({enabled:!0,updated:(new Date).toISOString()})),console.log(""),console.log(c("cyan"," Telemetry enabled")),console.log(c("gray"," Anonymous usage stats will be sent (no code, no paths, no PII)")),console.log(c("gray"," Turn off anytime: npx thuban telemetry --off")),console.log("");else if(n.includes("--off"))fs.writeFileSync(o,JSON.stringify({enabled:!1,updated:(new Date).toISOString()})),console.log(""),console.log(c("cyan"," Telemetry disabled")),console.log(c("gray"," No data will be collected")),console.log("");else{const e=isTelemetryEnabled();console.log(""),console.log(c("bold"," TELEMETRY STATUS")),console.log(""),console.log(` Status: ${e?c("cyan","Enabled"):c("gray","Disabled (default)")}`),console.log(""),console.log(c("gray"," Thuban telemetry is 100% opt-in and anonymous.")),console.log(c("gray"," We collect: file count, score, grade, languages, OS, scan duration.")),console.log(c("gray"," We never collect: code, file names, paths, project names, or PII.")),console.log(""),console.log(` Enable: ${c("cyan","npx thuban telemetry --on")}`),console.log(` Disable: ${c("cyan","npx thuban telemetry --off")}`),console.log("")}}async function runScanSilent(e){const o=/^(https?:\/\/|git@)/.test(e);let n=o?e:path.resolve(e),c=null,l=e;if(o){const o=path.join(os.tmpdir(),"thuban-compare-"+Date.now()+"-"+Math.random().toString(36).slice(2,6)),{execFileSync:s}=require("child_process");s("git",["clone","--depth","1",e,o],{stdio:"pipe",timeout:6e4}),n=o,c=o;const t=e.replace(/\.git$/,"").split("/");l=t[t.length-1]||e}else l=path.basename(path.resolve(e))||e;const s=Date.now(),t=new CodeScanner,a=new DependencyGraph,r=new HallucinationDetector({rootPath:n}),i=collectFiles(n,[]),g={};let d=0,h=0;for(const e of i)try{const o=t.scanFile(e);path.relative(n,e),g[e]=o,a.addFile(e,n),o.motherCode&&o.motherCode.hasDNA&&d++,o.drifts&&o.drifts.length>0&&h++}catch(e){}const u=r.scan(i,n),y=Date.now()-s;let p=0,f=0,m=0;const b={};for(const[,e]of Object.entries(g))if(e.issues){p+=e.issues.length;for(const o of e.issues){"critical"===o.severity&&f++,"high"===o.severity&&m++;const e=o.category||o.type||"other";b[e]=(b[e]||0)+1}}const $=(u.phantomAPIs||[]).length+(u.phantomImports||[]).length+(u.deprecatedAPIs||[]).length;p+=$,f+=(u.phantomAPIs||[]).length+(u.phantomImports||[]).length,m+=(u.deprecatedAPIs||[]).length,$>0&&(b.hallucination=$);const w=a.getOrphanFiles(),v=a.circularDeps||[],S=i.length>0?Math.round(d/i.length*100):0,C=Math.max(0,Math.round(100-15*f-5*m-10*v.length-1*w.length-.1*(100-S)-3*h)),x=C>=90?"A":C>=80?"B":C>=70?"C":C>=60?"D":"F";if(c)try{fs.rmSync(c,{recursive:!0,force:!0})}catch{}return{label:l,files:i.length,score:C,grade:x,elapsed:y,issues:{total:p,critical:f,high:m},categories:b,dependencies:{circular:v.length,orphans:w.length},motherCode:{annotated:d,coverage:S,drifted:h}}}async function cmdCompare(e){const o=process.argv.slice(2).filter(e=>"compare"!==e&&!e.startsWith("--"));o.length<2&&(console.log(""),console.log(c("red"," Compare requires two paths or URLs")),console.log(""),console.log(c("gray"," Usage:")),console.log(` ${c("cyan","npx thuban compare ./project-a ./project-b")}`),console.log(` ${c("cyan","npx thuban compare . https://github.com/user/repo")}`),console.log(` ${c("cyan","npx thuban compare https://github.com/a/repo https://github.com/b/repo")}`),console.log(""),process.exit(1)),console.log(""),console.log(c("bold"," ╔══════════════════════════════════════╗")),console.log(c("bold"," ║ THUBAN — Codebase Comparison ║")),console.log(c("bold"," ╚══════════════════════════════════════╝")),console.log(""),console.log(c("cyan",` Scanning: ${o[0]}`));const n=await runScanSilent(o[0]);console.log(c("cyan",` Scanning: ${o[1]}`));const l=await runScanSilent(o[1]);console.log("");const s=(e,o)=>String(e).padEnd(o),t=(e,o)=>String(e).padStart(o),a=20,r=n.label.length>a?n.label.slice(0,18)+"..":n.label,i=l.label.length>a?l.label.slice(0,18)+"..":l.label,g=n.score>=80?"green":n.score>=60?"yellow":"red",d=l.score>=80?"green":l.score>=60?"yellow":"red";console.log(c("bold"," ┌──────────────────────┬──────────────────────┬──────────────────────┐")),console.log(c("bold",` │ ${s("METRIC",a)} │ ${s(r,a)} │ ${s(i,a)} │`)),console.log(c("bold"," ├──────────────────────┼──────────────────────┼──────────────────────┤"));const h=(e,o,n)=>{console.log(` │ ${c("gray",s(e,a))} │ ${s(o,a)} │ ${s(n,a)} │`)};h("Health Score",`${c(g,n.score+"/100")}`,`${c(d,l.score+"/100")}`),h("Grade",`${c(g,n.grade)}`,`${c(d,l.grade)}`),h("Files Scanned",String(n.files),String(l.files)),h("Total Issues",String(n.issues.total),String(l.issues.total)),h("Critical Issues",String(n.issues.critical),String(l.issues.critical)),h("High Issues",String(n.issues.high),String(l.issues.high)),h("Circular Deps",String(n.dependencies.circular),String(l.dependencies.circular)),h("Orphan Files",String(n.dependencies.orphans),String(l.dependencies.orphans)),h("Mother Code DNA",`${n.motherCode.coverage}%`,`${l.motherCode.coverage}%`),h("Drift Issues",String(n.motherCode.drifted),String(l.motherCode.drifted)),h("Scan Time",`${n.elapsed}ms`,`${l.elapsed}ms`),console.log(c("bold"," └──────────────────────┴──────────────────────┴──────────────────────┘")),console.log("");const u=n.score-l.score;if(0===u)console.log(c("cyan",` VERDICT: Both codebases score identically (${n.score}/100)`));else{const e=u>0?n:l,o=u>0?l:n;console.log(c("cyan",` VERDICT: ${e.label} is healthier`)),console.log(c("gray",` ${e.label} scores ${e.score}/100 (${e.grade}) vs ${o.label} at ${o.score}/100 (${o.grade})`)),console.log(c("gray",` ${Math.abs(u)} point difference — ${Math.abs(u)>20?"significant gap":Math.abs(u)>10?"moderate gap":"close race"}`))}const y=new Set([...Object.keys(n.categories),...Object.keys(l.categories)]);if(y.size>0){console.log(""),console.log(c("bold"," ISSUE BREAKDOWN"));for(const e of y){const o=n.categories[e]||0,a=l.categories[e]||0,g=e.charAt(0).toUpperCase()+e.slice(1);console.log(c("gray",` ${s(g,22)} ${t(o,5)} vs ${t(a,5)} ${o<a?c("green",`← ${r}`):o>a?c("green",`→ ${i}`):c("gray","tied")}`))}}console.log(""),console.log(c("gray",` Full scan: npx thuban scan ${o[0]}`)),console.log(c("gray",` Full scan: npx thuban scan ${o[1]}`)),console.log("")}async function main(){const e=parseArgs(process.argv.slice(2));if(e.command&&"help"!==e.command||(printHelp(),process.exit(0)),"version"===e.command){const e=JSON.parse(fs.readFileSync(path.join(__dirname,"package.json"),"utf-8"));console.log(`thuban v${e.version}`),process.exit(0)}["activate","status","upgrade","telemetry","compare","crucible"].includes(e.command)||e.targetPath.match(/^(https?:\/\/|git@)/)||fs.existsSync(e.targetPath)||(console.error(c("red",` Error: Path not found: ${e.targetPath}`)),process.exit(1));try{switch(e.command){case"scan":await cmdScan(e);break;case"deps":await cmdDeps(e);break;case"drift":await cmdDrift(e);break;case"inject":await cmdInject(e);break;case"health":case"report":await cmdReport(e);break;case"debt":await cmdDebt(e);break;case"fix":await cmdFix(e);break;case"hallucinate":case"hal":await cmdHallucinate(e);break;case"watch":await cmdWatch(e);break;case"monitor":await cmdMonitor(e);break;case"history":await cmdHistory(e);break;case"trend":await cmdTrend(e);break;case"dashboard":case"dash":await cmdDashboard(e);break;case"diff":await cmdDiff(e);break;case"activate":await cmdActivate(e);break;case"status":await cmdStatus(e);break;case"upgrade":cmdUpgrade();break;case"gate":await cmdGate(e);break;case"cost":await cmdCost(e);break;case"ghosts":await cmdGhosts(e);break;case"ai-score":case"aiscore":await cmdAIScore(e);break;case"clones":case"duplicates":await cmdClones(e);break;case"passport":await cmdPassport(e);break;case"executive":case"exec-report":case"pdf":await cmdExecutive(e);break;case"baseline":await cmdBaseline(e);break;case"telemetry":await cmdTelemetry(e);break;case"compare":await cmdCompare(e);break;case"crucible":await cmdCrucible(e);break;default:console.error(""),console.error(c("red",` Unknown command: ${e.command}`)),console.error("");const o=["scan","compare","deps","drift","inject","health","report","debt","fix","hallucinate","watch","dashboard","diff","gate","cost","ghosts","ai-score","clones","passport","executive","baseline","activate","status","upgrade","telemetry"].filter(o=>o.startsWith(e.command.slice(0,2))||o.includes(e.command));o.length>0&&(console.error(c("gray"," Did you mean: ")+c("cyan",o.join(", "))+c("gray","?")),console.error("")),console.error(c("gray"," Quick start:")),console.error(` ${c("cyan","npx thuban scan .")} Scan your project`),console.error(` ${c("cyan","npx thuban --help")} See all commands`),console.error(""),process.exit(1)}}catch(o){console.error(c("red",` Error: ${o.message}`)),e.verbose&&console.error(o.stack),process.exit(1)}}main();
|