thuban 0.4.7 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/cli.js +2 -0
- package/package.json +13 -13
- package/packages/crucible/README.md +93 -0
- package/{dist/packages → packages}/scanner/ai-confidence-scorer.js +1 -1
- package/{dist/packages → packages}/scanner/code-scanner.js +1 -1
- package/packages/scanner/drift-detector.js +1 -0
- package/packages/scanner/go-ast-analyzer.js +1 -0
- package/packages/scanner/hallucination-detector.js +1 -0
- package/packages/scanner/license-manager.js +1 -0
- package/packages/scanner/support-knowledge.js +1 -0
- package/packages/scanner/taint-tracker.js +1 -0
- package/packages/scanner/widget-generator.js +1 -0
- package/dist/LICENSE +0 -21
- package/dist/README.md +0 -437
- package/dist/cli.js +0 -2
- package/dist/package.json +0 -65
- package/dist/packages/scanner/drift-detector.js +0 -1
- package/dist/packages/scanner/go-ast-analyzer.js +0 -1
- package/dist/packages/scanner/hallucination-detector.js +0 -1
- package/dist/packages/scanner/license-manager.js +0 -1
- package/dist/packages/scanner/support-knowledge.js +0 -1
- package/dist/packages/scanner/taint-tracker.js +0 -1
- package/dist/packages/scanner/widget-generator.js +0 -1
- /package/{dist/packages → packages}/crucible/.golden/golden-master.json +0 -0
- /package/{dist/packages → packages}/crucible/badge-generator.js +0 -0
- /package/{dist/packages → packages}/crucible/banner.js +0 -0
- /package/{dist/packages → packages}/crucible/ci-integration.js +0 -0
- /package/{dist/packages → packages}/crucible/golden-master.js +0 -0
- /package/{dist/packages → packages}/crucible/index.js +0 -0
- /package/{dist/packages → packages}/crucible/kenny-mode.js +0 -0
- /package/{dist/packages → packages}/crucible/leaderboard.js +0 -0
- /package/{dist/packages → packages}/crucible/mutation-engine.js +0 -0
- /package/{dist/packages → packages}/crucible/pattern-learner.js +0 -0
- /package/{dist/packages → packages}/crucible/report-generator.js +0 -0
- /package/{dist/packages → packages}/crucible/rule-loader.js +0 -0
- /package/{dist/packages → packages}/crucible/rules/code-scanner-core.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/command-injection.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/crypto-misuse.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/deserialization.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/env-injection.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/eval-abuse.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/file-upload.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/hallucination.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/hardcoded-secret.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/hardcoded-url.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/insecure-crypto.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/integer-overflow.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/log-injection.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/mass-assignment.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/open-redirect.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/path-traversal.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/prototype-pollution.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/sql-injection.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/ssrf.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/timing-attack.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/unsafe-block.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/xss.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/xxe.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/yaml-deserialization.json +0 -0
- /package/{dist/packages → packages}/crucible/rules/yaml-injection.json +0 -0
- /package/{dist/packages → packages}/crucible/seeding-engine.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-001.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-002.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-003.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-004.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-005.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-006.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-007.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-008.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-009.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-010.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-011.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-012.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-013.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-014.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-015.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-016.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-017.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-018.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-019.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-020.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-021.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-022.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-023.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-024.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-025.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-026.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-027.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-028.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-029.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-030.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-031.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-032.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-033.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-034.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-035.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-036.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-037.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-038.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-039.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-040.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-041.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-042.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-043.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-044.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-045.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-046.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-047.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-048.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-049.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-050.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-051.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/csharp/seed-052.cs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-001.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-002.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-003.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-004.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-005.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-006.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-007.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-008.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-009.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-010.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-011.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-012.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-013.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-014.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-015.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-016.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-017.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-018.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-019.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-020.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-021.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-022.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-023.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-024.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-025.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-026.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-027.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-028.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-029.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-030.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-031.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-032.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-033.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-034.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-035.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-036.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-037.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-038.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-039.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-040.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-041.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-042.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-043.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-044.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-045.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-046.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-047.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-048.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-049.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-050.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-051.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/go/seed-052.go +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-001.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-002.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-003.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-004.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-005.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-006.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-007.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-008.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-009.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-010.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-011.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-012.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-013.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-014.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-015.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-016.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-017.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-018.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-019.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-020.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-021.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-022.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-023.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-024.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-025.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-026.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-027.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-028.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-029.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-030.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-031.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-032.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-033.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-034.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-035.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-036.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-037.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-038.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-039.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-040.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-041.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-042.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-043.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-044.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-045.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-046.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-047.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-048.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-049.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-050.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-051.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/java/seed-052.java +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-001.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-002.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-003.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-004.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-005.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-006.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-007.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-008.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-009.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-010.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-011.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-012.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-013.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-014.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-015.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-016.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-017.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-018.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-019.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-020.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-021.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-022.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-023.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-024.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-025.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-026.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-027.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-028.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-029.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-030.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-031.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-032.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-033.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-034.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-035.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-036.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-037.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-038.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-039.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-040.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-041.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-042.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-043.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-044.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-045.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-046.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-047.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-048.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-049.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-050.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-051.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-052.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-053.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-054.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/js/seed-055.js +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-001.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-002.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-003.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-004.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-005.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-006.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-007.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-008.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-009.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-010.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-011.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-012.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-013.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-014.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-015.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-016.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-017.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-018.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-019.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-020.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-021.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-022.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-023.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-024.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-025.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-026.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-027.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-028.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-029.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-030.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-031.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-032.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-033.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-034.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-035.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-036.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-037.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-038.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-039.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-040.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-041.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-042.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-043.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-044.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-045.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-046.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-047.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-048.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-049.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/kotlin/seed-050.kt +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-001.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-002.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-003.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-004.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-005.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-006.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-007.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-008.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-009.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-010.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-011.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-012.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-013.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-014.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-015.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-016.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-017.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-018.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-019.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-020.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-021.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-022.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-023.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-024.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-025.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-026.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-027.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-028.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-029.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-030.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-031.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-032.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-033.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-034.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-035.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-036.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-037.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-038.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-039.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-040.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-041.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-042.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-043.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-044.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-045.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-046.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-047.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-048.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-049.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/php/seed-050.php +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-001.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-002.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-003.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-004.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-005.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-006.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-007.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-008.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-009.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-010.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-011.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-012.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-013.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-014.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-015.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-016.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-017.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-018.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-019.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-020.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-021 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-021.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-022 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-022.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-023 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-023.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-024 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-024.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-025 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-025.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-026 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-026.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-027 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-027.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-028 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-028.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-029.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-030 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-030.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-031 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-031.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-032.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-033.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-034.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-035.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-036 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-036.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-037 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-037.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-038 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-038.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-039 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-039.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-040 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-040.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-041 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-041.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-042 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-042.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-043 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-043.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-044 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-044.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-045 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-045.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-046 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-046.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-047 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-047.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-048 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-048.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-049 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-049.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-050 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-050.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-051 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-051.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-052 2.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/python/seed-052.py +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-001 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-001.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-002 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-002.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-003 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-003.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-004 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-004.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-005 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-005.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-006 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-006.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-007 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-007.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-008 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-008.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-009 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-009.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-010 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-010.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-011 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-011.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-012 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-012.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-013 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-013.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-014 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-014.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-015 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-015.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-016 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-016.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-017 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-017.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-018 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-018.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-019 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-019.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-020 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-020.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-021 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-021.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-022 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-022.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-023 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-023.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-024 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-024.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-025 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-025.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-026 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-026.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-027 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-027.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-028 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-028.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-029 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-029.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-030 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-030.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-031 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-031.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-032 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-032.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-033 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-033.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-034 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-034.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-035 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-035.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-036 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-036.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-037 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-037.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-038 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-038.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-039 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-039.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-040 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-040.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-041 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-041.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-042 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-042.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-043 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-043.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-044 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-044.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-045 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-045.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-046 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-046.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-047 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-047.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-048 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-048.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-049 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-049.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-050 2.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ruby/seed-050.rb +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-001 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-001.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-002 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-002.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-003 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-003.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-004 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-004.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-005 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-005.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-006 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-006.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-007 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-007.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-008 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-008.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-009 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-009.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-010 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-010.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-011 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-011.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-012 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-012.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-013 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-013.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-014 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-014.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-015 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-015.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-016 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-016.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-017 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-017.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-018 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-018.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-019 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-019.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-020 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-020.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-021 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-021.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-022 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-022.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-023 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-023.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-024 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-024.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-025 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-025.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-026 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-026.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-027 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-027.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-028 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-028.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-029 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-029.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-030 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-030.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-031 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-031.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-032 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-032.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-033 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-033.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-034 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-034.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-035 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-035.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-036 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-036.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-037 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-037.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-038 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-038.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-039 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-039.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-040 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-040.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-041 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-041.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-042 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-042.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-043 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-043.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-044 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-044.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-045 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-045.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-046 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-046.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-047 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-047.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-048 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-048.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-049 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-049.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-050 2.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/rust/seed-050.rs +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-001 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-001.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-002 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-002.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-003 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-003.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-004 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-004.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-005 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-005.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-006 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-006.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-007 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-007.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-008 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-008.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-009 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-009.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-010 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-010.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-011 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-011.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-012 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-012.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-013 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-013.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-014 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-014.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-015 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-015.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-016 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-016.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-017 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-017.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-018 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-018.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-019 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-019.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-020 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-020.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-021 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-021.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-022 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-022.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-023 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-023.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-024 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-024.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-025 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-025.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-026 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-026.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-027 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-027.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-028 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-028.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-029 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-029.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-030 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-030.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-031 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-031.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-032 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-032.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-033 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-033.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-034 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-034.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-035 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-035.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-036 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-036.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-037 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-037.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-038 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-038.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-039 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-039.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-040 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-040.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-041 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-041.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-042 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-042.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-043 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-043.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-044 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-044.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-045 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-045.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-046 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-046.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-047 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-047.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-048 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-048.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-049 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-049.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-050 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-050.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-051 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-051.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-052 2.ts +0 -0
- /package/{dist/packages → packages}/crucible/seeds/ts/seed-052.ts +0 -0
- /package/{dist/packages → packages}/crucible/self-attack.js +0 -0
- /package/{dist/packages → packages}/scanner/alert-manager.js +0 -0
- /package/{dist/packages → packages}/scanner/ast-analyzer.js +0 -0
- /package/{dist/packages → packages}/scanner/baseline-manager.js +0 -0
- /package/{dist/packages → packages}/scanner/cfg-analyzer.js +0 -0
- /package/{dist/packages → packages}/scanner/codebase-passport.js +0 -0
- /package/{dist/packages → packages}/scanner/copy-paste-detector.js +0 -0
- /package/{dist/packages → packages}/scanner/dependency-graph.js +0 -0
- /package/{dist/packages → packages}/scanner/executive-report.js +0 -0
- /package/{dist/packages → packages}/scanner/export-verifier.js +0 -0
- /package/{dist/packages → packages}/scanner/feedback-client.js +0 -0
- /package/{dist/packages → packages}/scanner/file-collector.js +0 -0
- /package/{dist/packages → packages}/scanner/file-watcher.js +0 -0
- /package/{dist/packages → packages}/scanner/ghost-code-detector.js +0 -0
- /package/{dist/packages → packages}/scanner/health-checker.js +0 -0
- /package/{dist/packages → packages}/scanner/html-report.js +0 -0
- /package/{dist/packages → packages}/scanner/index.js +0 -0
- /package/{dist/packages → packages}/scanner/investor-report.js +0 -0
- /package/{dist/packages → packages}/scanner/master-health-checker.js +0 -0
- /package/{dist/packages → packages}/scanner/monitor-notifier.js +0 -0
- /package/{dist/packages → packages}/scanner/monitor-service.js +0 -0
- /package/{dist/packages → packages}/scanner/monitor-store.js +0 -0
- /package/{dist/packages → packages}/scanner/pre-commit-gate.js +0 -0
- /package/{dist/packages → packages}/scanner/python-ast-analyzer.js +0 -0
- /package/{dist/packages → packages}/scanner/python_ast_helper.py +0 -0
- /package/{dist/packages → packages}/scanner/read-file.js +0 -0
- /package/{dist/packages → packages}/scanner/scan-diff.js +0 -0
- /package/{dist/packages → packages}/scanner/scan-runner.js +0 -0
- /package/{dist/packages → packages}/scanner/secret-scanner.js +0 -0
- /package/{dist/packages → packages}/scanner/sentinel-core.js +0 -0
- /package/{dist/packages → packages}/scanner/sentinel-knowledge.js +0 -0
- /package/{dist/packages → packages}/scanner/slack-notifier.js +0 -0
- /package/{dist/packages → packages}/scanner/support-bot.js +0 -0
- /package/{dist/packages → packages}/scanner/tech-debt-analyzer.js +0 -0
- /package/{dist/packages → packages}/scanner/tech-debt-cost.js +0 -0
package/dist/cli.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const path=require("path"),fs=require("fs"),os=require("os"),_CLI_VERSION=JSON.parse(fs.readFileSync(path.join(__dirname,"package.json"),"utf-8")).version,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"),InvestorReport=require("./packages/scanner/investor-report.js"),SupportBot=require("./packages/scanner/support-bot.js"),FeedbackClient=require("./packages/scanner/feedback-client.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",` v${_CLI_VERSION} · 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"," INVESTOR")),console.log(""),console.log(` ${c("cyan","investor-report")} [path] Board-ready due diligence report ${c("gray","(--key=XXX for full)")}`),console.log(` ${c("gray"," Free: score + verdict | $99 Snapshot: + risk matrix | $399 Full: everything")}`),console.log(""),console.log(c("bold"," SUPPORT & FEEDBACK")),console.log(""),console.log(` ${c("cyan","support")} Interactive diagnostic assistant`),console.log(` ${c("cyan","support")} ${c("gray","--diagnose")} Run full system diagnostic`),console.log(` ${c("cyan","feedback")} ${c("gray",'"message"')} Report a bug or request a feature`),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"," # Generate an investor due diligence report")),console.log(` ${c("white",'npx thuban investor-report . --company-name="Acme Corp"')}`),console.log(""),console.log(c("gray"," # Get help from the support assistant")),console.log(` ${c("white","npx thuban support")}`),console.log(""),console.log(c("gray"," Report a bug or request a feature:")),console.log(` ${c("white",'npx thuban feedback "your message here"')}`),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,companyName:null,feedbackText:null,diagnoseOnly:!1,smart:!1,reportKey:null},n=["activate","status","upgrade","help","version","support","feedback"];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:"--diagnose"===l?o.diagnoseOnly=!0:"--smart"===l?o.smart=!0:l.startsWith("--key=")?o.reportKey=l.split("=").slice(1).join("="):"--key"===l&&e[c+1]?o.reportKey=e[++c]:l.startsWith("--company-name=")?o.companyName=l.split("=").slice(1).join("="):"--company-name"===l&&e[c+1]?o.companyName=e[++c]:"--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?"feedback"!==o.command||o.feedbackText?n.includes(o.command)||(l.match(/^(https?:\/\/|git@)/)?o.targetPath=l:o.targetPath=path.resolve(l)):o.feedbackText=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,y=a.maxFiles<1/0?g.slice(0,a.maxFiles):g,u=d>a.maxFiles,h=u?summarizeRemainingFiles(y,g,l):null;if(!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 ${y.length} files to scan...`)),console.log("")),0===y.length)return e.json?void console.log(JSON.stringify({files:0,filesScanned:0,elapsed_ms:Date.now()-o,tier:t.getTier(),issues:[],totalIssues:0,score:null,grade:"N/A",warning:"No scannable files found. Thuban deeply analyses: JavaScript, TypeScript, Python, Go, Rust, Java, Kotlin, C#, PHP, Ruby. Other file types are not yet supported.",supportedExtensions:[".js",".ts",".jsx",".tsx",".mjs",".cjs",".py",".go",".rs",".java",".kt",".cs",".php",".rb"]},null,2)):(console.log(c("yellow"," ╔══════════════════════════════════════════════════════╗")),console.log(c("yellow"," ║")+c("bold"," NO SCANNABLE FILES FOUND ")+c("yellow","║")),console.log(c("yellow"," ╠══════════════════════════════════════════════════════╣")),console.log(c("yellow"," ║")+" "+c("yellow","║")),console.log(c("yellow"," ║")+c("bold"," Thuban cannot score this project. ")+" "+c("yellow","║")),console.log(c("yellow"," ║")+" No files matched the supported language list. "+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("cyan","Deeply analysed:")+" "+c("yellow","║")),console.log(c("yellow"," ║")+" JS · TS · Python · Go · Rust · Java "+c("yellow","║")),console.log(c("yellow"," ║")+" Kotlin · C# · PHP · Ruby "+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("gray","More languages coming soon. Request yours at")+" "+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("cyan",'thuban feedback "Please add <language>"')+" "+c("yellow","║")),console.log(c("yellow"," ║")+" "+c("yellow","║")),console.log(c("yellow"," ╚══════════════════════════════════════════════════════╝")),void 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(y),f.scan(y)]),$=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:y.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:h?h.remainingCount:0,remainingDirectories:h?h.topDirectories:[],remainingPreview:h?h.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),T=Math.max(0,100-15*S.length-5*C.length-2*D.length-.5*A.length-.25*E.length),R=T>=90?"A":T>=80?"B":T>=70?"C+":T>=60?"C":T>=50?"D+":T>=40?"D":"F",N=T>=80?"green":T>=60?"yellow":"red",F=w.filter(e=>!1!==e.fixable).length;console.log(c("cyan"," ╔══════════════════════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold"," THUBAN SCAN RESULTS ")+c("cyan","║")),console.log(c("cyan"," ║")+c("gray",` v${_CLI_VERSION} · Public Beta `)+c("cyan","║")),console.log(c("cyan"," ╠══════════════════════════════════════════════════════╣")),console.log(c("cyan"," ║")+` Files scanned: ${c("bold",String(y.length).padEnd(6))}`+(u?c("yellow",` of ${d}`):" ")+c("cyan"," ║")),console.log(c("cyan"," ║")+` Health score: ${c(N,(R+" ("+Math.round(T)+"/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("");const k=t.getTier();if("trial"===k&&t._trialInfo){const{daysRemaining:e,expiresAt:o}=t._trialInfo,n=e<=3?"red":e<=7?"yellow":"cyan",l=new Date(o).toLocaleDateString("en-GB",{day:"numeric",month:"long",year:"numeric"});console.log(c(n,` Trial: ${e} day${1===e?"":"s"} remaining (expires ${l})`)),e<=7&&console.log(c("gray"," Love it? Upgrade at: ")+c("cyan","https://thuban.dev/pricing")),console.log("")}else"free"===k&&t._trialExpired&&(console.log(c("yellow"," Your Thuban trial has expired. Upgrade to continue:")),console.log(c("cyan"," https://thuban.dev/pricing")),console.log(""));if(y.some(e=>!(e.endsWith(".js")||e.endsWith(".ts")||e.endsWith(".jsx")||e.endsWith(".tsx")||e.endsWith(".mjs")))){const e=[...new Set(y.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").replace(/\r\n/g,"\n").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"," ┌──────────────────────────────────────────────────────┐")),T<60?console.log(c("bold"," │ ")+c("red","YOUR CODEBASE HAS A SERIOUS HEALTH PROBLEM ")+c("bold"," │")):T<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(N,R+" ("+Math.round(T)+"/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:y.length,totalCount:d,remainingSummary:h,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").replace(/\r\n/g,"\n");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 y;if(y=".py"===d||".rb"===d?g.replace(/^\/\*\*\r?\n/,"").replace(/\s*\*\/\s*$/,"").split(/\r?\n/).map(e=>e.replace(/^\s*\*\s?/,"# ")).join("\n"):".go"===d||".rs"===d?g.replace(/^\/\*\*\r?\n/,"").replace(/\s*\*\/\s*$/,"").split(/\r?\n/).map(e=>e.replace(/^\s*\*\s?/,"// ")).join("\n"):g,e.fix){let s;if(".php"===d&&n.trimStart().startsWith("<?php")){const e=n.indexOf("<?php")+5,o=n.slice(e);s=n.slice(0,e)+"\n"+y+"\n"+o}else s=y+"\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:y}),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(/\r?\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 y=0,u=0,h=0;for(const e of r.issues||[])y++,"critical"===e.severity&&u++,"high"===e.severity&&h++;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*h-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:y,critical:u,high:h},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: ${y}`),console.log(` Critical: ${u>0?c("red",u):c("green","0")}`),console.log(` High: ${h>0?c("red",h):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),y=await g.writeReport(s,a,{projectName:d,hallucinations:i});e.json?console.log(JSON.stringify({outputPath:y,scores:s.scores,stats:s.stats},null,2)):(console.log(c("green"," ✓ Dashboard generated:")),console.log(` ${c("cyan",y)}`),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(/\r?\n/).filter(Boolean),...s.split(/\r?\n/).filter(Boolean),...t.split(/\r?\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);if(l.success)if("trial"===l.tier){const e=new Date(l.expiresAt).toLocaleDateString("en-GB",{day:"numeric",month:"long",year:"numeric"});console.log(c("cyan"," ╔══════════════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold"," Trial activated — Pro features unlocked! ")+c("cyan","║")),console.log(c("cyan"," ╚══════════════════════════════════════════════╝")),console.log(""),console.log(` Tier: ${c("bold","Trial (Pro features)")}`),console.log(` Status: ${c("green","Active")}`),console.log(` Days left: ${c("cyan",l.daysRemaining+" days")}`),console.log(` Expires: ${c("gray",e)}`),console.log(""),console.log(c("gray"," Unlimited scans, all languages, full security reports.")),console.log(c("gray"," Run ")+c("cyan","npx thuban scan .")+c("gray"," to get started.")),console.log(""),console.log(c("gray"," Love it? Upgrade at: ")+c("cyan","https://thuban.dev/pricing")),console.log("")}else 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("");else console.log(c("red"," Invalid license key.")),console.log(""),l.error&&l.error.includes("expired")?console.log(c("yellow",` ${l.error}`)):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();if(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)}`),"trial"===o.tier&&void 0!==o.trialDaysRemaining){const e=new Date(o.trialExpiresAt).toLocaleDateString("en-GB",{day:"numeric",month:"long",year:"numeric"}),n=o.trialDaysRemaining<=3?"red":o.trialDaysRemaining<=7?"yellow":"cyan";console.log(""),console.log(c("cyan"," ╔══════════════════════════════════════════════════════╗")),console.log(c("cyan"," ║")+c("bold"," TRIAL KEY ACTIVE ")+c("cyan","║")),console.log(c("cyan"," ╠══════════════════════════════════════════════════════╣")),console.log(c("cyan"," ║")+` Trial expires: ${c(n,e.padEnd(36))}`+c("cyan"," ║")),console.log(c("cyan"," ║")+` Days remaining: ${c(n,String(o.trialDaysRemaining).padEnd(35))}`+c("cyan","║")),console.log(c("cyan"," ║")+" Love it? Upgrade to keep full access: "+c("cyan","║")),console.log(c("cyan"," ║")+" "+c("bold","https://thuban.dev/pricing")+" "+c("cyan","║")),console.log(c("cyan"," ╚══════════════════════════════════════════════════════╝"))}else o.trialExpired&&(console.log(""),console.log(c("yellow"," Your Thuban trial has expired.")),console.log(c("gray"," Upgrade to keep unlimited scans and full reports:")),console.log(c("cyan"," https://thuban.dev/pricing")));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}),s=await l.scan(n);if(e.json)console.log(JSON.stringify(s,null,2));else{if(0===s.highConfidence.length&&0===s.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 (${s.highConfidence.length} functions)`))),console.log("");for(const e of s.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(s.mediumConfidence.length>0){console.log(c("yellow",c("bold",` POSSIBLE AI-GENERATED (${s.mediumConfidence.length} functions)`))),console.log("");for(const e of s.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",s.aiPercentage+"%")} of functions are likely AI-generated `+c("bold","│")),console.log(c("bold"," │")+` ${c("yellow",s.aiLikelyCount)} high confidence | ${s.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,y,u]=await Promise.all([l.scanFiles(n),s.scan(n),t.scan(n),a.scan(n),r.scan(n)]);let h=0;for(const e of n)try{h+=fs.readFileSync(e,"utf-8").replace(/\r\n/g,"\n").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:y,cloneResults:u,fileCount:n.length,lineCount:h}),$=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 cmdInvestorReport(e){const o=path.resolve(e.targetPath);banner(),console.log(c("bold"," GENERATING INVESTOR DUE DILIGENCE REPORT")),console.log(c("cyan",` Target: ${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,y,u]=await Promise.all([l.scanFiles(n),s.scan(n),t.scan(n),a.scan(n),r.scan(n)]);let h=0;for(const e of n)try{h+=fs.readFileSync(e,"utf-8").replace(/\r\n/g,"\n").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 InvestorReport({rootPath:o,companyName:e.companyName||void 0,reportKey:e.reportKey||void 0}),b="full"===m.tier?"Full Audit":"snapshot"===m.tier?"Snapshot":"Preview (free)";console.log(` ${c("bold","Tier:")} ${c("free"===m.tier?"yellow":"green",b)}`),"free"===m.tier&&console.log(c("yellow"," ⚠ Free preview — some sections locked. Purchase a key at thuban.dev")),console.log("");const $=m.generate({scanResults:i,hallResults:g,debtCost:f,ghostResults:d,aiScoreResults:y,cloneResults:u,fileCount:n.length,lineCount:h}),w=m.save($,o);console.log(c("green"," ✓ Investor report generated!")),console.log(""),console.log(` ${c("bold","Report:")} ${c("cyan",w)}`),console.log(""),console.log(c("gray"," Open in browser → Ctrl+P → Save as PDF for board presentations")),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"} "${w}"`),console.log(c("green"," ✓ Opened in your default browser.")),console.log("")}catch(e){}}async function cmdSupport(e){const o=new SupportBot({rootPath:e.targetPath,verbose:e.verbose,smart:e.smart});if(e.diagnoseOnly)return banner(),console.log(c("bold"," SYSTEM DIAGNOSTIC")),console.log(""),void await o.diagnose();const n=process.argv.slice(3).filter(e=>!e.startsWith("--"));if(n.length>0){banner();const l=n.join(" "),s=e.smart?await o.queryAsync(l):o.query(l);return"none"===s.type?(console.log(c("yellow",` No exact match found for: "${l}"`)),console.log(""),console.log(c("gray"," Try running:")),console.log(` ${c("cyan","thuban support")} Interactive help`),console.log(` ${c("cyan","thuban support --diagnose")} System diagnostic`)):(console.log(c("green",` Found: ${s.type}`)),console.log(""),s.data&&(s.data.answer?console.log(` ${s.data.answer}`):s.data.fix?console.log(` ${c("bold","Fix:")} ${s.data.fix}`):s.data.description&&console.log(` ${s.data.description}`))),void console.log("")}await o.startInteractive()}async function cmdFeedback(e){const o=new FeedbackClient;if(process.argv.includes("--retry")){banner(),console.log(c("bold"," RETRYING PENDING FEEDBACK")),console.log("");const e=await o.retryPending();return console.log(c("green",` ✓ Sent ${e.sent}/${e.total} pending items`)),e.failed>0&&console.log(c("yellow",` ⚠ ${e.failed} items still pending (will retry next time)`)),void console.log("")}if(e.feedbackText){const n=process.argv.includes("--bug")?"bug":process.argv.includes("--feature")?"feature":"general";return void await o.submit(e.feedbackText,n)}await o.startInteractive()}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:_CLI_VERSION})),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 y=Crucible.compareGolden(d);return y.hasMaster?console.log(y.passed?c("green"," ✓ No regressions vs golden master"):c("red",` ✗ ${y.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||_CLI_VERSION,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,y=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&&y++}catch(e){}const u=r.scan(i,n),h=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*y)),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:h,issues:{total:p,critical:f,high:m},categories:b,dependencies:{circular:v.length,orphans:w.length},motherCode:{annotated:d,coverage:S,drifted:y}}}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 y=(e,o,n)=>{console.log(` │ ${c("gray",s(e,a))} │ ${s(o,a)} │ ${s(n,a)} │`)};y("Health Score",`${c(g,n.score+"/100")}`,`${c(d,l.score+"/100")}`),y("Grade",`${c(g,n.grade)}`,`${c(d,l.grade)}`),y("Files Scanned",String(n.files),String(l.files)),y("Total Issues",String(n.issues.total),String(l.issues.total)),y("Critical Issues",String(n.issues.critical),String(l.issues.critical)),y("High Issues",String(n.issues.high),String(l.issues.high)),y("Circular Deps",String(n.dependencies.circular),String(l.dependencies.circular)),y("Orphan Files",String(n.dependencies.orphans),String(l.dependencies.orphans)),y("Mother Code DNA",`${n.motherCode.coverage}%`,`${l.motherCode.coverage}%`),y("Drift Issues",String(n.motherCode.drifted),String(l.motherCode.drifted)),y("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 h=new Set([...Object.keys(n.categories),...Object.keys(l.categories)]);if(h.size>0){console.log(""),console.log(c("bold"," ISSUE BREAKDOWN"));for(const e of h){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","support","feedback"].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;case"investor-report":case"investor":await cmdInvestorReport(e);break;case"support":case"help-me":await cmdSupport(e);break;case"feedback":await cmdFeedback(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","investor-report","support","feedback"].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();
|
package/dist/package.json
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "thuban",
|
|
3
|
-
"version": "0.4.7",
|
|
4
|
-
"description": "The safety layer for AI-coded software. Detect hallucinated APIs, ghost code, tech debt, and architecture drift. One command. Minimal dependencies.",
|
|
5
|
-
"bin": {
|
|
6
|
-
"thuban": "./dist/cli.js"
|
|
7
|
-
},
|
|
8
|
-
"scripts": {
|
|
9
|
-
"scan": "node cli.js scan",
|
|
10
|
-
"test": "node build.js && node --test tests/build-integrity.test.js tests/crlf-safety.test.js tests/windows-paths.test.js tests/npm-publish-smoke.test.js",
|
|
11
|
-
"test:all": "node --test tests/*.test.js packages/scanner/*.test.js packages/crucible/*.test.js",
|
|
12
|
-
"test:build": "node build.js && node --test tests/build-integrity.test.js tests/npm-publish-smoke.test.js",
|
|
13
|
-
"build": "node build.js",
|
|
14
|
-
"prepublishOnly": "npm run build && node --test tests/build-integrity.test.js tests/npm-publish-smoke.test.js"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"code-quality",
|
|
18
|
-
"static-analysis",
|
|
19
|
-
"ai-hallucination",
|
|
20
|
-
"hallucination-detection",
|
|
21
|
-
"ghost-code",
|
|
22
|
-
"tech-debt",
|
|
23
|
-
"ai-code-review",
|
|
24
|
-
"code-health",
|
|
25
|
-
"pre-commit",
|
|
26
|
-
"copilot",
|
|
27
|
-
"cursor",
|
|
28
|
-
"ai-safety",
|
|
29
|
-
"developer-tools",
|
|
30
|
-
"devtools",
|
|
31
|
-
"linter",
|
|
32
|
-
"code-scanner"
|
|
33
|
-
],
|
|
34
|
-
"author": "Silverwings Benefits <hello@thuban.dev>",
|
|
35
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
36
|
-
"homepage": "https://thuban.dev",
|
|
37
|
-
"repository": {
|
|
38
|
-
"type": "git",
|
|
39
|
-
"url": "https://github.com/SilverwingsBenefitsGit/thuban.git"
|
|
40
|
-
},
|
|
41
|
-
"bugs": {
|
|
42
|
-
"url": "https://github.com/SilverwingsBenefitsGit/thuban/issues"
|
|
43
|
-
},
|
|
44
|
-
"engines": {
|
|
45
|
-
"node": ">=16.0.0"
|
|
46
|
-
},
|
|
47
|
-
"files": [
|
|
48
|
-
"dist/cli.js",
|
|
49
|
-
"dist/packages/scanner/*.js",
|
|
50
|
-
"dist/packages/scanner/python_ast_helper.py",
|
|
51
|
-
"dist/packages/crucible/*.js",
|
|
52
|
-
"dist/packages/crucible/seeds/**",
|
|
53
|
-
"dist/packages/crucible/.golden/",
|
|
54
|
-
"dist/packages/crucible/rules/**",
|
|
55
|
-
"dist/README.md",
|
|
56
|
-
"dist/LICENSE",
|
|
57
|
-
"dist/package.json"
|
|
58
|
-
],
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"@babel/parser": "^7.29.7"
|
|
61
|
-
},
|
|
62
|
-
"devDependencies": {
|
|
63
|
-
"terser": "^5.48.0"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const fs=require("fs"),path=require("path"),EventEmitter=require("events");class DriftDetector extends EventEmitter{constructor(e={}){super(),this.config={rootPath:e.rootPath||process.cwd(),widgetPattern:e.widgetPattern||/\/\*\*[\s\S]*?@(purpose|module|layer|imports-from|exports-to|depends-on|critical-for)[\s\S]*?\*\//,ignorePatterns:e.ignorePatterns||["node_modules/**",".git/**","dist/**",".orion/snapshots/**"],...e},this.analysisCache=new Map}async detectAll(){const e=Date.now(),t={filesAnalyzed:0,filesWithWidgets:0,filesWithoutWidgets:0,issues:[],moduleMap:{},duration:0};try{const s=await this._discoverFiles(this.config.rootPath);for(const e of s){const s=await this.analyzeFile(e);t.filesAnalyzed++,s.hasWidget?t.filesWithWidgets++:(t.filesWithoutWidgets++,t.issues.push({file:e,category:"drift",severity:"info",id:"DRIFT001",name:"Missing Widget",message:"File has no widget declaration - add @purpose, @module, @layer etc."})),t.issues.push(...s.issues),s.module&&(t.moduleMap[s.module]||(t.moduleMap[s.module]=[]),t.moduleMap[s.module].push(e))}return t.issues.push(...this._analyzeCrossFile(t.moduleMap)),t.duration=Date.now()-e,t}catch(e){return console.error("[DRIFT-DETECTOR] Detection failed"),t.error="Detection failed",t}}async analyzeFile(e){const t={file:e,hasWidget:!1,widget:null,actualExports:[],actualImports:[],module:null,issues:[]};try{const s=fs.readFileSync(e,"utf8").replace(/\r\n/g,"\n");return t.widget=this._parseWidget(s),t.hasWidget=!!t.widget,t.actualExports=this._extractExports(s),t.actualImports=this._extractImports(s),t.widget&&(t.module=t.widget.module,t.issues.push(...this._compareWidgetToCode(e,t.widget,{exports:t.actualExports,imports:t.actualImports}))),t.drifts=t.issues,this.analysisCache.set(e,t),t}catch(s){const o="ENOENT"===s.code?"File not found":"EACCES"===s.code?"Permission denied":"Analysis error";return t.issues.push({file:e,category:"drift",severity:"error",id:"DRIFT000",message:`Failed to analyze file: ${o}`}),t.drifts=t.issues,t}}async checkFileDrift(e){const t=await this.analyzeFile(e);return{hasDrift:t.issues.length>0,issues:t.issues,widget:t.widget}}async suggestWidget(e){try{const t=fs.readFileSync(e,"utf8").replace(/\r\n/g,"\n"),s=this._extractExports(t),o=this._extractImports(t),r=path.relative(this.config.rootPath,e),i=r.split(path.sep)[0];let n="application";return r.includes("routes")||r.includes("api")?n="presentation":r.includes("core")||r.includes("engine")?n="infrastructure":(r.includes("model")||r.includes("domain"))&&(n="domain"),{purpose:s.length>0?`Provides ${s.join(", ")}`:"Unknown purpose - needs description",module:i,layer:n,importsFrom:o.map(e=>`${e.module} - ${e.specifiers.join(", ")}`),exportsTo:"To be determined",dataFlow:"To be documented",sideEffects:t.includes("fs.")?"File system operations":"None documented",criticalFor:"To be documented"}}catch(e){return{error:e.message}}}async _discoverFiles(e,t=[],s=0){if(s>100)return t;try{const o=fs.readdirSync(e,{withFileTypes:!0});for(const r of o){const o=path.join(e,r.name),i=path.relative(this.config.rootPath,o);this._shouldIgnore(i)||(r.isDirectory()?await this._discoverFiles(o,t,s+1):r.isFile()&&r.name.endsWith(".js")&&t.push(o))}}catch(e){}return t}_shouldIgnore(e){const t=e.replace(/\\/g,"/"),s=["node_modules",".git","dist",".vite"];for(const e of s)if(t.includes("/"+e+"/")||t.startsWith(e+"/")||t===e||t.endsWith("/"+e))return!0;for(const e of this.config.ignorePatterns){const s=e.replace(/\\/g,"/"),o=s.split("/")[0].replace(/\*/g,"");if(o&&(t===o||t.startsWith(o+"/")))return!0;let r=s.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/]*");if(new RegExp("^"+r).test(t))return!0}return!1}_parseWidget(e){const t=e.match(/\/\*\*[\s\S]*?\*\//);if(t){const e=t[0],s=this._extractWidgetFields(e,t=>{const s=e.match(new RegExp(`@${t}\\s+(.+?)(?=\\r?\\n\\s*\\*\\s*@|\\r?\\n\\s*\\*\\/|$)`,"s"));return s?s[1].trim().replace(/\n\s*\*\s*/g," ").trim():null});if(s)return s}const s=e.match(/"{3}[\s\S]*?@(?:purpose|module|layer)[\s\S]*?"{3}|'{3}[\s\S]*?@(?:purpose|module|layer)[\s\S]*?'{3}/);if(s){const e=s[0],t=this._extractWidgetFields(e,t=>{const s=e.match(new RegExp(`@${t}\\s+(.+?)(?=\\r?\\n\\s*@|$)`,"s"));return s?s[1].trim():null});if(t)return t}const o=e.match(/(?:^|\r?\n)((?:\s*#[^\r\n]*\r?\n)+)/);if(o){const e=o[0];if(/@(?:purpose|module|layer)/.test(e)){const t=this._extractWidgetFields(e,t=>{const s=e.match(new RegExp(`@${t}\\s+(.+?)(?=\\r?\\n\\s*#\\s*@|\\r?\\n[^#]|$)`));return s?s[1].trim():null});if(t)return t}}const r=e.match(/(?:^|\r?\n)((?:\s*\/\/[^\r\n]*\r?\n)+)/);if(r){const e=r[0];if(/@(?:purpose|module|layer)/.test(e)){const t=this._extractWidgetFields(e,t=>{const s=e.match(new RegExp(`@${t}\\s+(.+?)(?=\\r?\\n\\s*//\\s*@|\\r?\\n[^/]|$)`));return s?s[1].trim():null});if(t)return t}}return null}_extractWidgetFields(e,t){const s=["purpose","module","layer","imports-from","exports-to","data-flow","side-effects","depends-on-env","critical-for","known-issues","last-audit","last-modified"],o={};for(const e of s){const s=t(e);s&&(o[e.replace(/-/g,"_")]=s)}return Object.keys(o).length>0?o:null}_extractExports(e){const t=[],s=e.search(/module\.exports\s*=\s*\{/);if(s>=0){const o=e.indexOf("{",s);if(o>=0){let s=0,r=e.length;for(let t=o;t<e.length;t++)if("{"===e[t]&&s++,"}"===e[t]&&(s--,0===s)){r=t;break}const i=e.substring(o+1,r);let n=0,c="";for(const e of i)if("{"!==e&&"["!==e&&"("!==e||n++,"}"!==e&&"]"!==e&&")"!==e||n--,0!==n||","!==e&&"\n"!==e)c+=e;else{const e=c.trim().match(/^(\w+)/);e&&t.push(e[1]),c=""}if(c.trim()){const e=c.trim().match(/^(\w+)/);e&&t.push(e[1])}}}const o=e.match(/module\.exports\s*=\s*(class\s+)?(\w+)/);o&&o[2]&&t.push(o[2]);const r=e.match(/exports\.(\w+)\s*=/g)||[];for(const e of r){const s=e.match(/exports\.(\w+)/);s&&t.push(s[1])}const i=e.match(/^(?:def|class)\s+([a-zA-Z_]\w*)/gm)||[];for(const e of i){const s=e.match(/^(?:def|class)\s+([a-zA-Z_]\w*)/);s&&!s[1].startsWith("_")&&t.push(s[1])}const n=e.match(/^func\s+([A-Z][a-zA-Z0-9]*)/gm)||[];for(const e of n){const s=e.match(/^func\s+([A-Z][a-zA-Z0-9]*)/);s&&t.push(s[1])}const c=e.match(/(?:public\s+function|class)\s+([a-zA-Z_]\w*)/g)||[];for(const e of c){const s=e.match(/(?:public\s+function|class)\s+([a-zA-Z_]\w*)/);s&&t.push(s[1])}const a=e.match(/^export\s+(?:(?:async\s+)?function|class|const|let|var)\s+([a-zA-Z_$]\w*)/gm)||[];for(const e of a){const s=e.match(/^export\s+(?:(?:async\s+)?function|class|const|let|var)\s+([a-zA-Z_$]\w*)/);s&&t.push(s[1])}const l=e.match(/^export\s*\{([^}]+)\}/gm)||[];for(const e of l){const s=e.match(/^export\s*\{([^}]+)\}/);if(s){const e=s[1].split(",").map(e=>{const t=e.trim().split(/\s+as\s+/);return(t[1]||t[0]).trim()}).filter(Boolean);t.push(...e)}}/^export\s+default\b/m.test(e)&&t.push("default");const d=e.match(/^pub(?:\([^)]*\))?\s+(?:(?:async\s+)?fn|struct|enum|type|trait)\s+([a-zA-Z_]\w*)/gm)||[];for(const e of d){const s=e.match(/(?:fn|struct|enum|type|trait)\s+([a-zA-Z_]\w*)/);s&&t.push(s[1])}const u=e.match(/^(?:\s*)def\s+(?:self\.)?([a-zA-Z_]\w*[?!]?)/gm)||[];for(const e of u){const s=e.match(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!]?)/);s&&!s[1].startsWith("_")&&t.push(s[1])}return[...new Set(t)]}_extractImports(e){const t=[],s=e.matchAll(/(?:const|let|var)\s+(?:\{([^}]+)\}|(\w+))\s*=\s*require\(['"]([^'"]+)['"]\)/g);for(const e of s){const s=e[1]?e[1].split(",").map(e=>e.trim().split(":")[0].trim()):[e[2]];t.push({module:e[3],specifiers:s.filter(Boolean)})}const o=e.matchAll(/^(?:import\s+(\S+)|from\s+(\S+)\s+import)/gm);for(const e of o)t.push({module:e[1]||e[2],specifiers:[]});const r=e.matchAll(/"([^"]+)"/g);for(const e of r)!e[1].includes("/")&&e[1].includes(" ")||t.push({module:e[1],specifiers:[]});return t}_compareWidgetToCode(e,t,s){const o=[];if(t.exports_to){const r=t.exports_to.split(",").map(e=>e.trim().split(" ")[0]).filter(e=>!s.exports.some(t=>t.toLowerCase().includes(e.toLowerCase())));r.length>0&&o.push({file:e,category:"drift",severity:"warning",id:"DRIFT002",name:"Missing Declared Export",message:`Widget declares exports not found in code: ${r.join(", ")}`})}if(t.imports_from){const r=t.imports_from.split(",").map(e=>e.trim().split(" ")[0]),i=s.imports.map(e=>e.module),n=r.filter(e=>!i.some(t=>t.includes(e)||e.includes(t.split("/").pop())));n.length>0&&o.push({file:e,category:"drift",severity:"warning",id:"DRIFT003",name:"Missing Declared Import",message:`Widget declares imports not found in code: ${n.join(", ")}`})}return!/fs\.(write|append|unlink|mkdir|rmdir)/i.test(fs.readFileSync(e,"utf8").replace(/\r\n/g,"\n"))||t.side_effects&&"None"!==t.side_effects||o.push({file:e,category:"drift",severity:"warning",id:"DRIFT004",name:"Undeclared Side Effects",message:"File has file system operations but widget declares no side effects"}),o}_analyzeCrossFile(e){const t=[];for(const[s,o]of Object.entries(e))1===o.length&&t.push({file:o[0],category:"drift",severity:"info",id:"DRIFT005",name:"Orphaned Module",message:`Module "${s}" only has one file - verify module organization`});return t}}module.exports=DriftDetector;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const{execFileSync:execFileSync}=require("child_process"),path=require("path"),HELPER_SCRIPT=path.join(__dirname,"go_ast_helper.go"),PROBE_TIMEOUT_MS=3e3,EXEC_TIMEOUT_MS=8e3,MAX_BUFFER=2097152;let cachedGoBin;function resolveGoBin(){if(void 0!==cachedGoBin)return cachedGoBin;try{execFileSync("go",["version"],{stdio:"pipe",timeout:3e3}),cachedGoBin="go"}catch(e){cachedGoBin=null}return cachedGoBin}function _resetGoBinCache(){cachedGoBin=void 0}function snippet(e,n){return!n||n<1||n>e.length?"":e[n-1].trim().substring(0,100)}const RULES_BY_TYPE={unused_import:{id:"AST031",severity:"info",category:"quality",name:"Unused Import (Go AST)"},unused_variable:{id:"AST032",severity:"info",category:"quality",name:"Ineffectual Assignment (Go AST)"},high_complexity:{id:"AST033",severity:"warning",category:"quality",name:"High Cyclomatic Complexity (Go AST)"},dead_code:{id:"AST034",severity:"warning",category:"quality",name:"Unreachable Code (Go AST)"},unchecked_error:{id:"AST035",severity:"warning",category:"security",name:"Unchecked Error (Go AST)"},goroutine_leak:{id:"AST036",severity:"warning",category:"quality",name:"Goroutine Leak (Go AST)"},defer_in_loop:{id:"AST037",severity:"warning",category:"quality",name:"Defer Inside Loop (Go AST)"}};function toIssue(e,n,i){const t=RULES_BY_TYPE[i.type];return t?{file:e,line:i.line||0,category:t.category,type:i.type,severity:t.severity,id:t.id,name:t.name,message:i.message,code:snippet(n,i.line),source:"go-ast"}:null}function analyze(e,n){const i=resolveGoBin();if(!i)return[];let t,o;try{t=execFileSync(i,["run",HELPER_SCRIPT],{input:n,encoding:"utf8",timeout:8e3,maxBuffer:2097152,windowsHide:!0})}catch(e){return[]}try{o=JSON.parse(t)}catch(e){return[]}if(!o||!0!==o.ok||!Array.isArray(o.issues))return[];const r=n.split("\n"),a=[];for(const n of o.issues){const i=toIssue(e,r,n);i&&a.push(i)}return a}module.exports={analyze:analyze,_internal:{resolveGoBin:resolveGoBin,_resetGoBinCache:_resetGoBinCache,RULES_BY_TYPE:RULES_BY_TYPE}};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const fs=require("fs"),path=require("path"),exportVerifier=require("./export-verifier");class HallucinationDetector{constructor(e={}){const t=new Set(["rootPath","ignorePatterns","maxFileSize"]),s={};for(const n of Object.keys(e))t.has(n)&&(s[n]=e[n]);this.config={rootPath:s.rootPath||process.cwd()},this.builtins=new Set(["assert","async_hooks","buffer","child_process","cluster","console","constants","crypto","dgram","diagnostics_channel","dns","domain","events","fs","http","http2","https","inspector","module","net","os","path","perf_hooks","process","punycode","querystring","readline","repl","stream","string_decoder","sys","timers","tls","trace_events","tty","url","util","v8","vm","wasi","worker_threads","zlib","node:fs","node:path","node:os","node:crypto","node:http","node:https","node:events","node:util","node:stream","node:child_process","node:url","node:querystring","node:buffer","node:net","node:tls","node:dns","node:readline","node:zlib","node:worker_threads","node:cluster","node:vm","node:assert","node:timers","node:timers/promises","node:test","fs/promises","stream/promises","timers/promises","dns/promises","readline/promises"]),this.phantomPackages=new Set(["node-fetch-extra","express-async","mongoose-v2","react-native-web-view","axios-retry-enhanced","lodash-extended","moment-timezone-v2","socket.io-extra","graphql-tools-v2","next-auth-v5","prisma-client-v2","tailwind-utils","react-query-v4","jest-extended-v2"]),this.knownRealPackages=new Set(["express","koa","fastify","hapi","nest","@nestjs/core","@nestjs/common","next","nuxt","gatsby","remix","@remix-run/node","@remix-run/react","react","react-dom","react-native","react-router","react-router-dom","@tanstack/react-query","react-query","react-hook-form","react-redux","redux","@reduxjs/toolkit","zustand","jotai","recoil","mobx","vue","vuex","pinia","vue-router","@vue/compiler-sfc","@angular/core","@angular/common","@angular/router","@angular/forms","lodash","lodash-es","underscore","ramda","date-fns","dayjs","moment","uuid","nanoid","chalk","colors","debug","dotenv","cross-env","commander","yargs","inquirer","ora","glob","minimatch","semver","minimist","meow","execa","shelljs","fs-extra","rimraf","mkdirp","del","cpy","globby","fast-glob","chokidar","nodemon","axios","node-fetch","got","superagent","ky","undici","isomorphic-fetch","cors","helmet","body-parser","cookie-parser","compression","express-validator","joi","yup","zod","ajv","mongoose","sequelize","typeorm","prisma","@prisma/client","knex","pg","mysql","mysql2","sqlite3","better-sqlite3","redis","ioredis","mongodb","drizzle-orm","objection","bookshelf","jsonwebtoken","bcrypt","bcryptjs","passport","passport-local","passport-jwt","express-session","cookie-session","csurf","hpp","rate-limiter-flexible","express-rate-limit","next-auth","@auth/core","jest","mocha","chai","sinon","vitest","@testing-library/react","@testing-library/jest-dom","supertest","nock","cypress","playwright","@playwright/test","enzyme","nyc","istanbul","c8","ava","tap","webpack","vite","esbuild","rollup","parcel","turbo","tsup","babel-loader","@babel/core","@babel/preset-env","@babel/preset-react","@babel/preset-typescript","ts-node","tsx","typescript","tailwindcss","postcss","autoprefixer","sass","less","styled-components","@emotion/react","@emotion/styled","css-modules","classnames","clsx","winston","pino","bunyan","morgan","log4js","loglevel","sentry","@sentry/node","@sentry/react","newrelic","datadog-metrics","aws-sdk","@aws-sdk/client-s3","@aws-sdk/client-dynamodb","@google-cloud/storage","@google-cloud/pubsub","@google-cloud/firestore","firebase","firebase-admin","@supabase/supabase-js","socket.io","socket.io-client","ws","mqtt","amqplib","bull","bullmq","multer","sharp","jimp","formidable","busboy","csv-parse","csv-parser","papaparse","xlsx","exceljs","pdfkit","puppeteer","cheerio","jsdom","graphql","apollo-server","@apollo/server","@apollo/client","graphql-tag","type-graphql","graphql-yoga","urql","async","bluebird","rxjs","immutable","immer","p-limit","p-queue","eventemitter3","mitt","cron","node-cron","agenda","handlebars","ejs","pug","nunjucks","mustache","marked","markdown-it","remark","rehype","unified","nodemailer","twilio","stripe","@stripe/stripe-js","i18next","intl","i18n","luxon","eslint","prettier","stylelint","lint-staged","husky","lerna","nx","@nrwl/workspace","changesets","@changesets/cli"]),this.phantomAPIs=[{pattern:/fs\.readFileAsync\s*\(/,suggestion:"Use fs.promises.readFile() or fs.readFileSync()",name:"fs.readFileAsync",id:"HALL_API001"},{pattern:/fs\.writeFileAsync\s*\(/,suggestion:"Use fs.promises.writeFile() or fs.writeFileSync()",name:"fs.writeFileAsync",id:"HALL_API002"},{pattern:/fs\.existsAsync\s*\(/,suggestion:"Use fs.promises.access() or fs.existsSync()",name:"fs.existsAsync",id:"HALL_API003"},{pattern:/path\.exists\s*\(/,suggestion:"Use fs.existsSync() — path module has no exists()",name:"path.exists",id:"HALL_API004"},{pattern:/path\.isFile\s*\(/,suggestion:"Use fs.statSync().isFile() — path module has no isFile()",name:"path.isFile",id:"HALL_API005"},{pattern:/path\.isDirectory\s*\(/,suggestion:"Use fs.statSync().isDirectory()",name:"path.isDirectory",id:"HALL_API006"},{pattern:/console\.success\s*\(/,suggestion:"Use console.log() — console.success() does not exist",name:"console.success",id:"HALL_API007"},{pattern:/console\.verbose\s*\(/,suggestion:"Use console.log() or console.debug()",name:"console.verbose",id:"HALL_API008"},{pattern:/JSON\.tryParse\s*\(/,suggestion:"Use try/catch with JSON.parse()",name:"JSON.tryParse",id:"HALL_API009"},{pattern:/JSON\.safeStringify\s*\(/,suggestion:"Use JSON.stringify() with a replacer",name:"JSON.safeStringify",id:"HALL_API010"},{pattern:/Array\.flatten\s*\(/,suggestion:"Use Array.prototype.flat()",name:"Array.flatten",id:"HALL_API011"},{pattern:/Object\.deepClone\s*\(/,suggestion:"Use structuredClone() or JSON.parse(JSON.stringify())",name:"Object.deepClone",id:"HALL_API012"},{pattern:/Object\.deepMerge\s*\(/,suggestion:"Use a library like lodash.merge or write a custom function",name:"Object.deepMerge",id:"HALL_API013"},{pattern:/String\.prototype\.replaceAll\s*&&.*polyfill/i,suggestion:"replaceAll() is native since ES2021 — no polyfill needed",name:"replaceAll polyfill",id:"HALL_API014"},{pattern:/require\s*\(\s*['"]fs\/sync['"]\s*\)/,suggestion:"fs/sync is not a real module — use fs directly",name:"fs/sync",id:"HALL_API015"},{pattern:/require\s*\(\s*['"]http\/server['"]\s*\)/,suggestion:"http/server is not a real module — use http.createServer()",name:"http/server",id:"HALL_API016"},{pattern:/process\.env\.get\s*\(/,suggestion:"Use process.env.VAR_NAME — process.env is a plain object, not a Map",name:"process.env.get()",id:"HALL_API017"},{pattern:/process\.exit\s*\(\s*['"]/,suggestion:"process.exit() takes a number, not a string",name:"process.exit(string)",id:"HALL_API018"}],this.pythonPhantomAPIs=[{pattern:/os\.path\.exists_sync\s*\(/,suggestion:"Use os.path.exists() — exists_sync does not exist in Python",name:"os.path.exists_sync",id:"PY_HALL001"},{pattern:/json\.tryParse\s*\(/,suggestion:"Use json.loads() with try/except",name:"json.tryParse",id:"PY_HALL002"},{pattern:/\w+\.flatMap\s*\(/,suggestion:"Python lists have no flatMap — use list comprehension or itertools.chain.from_iterable()",name:"list.flatMap",id:"PY_HALL003"},{pattern:/\w+\.merge\s*\((?!.*\bself\b)/,suggestion:"Use {**dict1, **dict2} or dict1 | dict2 (3.9+)",name:"dict.merge",id:"PY_HALL004"},{pattern:/\w+\.format_map\s*\(/,suggestion:"str.format_map exists but is rarely correct — did you mean .format()?",name:"string.format_map misuse",id:"PY_HALL005"},{pattern:/from\s+collections\s+import\s+OrderedDict.*#.*maintain\s+order/i,suggestion:"Regular dict maintains order since Python 3.7 — OrderedDict is unnecessary",name:"Unnecessary OrderedDict",id:"PY_HALL006"},{pattern:/async\s+def\s+\w+.*asyncio\.sleep\s*\(\s*0\s*\)\s*#.*yield/i,suggestion:"asyncio.sleep(0) to yield is a code smell — review async design",name:"asyncio.sleep(0) hack",id:"PY_HALL007"},{pattern:/import\s+tensorflow\.v2/,suggestion:"tensorflow.v2 is not a real module — use import tensorflow",name:"tensorflow.v2",id:"PY_HALL008"},{pattern:/from\s+sklearn\.model_selection\s+import\s+train_test_split_v2/,suggestion:"train_test_split_v2 does not exist — use train_test_split",name:"sklearn v2 hallucination",id:"PY_HALL009"},{pattern:/requests\.async_get\s*\(/,suggestion:"requests has no async_get — use aiohttp or httpx",name:"requests.async_get",id:"PY_HALL010"}],this.pythonDeprecated=[{pattern:/from\s+distutils/,suggestion:"distutils removed in Python 3.12 — use setuptools",since:"Python 3.12",name:"distutils",id:"PY_DEPR001"},{pattern:/from\s+imp\s+import/,suggestion:"imp removed in Python 3.12 — use importlib",since:"Python 3.12",name:"imp module",id:"PY_DEPR002"},{pattern:/asyncio\.get_event_loop\(\)/,suggestion:"Deprecated in 3.10+ — use asyncio.run() or get_running_loop()",since:"Python 3.10",name:"asyncio.get_event_loop()",id:"PY_DEPR003"},{pattern:/collections\.MutableMapping/,suggestion:"Moved to collections.abc.MutableMapping in Python 3.3+",since:"Python 3.9",name:"collections.MutableMapping",id:"PY_DEPR004"},{pattern:/optparse\.OptionParser/,suggestion:"optparse deprecated since Python 3.2 — use argparse",since:"Python 3.2",name:"optparse",id:"PY_DEPR005"},{pattern:/cgi\.parse_header\s*\(/,suggestion:"cgi module deprecated in Python 3.11, removed in 3.13",since:"Python 3.11",name:"cgi module",id:"PY_DEPR006"},{pattern:/from\s+typing\s+import\s+(List|Dict|Tuple|Set)\b/,suggestion:"Use built-in list, dict, tuple, set for type hints (Python 3.9+)",since:"Python 3.9",name:"typing.List/Dict/Tuple",id:"PY_DEPR007"},{pattern:/unittest\.makeSuite\s*\(/,suggestion:"makeSuite deprecated — use TestLoader.loadTestsFromTestCase",since:"Python 3.11",name:"unittest.makeSuite",id:"PY_DEPR008"}],this.pythonSmells=[{pattern:/print\s*\(\s*f?['"]\s*debug/i,id:"PY_SMELL001",name:"Debug Print",message:"Debug print statement left in code"},{pattern:/except\s*:\s*$|except\s+Exception\s*:\s*\n\s*pass/m,id:"PY_SMELL002",name:"Bare Except",message:"Bare except or swallowed exception — hides real errors"},{pattern:/#\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"PY_SMELL003",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/raise\s+NotImplementedError\s*\(?\s*\)?/,id:"PY_SMELL004",name:"Not Implemented",message:"Stub implementation — function body was not generated"},{pattern:/['"]your.api.key.here['"]|['"]sk-[.]{3,}['"]/i,id:"PY_SMELL005",name:"Dummy Credential",message:"Placeholder credential — will fail at runtime"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"PY_SMELL006",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"},{pattern:/import\s+\*/,id:"PY_SMELL007",name:"Wildcard Import",message:"Wildcard import — pollutes namespace, hides dependencies"}],this.goDeprecated=[{pattern:/ioutil\.ReadFile\s*\(/,suggestion:"ioutil removed in Go 1.16 — use os.ReadFile()",since:"Go 1.16",name:"ioutil.ReadFile",id:"GO_DEPR001"},{pattern:/ioutil\.WriteFile\s*\(/,suggestion:"ioutil removed in Go 1.16 — use os.WriteFile()",since:"Go 1.16",name:"ioutil.WriteFile",id:"GO_DEPR002"},{pattern:/ioutil\.TempDir\s*\(/,suggestion:"ioutil removed in Go 1.16 — use os.MkdirTemp()",since:"Go 1.16",name:"ioutil.TempDir",id:"GO_DEPR003"},{pattern:/ioutil\.ReadAll\s*\(/,suggestion:"ioutil removed in Go 1.16 — use io.ReadAll()",since:"Go 1.16",name:"ioutil.ReadAll",id:"GO_DEPR004"},{pattern:/strings\.Title\s*\(/,suggestion:"strings.Title deprecated in Go 1.18 — use cases.Title from golang.org/x/text",since:"Go 1.18",name:"strings.Title",id:"GO_DEPR005"}],this.goSmells=[{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"GO_SMELL001",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/panic\s*\(\s*["']not implemented["']\s*\)/,id:"GO_SMELL002",name:"Panic Not Implemented",message:"Stub implementation — will panic at runtime"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"GO_SMELL003",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"}],this.rustPhantomAPIs=[{pattern:/std::fs::File::open_async\s*\(/,suggestion:"Use tokio::fs::File::open() for async file I/O",name:"File::open_async",id:"RS_HALL001"},{pattern:/Vec::flatten\s*\(/,suggestion:"Use .into_iter().flatten() — Vec has no flatten() method",name:"Vec::flatten",id:"RS_HALL002"},{pattern:/HashMap::get_or_default\s*\(/,suggestion:"Use .get().unwrap_or(&default) or entry().or_insert()",name:"HashMap::get_or_default",id:"RS_HALL003"},{pattern:/String::from_utf8_lossy_owned\s*\(/,suggestion:"Use String::from_utf8_lossy().into_owned()",name:"String::from_utf8_lossy_owned",id:"RS_HALL004"},{pattern:/\.async_iter\s*\(/,suggestion:"Use futures::stream::iter() from the futures crate",name:".async_iter()",id:"RS_HALL005"},{pattern:/std::net::TcpStream::connect_async\s*\(/,suggestion:"Use tokio::net::TcpStream::connect()",name:"TcpStream::connect_async",id:"RS_HALL006"},{pattern:/std::thread::sleep_async\s*\(/,suggestion:"Use tokio::time::sleep() for async sleep",name:"thread::sleep_async",id:"RS_HALL007"},{pattern:/Vec::remove_all\s*\(/,suggestion:"Use .retain(|x| condition) or .clear()",name:"Vec::remove_all",id:"RS_HALL008"},{pattern:/str::split_whitespace_n\s*\(/,suggestion:"Use .splitn(n, char::is_whitespace) instead",name:"str::split_whitespace_n",id:"RS_HALL009"},{pattern:/\.map_async\s*\(/,suggestion:"Use futures::future::join_all() or tokio::task::spawn",name:".map_async()",id:"RS_HALL010"}],this.rustDeprecated=[{pattern:/std::sync::ONCE_INIT/,suggestion:"std::sync::ONCE_INIT removed — use Once::new()",since:"Rust 1.38",name:"ONCE_INIT",id:"RS_DEPR001"},{pattern:/\bstd::mem::uninitialized\s*\(/,suggestion:"std::mem::uninitialized() removed — use MaybeUninit::uninit()",since:"Rust 1.39",name:"mem::uninitialized",id:"RS_DEPR002"},{pattern:/\btry!\s*\(/,suggestion:"try!() macro removed — use the ? operator",since:"Rust 2018",name:"try!() macro",id:"RS_DEPR003"},{pattern:/extern\s+crate\s+std\s*;/,suggestion:"extern crate std is implicit since Rust 2018 edition",since:"Rust 2018",name:"extern crate std",id:"RS_DEPR004"},{pattern:/extern\s+crate\s+alloc\s*;/,suggestion:"extern crate alloc is implicit in 2018+ edition",since:"Rust 2018",name:"extern crate alloc",id:"RS_DEPR005"},{pattern:/std::error::Error::cause\s*\(/,suggestion:".cause() deprecated — use .source() instead",since:"Rust 1.33",name:"Error::cause()",id:"RS_DEPR006"}],this.rustSmells=[{pattern:/todo!\s*\(\s*\)/,id:"RS_SMELL001",name:"todo! macro",message:"todo!() macro — will panic at runtime"},{pattern:/unimplemented!\s*\(\s*\)/,id:"RS_SMELL002",name:"unimplemented! macro",message:"unimplemented!() macro — will panic at runtime"},{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"RS_SMELL003",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/unwrap\(\).*unwrap\(\)/,id:"RS_SMELL004",name:"Double Unwrap",message:"Chained unwrap() — will panic on None/Err"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"RS_SMELL005",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"},{pattern:/unsafe\s*\{/,id:"RS_SMELL006",name:"Unsafe Block",message:"unsafe block — verify memory safety guarantees"},{pattern:/\.unwrap\(\)\s*;/,id:"RS_SMELL007",name:"Bare unwrap()",message:".unwrap() will panic on None/Err — use ? or match"},{pattern:/println!\s*\(\s*["'].*[Dd]ebug/,id:"RS_SMELL008",name:"Debug println!",message:"Debug println! left in code — use the log crate"},{pattern:/eprintln!\s*\(\s*["'].*[Dd]ebug/,id:"RS_SMELL009",name:"Debug eprintln!",message:"Debug eprintln! left in code — use the log crate"},{pattern:/#\[allow\(dead_code\)\]/,id:"RS_SMELL010",name:"Suppressed Dead Code",message:"#[allow(dead_code)] suppresses warnings — remove unused code"}],this.javaSmells=[{pattern:/System\.out\.println\s*\(.*debug/i,id:"JAVA_SMELL001",name:"Debug Println",message:"Debug System.out.println — use a logger"},{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"JAVA_SMELL002",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/throw\s+new\s+(?:Runtime)?Exception\s*\(\s*["']Not\s+implemented["']/i,id:"JAVA_SMELL003",name:"Not Implemented",message:"Stub implementation — will throw at runtime"},{pattern:/catch\s*\(\s*Exception\s+\w+\s*\)\s*\{\s*\}/,id:"JAVA_SMELL004",name:"Empty Catch",message:"Empty catch block — swallows all exceptions"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"JAVA_SMELL005",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"}],this.csharpSmells=[{pattern:/Console\.WriteLine\s*\(.*[Dd]ebug/i,id:"CS_SMELL001",name:"Debug WriteLine",message:"Debug Console.WriteLine — use ILogger or Debug.Write"},{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"CS_SMELL002",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/throw\s+new\s+(?:NotImplementedException)\s*\(/,id:"CS_SMELL003",name:"Not Implemented",message:"Stub implementation — will throw at runtime"},{pattern:/catch\s*\(\s*Exception\s+\w+\s*\)\s*\{\s*\}/,id:"CS_SMELL004",name:"Empty Catch",message:"Empty catch block — swallows all exceptions"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"CS_SMELL005",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"}],this.kotlinPhantomAPIs=[{pattern:/\.flatMap\s*\{[^}]*\}(?!.*asSequence)/,suggestion:"Use .flatMap { } — verify this is not confusing sequence vs list behavior",name:"flatMap confusion",id:"KT_HALL001"},{pattern:/listOf\(\)\.stream\s*\(/,suggestion:"Kotlin lists have no .stream() — use .asSequence() or direct collection ops",name:"listOf().stream()",id:"KT_HALL002"},{pattern:/String\.format\s*\(/,suggestion:'Prefer Kotlin string templates "$variable" over String.format()',name:"String.format Java-style",id:"KT_HALL003"},{pattern:/\bObject\s*\(\s*\)/,suggestion:"Kotlin uses Any() not Object() — or use object keyword for singletons",name:"Object() Java-style",id:"KT_HALL004"},{pattern:/\.forEach\s*\(\s*::println\s*\)(?!.*debug)/i,suggestion:"println is for debug output — use a logger",name:"println via forEach",id:"KT_HALL005"},{pattern:/coroutineScope\s*\{\s*launch\s*\{[^}]*\}\s*\}(?!\s*\.join)/,suggestion:"Unjoined coroutine in coroutineScope may cause issues — ensure structured concurrency",name:"Unawaited launch",id:"KT_HALL006"},{pattern:/Dispatchers\.IO\s*\+\s*Dispatchers/,suggestion:"Combining Dispatchers is not valid — use one dispatcher at a time",name:"Combined Dispatchers",id:"KT_HALL007"},{pattern:/\.toList\(\)\.stream\(\)/,suggestion:"Use Kotlin sequences (.asSequence()) instead of .toList().stream()",name:"toList().stream()",id:"KT_HALL008"},{pattern:/companion object.*getInstance/i,suggestion:"Kotlin idiom for singletons is object keyword, not companion object + getInstance()",name:"Java-style singleton",id:"KT_HALL009"},{pattern:/lateinit var.*\?/,suggestion:"lateinit properties cannot be nullable — remove ? or use by lazy {}",name:"lateinit nullable",id:"KT_HALL010"}],this.kotlinDeprecated=[{pattern:/\bapply\s+plugin:\s*['"]kotlin-android-extensions['"]/,suggestion:"kotlin-android-extensions deprecated — use view binding or Jetpack ViewBinding",since:"Kotlin 1.8",name:"kotlin-android-extensions",id:"KT_DEPR001"},{pattern:/\bkotlinx\.android\.synthetic/,suggestion:"Synthetic imports deprecated — use view binding or findViewById",since:"Kotlin 1.8",name:"Synthetic imports",id:"KT_DEPR002"},{pattern:/\bCoroutineScope\(EmptyCoroutineContext\)/,suggestion:"EmptyCoroutineContext coroutine scope is error-prone — use viewModelScope or lifecycleScope",since:"Kotlin Coroutines 1.6",name:"EmptyCoroutineContext scope",id:"KT_DEPR003"},{pattern:/\bBuildersKt\.launch\b/,suggestion:"Internal BuildersKt APIs are deprecated — use coroutineScope { launch {} }",since:"Kotlin Coroutines 1.5",name:"BuildersKt.launch",id:"KT_DEPR004"},{pattern:/\basyncLazy\s*\{/,suggestion:"asyncLazy {} is not a standard Kotlin API — use lazy {} or async {}",since:"Kotlin 1.6",name:"asyncLazy",id:"KT_DEPR005"}],this.kotlinSmells=[{pattern:/\bprintln\s*\(/,id:"KT_SMELL001",name:"Debug println",message:"println() is for debug output — use a proper logger"},{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"KT_SMELL002",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/TODO\s*\(\s*\)/,id:"KT_SMELL003",name:"TODO() stub",message:"TODO() will throw NotImplementedError at runtime"},{pattern:/!!\s*\./,id:"KT_SMELL004",name:"Non-null assertion chain",message:"!! non-null assertion — will throw NullPointerException if null"},{pattern:/\bas\s+\w+\b(?!.*\?)/,suggestion:"Unsafe cast — prefer safe cast (as? Type) with null check",id:"KT_SMELL005",name:"Unsafe cast",message:"Unsafe cast with as — will throw ClassCastException if wrong type"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"KT_SMELL006",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"},{pattern:/catch\s*\(\s*e:\s*Exception\s*\)\s*\{\s*\}/,id:"KT_SMELL007",name:"Empty Catch",message:"Empty catch block — swallows all exceptions"},{pattern:/throw\s+NotImplementedError\s*\(/,id:"KT_SMELL008",name:"Not Implemented",message:"Stub implementation — will throw at runtime"}],this.phpPhantomAPIs=[{pattern:/array_flatten\s*\(/,suggestion:"PHP has no array_flatten() — use array_merge(...$array) or a recursive function",name:"array_flatten",id:"PHP_HALL001"},{pattern:/str_contains_all\s*\(/,suggestion:"PHP has no str_contains_all() — use multiple str_contains() calls",name:"str_contains_all",id:"PHP_HALL002"},{pattern:/array_unique_values\s*\(/,suggestion:"PHP has no array_unique_values() — use array_values(array_unique())",name:"array_unique_values",id:"PHP_HALL003"},{pattern:/\$pdo->fetchAll\s*\(/,suggestion:"fetchAll() is on PDOStatement not PDO — call $stmt->fetchAll()",name:"PDO::fetchAll",id:"PHP_HALL004"},{pattern:/json_decode_safe\s*\(/,suggestion:"PHP has no json_decode_safe() — wrap json_decode() with json_last_error() check",name:"json_decode_safe",id:"PHP_HALL005"},{pattern:/str_replace_all\s*\(/,suggestion:"PHP has no str_replace_all() — use str_replace() which already replaces all occurrences",name:"str_replace_all",id:"PHP_HALL006"},{pattern:/array_map_keys\s*\(/,suggestion:"PHP has no array_map_keys() — use array_combine(array_map(...), array_keys())",name:"array_map_keys",id:"PHP_HALL007"},{pattern:/\$request->getJson\s*\(/,suggestion:'Not a standard PHP function — use json_decode(file_get_contents("php://input"))',name:"$request->getJson",id:"PHP_HALL008"},{pattern:/Date::now\s*\(/,suggestion:"PHP has no Date::now() — use new DateTime() or time()",name:"Date::now",id:"PHP_HALL009"},{pattern:/\bawait\s+/,suggestion:"PHP has no await keyword — use synchronous code or ReactPHP for async",name:"await keyword",id:"PHP_HALL010"}],this.phpDeprecated=[{pattern:/\bmysql_connect\s*\(/,suggestion:"mysql_* functions removed in PHP 7 — use PDO or MySQLi",since:"PHP 7.0",name:"mysql_connect",id:"PHP_DEPR001"},{pattern:/\bmysql_query\s*\(/,suggestion:"mysql_* functions removed in PHP 7 — use PDO or MySQLi",since:"PHP 7.0",name:"mysql_query",id:"PHP_DEPR002"},{pattern:/\bmysql_fetch_array\s*\(/,suggestion:"mysql_* functions removed in PHP 7 — use PDO or MySQLi",since:"PHP 7.0",name:"mysql_fetch_array",id:"PHP_DEPR003"},{pattern:/\bereg\s*\(/,suggestion:"ereg() removed in PHP 7 — use preg_match()",since:"PHP 7.0",name:"ereg()",id:"PHP_DEPR004"},{pattern:/\bsplit\s*\(/,suggestion:"split() removed in PHP 7 — use preg_split() or explode()",since:"PHP 7.0",name:"split()",id:"PHP_DEPR005"},{pattern:/\bcreate_function\s*\(/,suggestion:"create_function() removed in PHP 8 — use anonymous functions (closures)",since:"PHP 8.0",name:"create_function",id:"PHP_DEPR006"},{pattern:/\bmagic_quotes_gpc\b/,suggestion:"magic_quotes_gpc removed in PHP 7 — sanitize inputs manually",since:"PHP 7.0",name:"magic_quotes_gpc",id:"PHP_DEPR007"},{pattern:/\beach\s*\(/,suggestion:"each() deprecated in PHP 7.2, removed in PHP 8 — use foreach",since:"PHP 8.0",name:"each()",id:"PHP_DEPR008"},{pattern:/\bmcrypt_/,suggestion:"mcrypt removed in PHP 7.2 — use OpenSSL functions",since:"PHP 7.2",name:"mcrypt functions",id:"PHP_DEPR009"}],this.phpSmells=[{pattern:/\beval\s*\(/,id:"PHP_SMELL001",name:"eval() Usage",message:"eval() is dangerous — code injection risk"},{pattern:/\bextract\s*\(\s*\$_(?:GET|POST|REQUEST)/,id:"PHP_SMELL002",name:"extract() from superglobal",message:"extract($_GET/_POST) — variable injection vulnerability"},{pattern:/\$\$\w+/,id:"PHP_SMELL003",name:"Variable variable",message:"Variable variables ($$var) — hard to trace and injection risk"},{pattern:/\bshell_exec\s*\(/,id:"PHP_SMELL004",name:"shell_exec()",message:"shell_exec() — remote code execution risk if input unsanitized"},{pattern:/\bsystem\s*\(/,id:"PHP_SMELL005",name:"system()",message:"system() — remote code execution risk if input unsanitized"},{pattern:/\bpassthru\s*\(/,id:"PHP_SMELL006",name:"passthru()",message:"passthru() — remote code execution risk if input unsanitized"},{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"PHP_SMELL007",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"PHP_SMELL008",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"},{pattern:/\$_(?:GET|POST|REQUEST)\[.*\].*SELECT.*\./i,id:"PHP_SMELL009",name:"SQL Injection Risk",message:"User input directly in SQL string — use prepared statements"},{pattern:/\bvar_dump\s*\(/,id:"PHP_SMELL010",name:"Debug var_dump",message:"var_dump() is for debug only — remove before production"}],this.rubyPhantomAPIs=[{pattern:/\.flatten_map\s*\{/,suggestion:"Ruby has no .flatten_map — use .flat_map { }",name:".flatten_map",id:"RB_HALL001"},{pattern:/Array\.of\s*\(/,suggestion:"Ruby has no Array.of() — use Array() or []",name:"Array.of()",id:"RB_HALL002"},{pattern:/Hash\.from_array\s*\(/,suggestion:"Ruby has no Hash.from_array() — use array.to_h or Hash[array]",name:"Hash.from_array",id:"RB_HALL003"},{pattern:/\.async\s*\{/,suggestion:"Ruby has no .async {} — use Thread.new or concurrent-ruby gem",name:".async block",id:"RB_HALL004"},{pattern:/String\.format\s*\(/,suggestion:"Ruby has no String.format() — use string interpolation or % operator",name:"String.format",id:"RB_HALL005"},{pattern:/\bpromise\s*\{/,suggestion:"Ruby has no built-in promise {} — use concurrent-ruby gem or Thread",name:"promise block",id:"RB_HALL006"},{pattern:/\.try!\s*\(/,suggestion:"Ruby has no .try!() — use &. (safe navigation) or Rails .try()",name:".try!()",id:"RB_HALL007"},{pattern:/JSON\.safe_parse\s*\(/,suggestion:"Ruby has no JSON.safe_parse — use JSON.parse with rescue",name:"JSON.safe_parse",id:"RB_HALL008"},{pattern:/ActiveRecord::Base\.execute\s*\(/,suggestion:"ActiveRecord::Base has no .execute() — use connection.execute() or where()",name:"Base.execute",id:"RB_HALL009"},{pattern:/\.collect_map\s*\{/,suggestion:"Ruby has no .collect_map — use .map { }.flatten(1) or .flat_map",name:".collect_map",id:"RB_HALL010"}],this.rubyDeprecated=[{pattern:/\brequire\s+['"]thread['"]/,suggestion:'require "thread" is deprecated — Thread is now built-in without require',since:"Ruby 2.0",name:'require "thread"',id:"RB_DEPR001"},{pattern:/\bObject#type\b|\.type\s*==/,suggestion:".type is deprecated — use .class or .is_a?",since:"Ruby 1.8",name:"Object#type",id:"RB_DEPR002"},{pattern:/\bERB::Util\.html_escape\b/,suggestion:"ERB::Util.html_escape deprecated — use CGI.escapeHTML or h() in views",since:"Ruby 2.6",name:"ERB::Util.html_escape",id:"RB_DEPR003"},{pattern:/\bFile\.exists\?\s*\(/,suggestion:"File.exists? deprecated — use File.exist? (no s)",since:"Ruby 2.2",name:"File.exists?",id:"RB_DEPR004"},{pattern:/\bDir\.exists\?\s*\(/,suggestion:"Dir.exists? deprecated — use Dir.exist? (no s)",since:"Ruby 2.2",name:"Dir.exists?",id:"RB_DEPR005"},{pattern:/\bObject#returning\b|\s+returning\s+/,suggestion:"Object#returning removed from Rails core — use tap { |obj| }",since:"Rails 3.0",name:"Object#returning",id:"RB_DEPR006"}],this.rubySmells=[{pattern:/\bputs\s+(?!STDOUT)/,id:"RB_SMELL001",name:"Debug puts",message:"puts is for debug output — use Rails logger or a logging library"},{pattern:/\bp\s+\w/,id:"RB_SMELL002",name:"Debug p()",message:"p() is for debug output — remove before production"},{pattern:/\beval\s*\(/,id:"RB_SMELL003",name:"eval() Usage",message:"eval() is dangerous — code injection risk"},{pattern:/\bsystem\s*\(/,id:"RB_SMELL004",name:"system() Shell Call",message:"system() call — command injection risk if input unsanitized"},{pattern:/`[^`]+`/,id:"RB_SMELL005",name:"Backtick Shell Exec",message:"Backtick shell execution — command injection risk"},{pattern:/\bexec\s*\(/,id:"RB_SMELL006",name:"exec() call",message:"exec() replaces the process — ensure this is intentional"},{pattern:/\brescue\s*$|\brescue\s+Exception\b/,id:"RB_SMELL007",name:"Bare rescue",message:"Bare rescue catches all exceptions including fatal ones — be specific"},{pattern:/["'].*#\{.*sql.*\}.*["']/i,id:"RB_SMELL008",name:"SQL String Interpolation",message:"SQL built with string interpolation — use parameterized queries"},{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)/i,id:"RB_SMELL009",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished"},{pattern:/raise\s+NotImplementedError/,id:"RB_SMELL010",name:"Not Implemented",message:"Stub implementation — will raise at runtime"}],this.jsExtensions=new Set([".js",".ts",".jsx",".tsx",".mjs",".cjs"]),this.pyExtensions=new Set([".py",".pyw"]),this.goExtensions=new Set([".go"]),this.rustExtensions=new Set([".rs"]),this.javaExtensions=new Set([".java",".kt"]),this.csharpExtensions=new Set([".cs"]),this.phpExtensions=new Set([".php"]),this.rubyExtensions=new Set([".rb"]),this.aiCodeSmells=[{pattern:/\/\/\s*TODO:?\s*(implement|add|fix|complete|finish)\s*(this|here|later)/i,id:"AI_SMELL001",name:"Placeholder TODO",message:"AI-generated placeholder — likely unfinished implementation"},{pattern:/throw new Error\(['"]Not implemented['"]\)/,id:"AI_SMELL002",name:"Not Implemented",message:"Stub implementation — function body was not generated"},{pattern:/\/\/\s*\.\.\.\s*(rest|remaining|more|other|additional)/i,id:"AI_SMELL003",name:"Truncated Code",message:"AI output was truncated — code is incomplete"},{pattern:/\/\/\s*(your|replace|insert|put)\s+(code|logic|implementation|api[_\s]?key)/i,id:"AI_SMELL004",name:"Template Placeholder",message:"Template placeholder left in code — needs real implementation"},{pattern:/['"]your-api-key-here['"]|['"]sk-[.]{3,}['"]|['"]xxx+['"]/i,id:"AI_SMELL005",name:"Dummy Credential",message:"Placeholder credential — will fail at runtime"},{pattern:/example\.com|test@test\.com|john@doe\.com|foo@bar\.com/i,id:"AI_SMELL006",name:"Example Domain",message:"Example domain/email in production code"},{pattern:/localhost:\d{4}(?!.*(?:dev|test|local|development))/i,id:"AI_SMELL007",name:"Hardcoded Localhost",message:"Hardcoded localhost URL — will fail in production"}],this.deprecatedAPIs=[{pattern:/new Buffer\s*\(/,suggestion:"Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe()",since:"Node 6",name:"new Buffer()",id:"DEPR_API001"},{pattern:/require\s*\(\s*['"]sys['"]\s*\)/,suggestion:'Use require("util") — sys was removed in Node 1.0',since:"Node 1.0",name:'require("sys")',id:"DEPR_API002"},{pattern:/fs\.exists\s*\((?!Sync)/,suggestion:"Use fs.access() or fs.stat() — fs.exists() is deprecated",since:"Node 1.0",name:"fs.exists()",id:"DEPR_API003"},{pattern:/domain\.create\s*\(/,suggestion:"Use async_hooks or try/catch — domain module is deprecated",since:"Node 4",name:"domain.create()",id:"DEPR_API004",fixable:!1},{pattern:/require\s*\(\s*['"]punycode['"]\s*\)/,suggestion:"Use userland punycode package — built-in is deprecated",since:"Node 7",name:'require("punycode")',id:"DEPR_API005",fixable:!1},{pattern:/url\.parse\s*\(/,suggestion:"Use new URL() — url.parse() is legacy",since:"Node 11",name:"url.parse()",id:"DEPR_API006"},{pattern:/querystring\.(parse|stringify)\s*\(/,suggestion:"Use URLSearchParams — querystring is legacy",since:"Node 14",name:"querystring",id:"DEPR_API007",fixable:!1},{pattern:/util\.isArray\s*\(/,suggestion:"Use Array.isArray() — util type checks are deprecated",since:"Node 4",name:"util.isArray()",id:"DEPR_API008"},{pattern:/util\.isFunction\s*\(/,suggestion:'Use typeof fn === "function"',since:"Node 4",name:"util.isFunction()",id:"DEPR_API009"},{pattern:/util\.pump\s*\(/,suggestion:"Use stream.pipeline() — util.pump() was removed",since:"Node 1.0",name:"util.pump()",id:"DEPR_API010",fixable:!1}]}async scan(e){const t=Date.now(),s={phantomImports:[],phantomAPIs:[],aiSmells:[],deprecatedAPIs:[],unresolvedDeps:[],stats:{filesScanned:0,totalIssues:0,scanTime:0}},n=this._loadDeclaredDeps(),i=this._loadIgnoreRules();for(const t of e)try{const e=path.extname(t).toLowerCase(),a=this.jsExtensions.has(e),o=this.pyExtensions.has(e),r=this.goExtensions.has(e),l=this.rustExtensions.has(e),c=this.javaExtensions.has(e),d=this.csharpExtensions.has(e),p=this.phpExtensions.has(e),m=this.rubyExtensions.has(e);if(!(a||o||r||l||c||d||p||m))continue;const u=path.relative(this.config.rootPath,t);if(i.some(e=>u.includes(e)||t.includes(e)))continue;const g=fs.readFileSync(t,"utf-8").replace(/\r\n/g,"\n"),h=g.split("\n"),_=new Set;for(let e=0;e<h.length;e++)h[e].includes("thuban-ignore")&&(_.add(e+1),_.add(e+2));const f=this._isPatternDefinitionFile(g);s.stats.filesScanned++,a?(this._checkPhantomImports(u,t,g,h,n,s,_),f||this._checkPhantomAPIs(u,g,h,s,_),this._checkAISmells(u,g,h,s,_),f||this._checkDeprecatedAPIs(u,g,h,s,_),f||this._checkNamedExports(u,t,g,s,_)):o?(this._checkLanguagePatterns(u,g,h,s,_,this.pythonPhantomAPIs,"phantomAPIs"),this._checkLanguagePatterns(u,g,h,s,_,this.pythonDeprecated,"deprecatedAPIs"),this._checkLanguageSmells(u,g,h,s,_,this.pythonSmells)):p?(this._checkLanguagePatterns(u,g,h,s,_,this.phpPhantomAPIs,"phantomAPIs"),this._checkLanguagePatterns(u,g,h,s,_,this.phpDeprecated,"deprecatedAPIs"),this._checkLanguageSmells(u,g,h,s,_,this.phpSmells)):m?(this._checkLanguagePatterns(u,g,h,s,_,this.rubyPhantomAPIs,"phantomAPIs"),this._checkLanguagePatterns(u,g,h,s,_,this.rubyDeprecated,"deprecatedAPIs"),this._checkLanguageSmells(u,g,h,s,_,this.rubySmells)):r?(this._checkLanguagePatterns(u,g,h,s,_,this.goDeprecated,"deprecatedAPIs"),this._checkLanguageSmells(u,g,h,s,_,this.goSmells)):l?(this._checkLanguagePatterns(u,g,h,s,_,this.rustPhantomAPIs,"phantomAPIs"),this._checkLanguagePatterns(u,g,h,s,_,this.rustDeprecated,"deprecatedAPIs"),this._checkLanguageSmells(u,g,h,s,_,this.rustSmells)):c?".kt"===e?(this._checkLanguagePatterns(u,g,h,s,_,this.kotlinPhantomAPIs,"phantomAPIs"),this._checkLanguagePatterns(u,g,h,s,_,this.kotlinDeprecated,"deprecatedAPIs"),this._checkLanguageSmells(u,g,h,s,_,this.kotlinSmells)):this._checkLanguageSmells(u,g,h,s,_,this.javaSmells):d&&this._checkLanguageSmells(u,g,h,s,_,this.csharpSmells)}catch(e){}return s.stats.totalIssues=s.phantomImports.length+s.phantomAPIs.length+s.aiSmells.length+s.deprecatedAPIs.length+s.unresolvedDeps.length,s.stats.scanTime=Date.now()-t,s}_safeRegexTest(e,t,s=1e3){const n=Date.now();try{const i=e.test(t),a=Date.now()-n;return a>s?(console.warn(`[HALLUCINATION-DETECTOR] WARNING: Regex ${e.source.substring(0,50)}... took ${a}ms on input (${t.length} chars) — skipping pattern`),null):i}catch(e){return console.warn("[HALLUCINATION-DETECTOR] Regex error during scan"),null}}_safeRegexExec(e,t,s=1e3){const n=Date.now();try{const i=e.exec(t),a=Date.now()-n;return a>s?(console.warn(`[HALLUCINATION-DETECTOR] WARNING: Regex exec ${e.source.substring(0,50)}... took ${a}ms — skipping pattern`),null):i}catch(e){return console.warn("[HALLUCINATION-DETECTOR] Regex exec error during scan"),null}}_checkLanguagePatterns(e,t,s,n,i,a,o){for(let t=0;t<s.length;t++){if(i.has(t+1))continue;const r=s[t];for(const s of a){const i=this._safeRegexTest(s.pattern,r);if(null!==i&&i){const i={file:e,line:t+1,name:s.name,id:s.id};s.suggestion&&(i.suggestion=s.suggestion),s.since&&(i.since=s.since,i.fix=s.suggestion),"deprecatedAPIs"===o?n.deprecatedAPIs.push(i):n.phantomAPIs.push(i)}}}}_checkLanguageSmells(e,t,s,n,i,a){for(let t=0;t<s.length;t++){if(i.has(t+1))continue;const o=s[t];for(const s of a){const i=this._safeRegexTest(s.pattern,o);null!==i&&i&&n.aiSmells.push({file:e,line:t+1,id:s.id,name:s.name,message:s.message,type:"ai_smell",severity:"medium"})}}}formatReport(e){const t="[0m",s="[1m",n="[31m",i="[32m",a="[33m",o="[36m",r="[90m",l="[35m";let c="";if(c+=`\n${l} ╔══════════════════════════════════════════════╗${t}\n`,c+=`${l} ║${s} THUBAN HALLUCINATION REPORT ${t}${l}║${t}\n`,c+=`${l} ╚══════════════════════════════════════════════╝${t}\n\n`,0===e.stats.totalIssues)return c+=` ${i}${s}No hallucinations detected.${t} ${r}Clean codebase.${t}\n\n`,c;if(e.phantomImports.length>0){c+=` ${n}${s}Phantom Imports (${e.phantomImports.length})${t}\n`,c+=` ${r}Packages that don't exist in package.json or node_modules${t}\n\n`;for(const s of e.phantomImports.slice(0,10))c+=` ${n}✗${t} ${o}${s.file}${t}:${s.line}\n`,c+=` ${a}${s.module}${t} ${r}— ${s.reason}${t}\n`;e.phantomImports.length>10&&(c+=` ${r}... and ${e.phantomImports.length-10} more${t}\n`),c+="\n"}if(e.phantomAPIs.length>0){c+=` ${n}${s}Phantom APIs (${e.phantomAPIs.length})${t}\n`,c+=` ${r}Methods/properties that don't exist on their objects${t}\n\n`;for(const s of e.phantomAPIs.slice(0,10))c+=` ${n}✗${t} ${s.id?`${r}[${s.id}]${t} `:""}${o}${s.file}${t}:${s.line}\n`,c+=` ${a}${s.name}${t} ${r}— ${s.suggestion}${t}\n`,c+=` ${r}Suppress: // thuban-ignore ${s.id||"HALL_API"}${t}\n`;e.phantomAPIs.length>10&&(c+=` ${r}... and ${e.phantomAPIs.length-10} more${t}\n`),c+="\n"}if(e.aiSmells.length>0){c+=` ${a}${s}AI Code Smells (${e.aiSmells.length})${t}\n`,c+=` ${r}Patterns typical of AI-generated code that needs review${t}\n\n`;for(const s of e.aiSmells.slice(0,10))c+=` ${a}!${t} ${o}${s.file}${t}:${s.line}\n`,c+=` ${r}${s.message}${t}\n`;e.aiSmells.length>10&&(c+=` ${r}... and ${e.aiSmells.length-10} more${t}\n`),c+="\n"}if(e.deprecatedAPIs.length>0){c+=` ${a}${s}Deprecated APIs (${e.deprecatedAPIs.length})${t}\n`,c+=` ${r}APIs that LLMs still suggest but are deprecated or removed${t}\n\n`;for(const s of e.deprecatedAPIs.slice(0,10))c+=` ${a}⚠${t} ${o}${s.file}${t}:${s.line}\n`,c+=` ${a}${s.name}${t} ${r}(deprecated since ${s.since})${t}\n`,c+=` ${i}→${t} ${r}${s.suggestion}${t}\n`;e.deprecatedAPIs.length>10&&(c+=` ${r}... and ${e.deprecatedAPIs.length-10} more${t}\n`),c+="\n"}return c+=` ${s}Summary:${t} ${o}${e.stats.filesScanned}${t} files scanned, `,c+=`${e.stats.totalIssues>0?n:i}${e.stats.totalIssues}${t} hallucination issues found `,c+=`${r}(${e.stats.scanTime}ms)${t}\n\n`,c}_loadDeclaredDeps(){const e=new Set;return this._packageJsonPaths=new Map,this._collectPackageJsonDeps(this.config.rootPath,e,0),e}_collectPackageJsonDeps(e,t,s){if(!(s>5))try{const n=path.join(e,"package.json");if(fs.existsSync(n)){const s=JSON.parse(fs.readFileSync(n,"utf-8")),i=new Set;for(const e of Object.keys(s.dependencies||{}))t.add(e),i.add(e);for(const e of Object.keys(s.devDependencies||{}))t.add(e),i.add(e);for(const e of Object.keys(s.peerDependencies||{}))t.add(e),i.add(e);this._packageJsonPaths.set(e,i)}const i=new Set(["node_modules",".git","dist","build","coverage",".next",".cache","vendor"]),a=fs.readdirSync(e,{withFileTypes:!0});for(const n of a)!n.isDirectory()||i.has(n.name)||n.name.startsWith(".")||this._collectPackageJsonDeps(path.join(e,n.name),t,s+1)}catch(e){}}_checkPhantomImports(e,t,s,n,i,a,o=new Set){const r=[/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g,/import\s+.*?from\s+['"]([^'"]+)['"]/g,/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g];for(const n of r){let r;for(;null!==(r=n.exec(s));){const n=r[1];if(n.startsWith(".")||path.isAbsolute(n))continue;const l=n.split("/")[0];if(this.builtins.has(n)||this.builtins.has(l))continue;const c=n.startsWith("@")?n.split("/").slice(0,2).join("/"):l;if(!i.has(c)){if(this.knownRealPackages.has(c))continue;if(!this._findInNodeModules(t,c)){const t=this._findLineNumber(s,r.index);if(o.has(t))continue;const i=this.phantomPackages.has(n);a.phantomImports.push({file:e,line:t,module:n,reason:i?"Known AI-hallucinated package — does not exist on npm":"Not in package.json and not in node_modules",severity:i?"critical":"high",fixable:!1})}}}}}_checkNamedExports(e,t,s,n,i=new Set){let a;try{a=exportVerifier.verifyFile(t,s)}catch(e){return}for(const t of a)i.has(t.line)||n.phantomImports.push({file:e,line:t.line,module:t.source,reason:t.message,severity:"critical",fixable:!1,source:"export-verifier"})}_checkPhantomAPIs(e,t,s,n,i=new Set){for(const a of this.phantomAPIs){let o;const r=new RegExp(a.pattern.source,a.pattern.flags+(a.pattern.flags.includes("g")?"":"g"));for(;null!==(o=this._safeRegexExec(r,t));){const r=this._findLineNumber(t,o.index);if(i.has(r))continue;const l=s[r-1]||"";this._isInsidePattern(l,o[0])||n.phantomAPIs.push({file:e,line:r,name:a.name,id:a.id,suggestion:a.suggestion,severity:"high",fixable:!0,fixAction:"replace_phantom_api"})}}this._checkDynamicBuiltinCalls(e,t,s,n,i)}_checkDynamicBuiltinCalls(e,t,s,n,i){const a=new Map,o=/(?:const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*['"](?:node:)?(\w+)['"]\s*\)/g;let r;for(;null!==(r=o.exec(t));){const e=r[1],t=r[2];this.builtins.has(t)&&a.set(e,t)}const l=/import\s+(?:\*\s+as\s+)?(\w+)\s+from\s+['"](?:node:)?(\w+)['"]/g;let c;for(;null!==(c=l.exec(t));){const e=c[1],t=c[2];this.builtins.has(t)&&a.set(e,t)}if(0!==a.size){this._builtinMethodCache||(this._builtinMethodCache=new Map);for(const[o,r]of a){if(!this._builtinMethodCache.has(r))try{const e=require(r),t=new Set(Object.keys(e));"object"==typeof e&&null!==e&&Object.getOwnPropertyNames(e).forEach(e=>t.add(e)),this._builtinMethodCache.set(r,t)}catch{this._builtinMethodCache.set(r,null);continue}const a=this._builtinMethodCache.get(r);if(!a)continue;const l=new RegExp(`\\b${o}\\.(\\w+)\\s*\\(`,"g");let c;for(;null!==(c=l.exec(t));){const o=c[1],l=this._findLineNumber(t,c.index);if(i.has(l))continue;const d=s[l-1]||"";if(!this._isInsidePattern(d,c[0])&&!a.has(o)){if(n.phantomAPIs.some(t=>t.file===e&&t.line===l))continue;n.phantomAPIs.push({file:e,line:l,name:`${r}.${o}`,id:"HALL_DYN",suggestion:`'${o}' does not exist on the '${r}' module — this is a hallucinated API`,severity:"critical",fixable:!1})}}}}}_checkAISmells(e,t,s,n,i=new Set){for(const a of this.aiCodeSmells){let o;const r=new RegExp(a.pattern.source,a.pattern.flags+(a.pattern.flags.includes("g")?"":"g"));for(;null!==(o=this._safeRegexExec(r,t));){const r=this._findLineNumber(t,o.index);i.has(r)||n.aiSmells.push({file:e,line:r,id:a.id,name:a.name,message:a.message,severity:"warning",code:s[r-1]?.trim().substring(0,100)})}}}_checkDeprecatedAPIs(e,t,s,n,i=new Set){for(const a of this.deprecatedAPIs){let o;const r=new RegExp(a.pattern.source,a.pattern.flags+(a.pattern.flags.includes("g")?"":"g"));for(;null!==(o=this._safeRegexExec(r,t));){const r=this._findLineNumber(t,o.index);if(i.has(r))continue;const l=s[r-1]||"";this._isInsidePattern(l,o[0])||n.deprecatedAPIs.push({file:e,line:r,name:a.name,id:a.id,suggestion:a.suggestion,since:a.since,severity:"warning",fixable:!0,fixAction:"update_deprecated_api"})}}}_findLineNumber(e,t){let s=1;for(let n=0;n<t&&n<e.length;n++)"\n"===e[n]&&s++;return s}_isPatternDefinitionFile(e){const t=(e.match(/pattern:\s*\//g)||[]).length,s=(e.match(/phantom|hallucin/gi)||[]).length;return t>5&&s>2}_isInsidePattern(e,t){const s=e.trim();return!!(/pattern:\s*\//.test(s)||s.startsWith("//")||s.startsWith("*")||/(?:name|suggestion|message|description):\s*['"]/.test(s))}_loadIgnoreRules(){const e=[];try{const t=path.join(this.config.rootPath,".thubanrc.json"),s=JSON.parse(fs.readFileSync(t,"utf-8"));s.hallucination?.ignore&&e.push(...s.hallucination.ignore),s.ignore&&e.push(...s.ignore)}catch(e){}return e}_findInNodeModules(e,t){let s=path.dirname(e);const n=this.config.rootPath;for(;s.length>=n.length;){const e=path.join(s,"node_modules",t);try{if(fs.existsSync(e))return!0}catch(e){}const n=path.dirname(s);if(n===s)break;s=n}return!1}}module.exports=HallucinationDetector;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const fs=require("fs"),path=require("path"),os=require("os"),crypto=require("crypto"),TRIAL_HMAC_SECRET_DEFAULT="thuban-trial-silverwings-2026",THUBAN_DIR=path.join(os.homedir(),".thuban"),USAGE_FILE=path.join(THUBAN_DIR,"usage.json"),LICENSE_FILE=path.join(THUBAN_DIR,"license.json"),ED25519_PUBLIC_KEY_DER_B64="MCowBQYDK2VwAyEAyytegj0i6LHfXajJXodgEW6kAS9HxkWok+H3gGEy1lA=";function _trialBase64urlDecode(e){const t=e+"===".slice((e.length+3)%4);return Buffer.from(t.replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf-8")}function _trialHmac8(e){const t=process.env.TRIAL_HMAC_SECRET||TRIAL_HMAC_SECRET_DEFAULT;return crypto.createHmac("sha256",t).update(e).digest("hex").substring(0,8)}function validateTrialKey(e){const t=e&&e.match(/^THUBAN-TRIAL-([A-Za-z0-9_-]+)-([A-Fa-f0-9]{8})$/);if(!t)return null;const s=t[1],r=t[2],a=_trialHmac8(`THUBAN-TRIAL-${s}`);if(r.toLowerCase()!==a.toLowerCase())return null;let i;try{i=JSON.parse(_trialBase64urlDecode(s))}catch(e){return null}if(!i||!i.x||!i.e)return null;const n=Math.floor(Date.now()/1e3),o=n>i.x,c=Math.max(0,Math.ceil((i.x-n)/86400));return{valid:!o,expired:o,email:i.e,name:i.n,invitedBy:i.i,expiresAt:new Date(1e3*i.x).toISOString(),daysRemaining:c,tier:"trial"}}const TIERS={free:{name:"Free",price:"$0/forever",maxFiles:100,maxProjects:3,scansPerMonth:200,showFullDetails:!0,showDashboard:!0,showAutoFix:!1,showCIAction:!1,showVSCode:!0,showMCP:!1,teaserIssues:1/0,maxHallucinationDetail:1/0},pro:{name:"Pro",price:"$1/month",maxFiles:1/0,maxProjects:1/0,scansPerMonth:1/0,showFullDetails:!0,showDashboard:!0,showAutoFix:!0,showCIAction:!1,showVSCode:!0,showMCP:!0,teaserIssues:1/0,maxHallucinationDetail:1/0},team:{name:"Team",price:"$5/month flat",maxFiles:1/0,maxProjects:1/0,scansPerMonth:1/0,showFullDetails:!0,showDashboard:!0,showAutoFix:!0,showCIAction:!0,showVSCode:!0,showMCP:!0,teaserIssues:1/0,maxHallucinationDetail:1/0},enterprise:{name:"Enterprise",price:"$29/month",maxFiles:1/0,maxProjects:1/0,scansPerMonth:1/0,showFullDetails:!0,showDashboard:!0,showAutoFix:!0,showCIAction:!0,showVSCode:!0,showMCP:!0,showSSO:!0,showAuditLogs:!0,showSLA:!0,teaserIssues:1/0,maxHallucinationDetail:1/0},trial:{name:"Trial",price:"Free (14 days)",maxFiles:1/0,maxProjects:1/0,scansPerMonth:1/0,showFullDetails:!0,showDashboard:!0,showAutoFix:!0,showCIAction:!0,showVSCode:!0,showMCP:!0,teaserIssues:1/0,maxHallucinationDetail:1/0}};class LicenseManager{constructor(){this._ensureDir(),this.machineId=this._getMachineId(),this.usage=this._loadUsage(),this.license=this._loadLicense()}getTier(){if("true"===process.env.THUBAN_DEV_MODE&&!__filename.includes("node_modules"))return"enterprise";if(!this.license||!this.license.key)return"free";if(this.license.key.startsWith("THUBAN-TRIAL-")){const e=validateTrialKey(this.license.key);return e?e.expired?(this._trialExpired=!0,"free"):(this._trialInfo=e,"trial"):"free"}return this._validateKey(this.license.key)&&this.license.tier||"free"}getTierConfig(){return"true"!==process.env.THUBAN_DEV_MODE||__filename.includes("node_modules")?TIERS[this.getTier()]||TIERS.free:TIERS.pro}canScan(){if("true"===process.env.THUBAN_DEV_MODE&&!__filename.includes("node_modules"))return{allowed:!0,remaining:1/0,devMode:!0};const e=this.getTierConfig();if(e.scansPerMonth===1/0)return{allowed:!0,remaining:1/0};const t=this._currentMonth(),s=this.usage.scans?.[t]||0,r=Math.max(0,e.scansPerMonth-s);return{allowed:r>0,remaining:r,limit:e.scansPerMonth,used:s,resetsOn:this._nextMonthDate()}}recordScan(){if("true"===process.env.THUBAN_DEV_MODE&&!__filename.includes("node_modules"))return;const e=this._currentMonth();this.usage.scans||(this.usage.scans={}),this.usage.scans[e]=(this.usage.scans[e]||0)+1,this.usage.lastScan=(new Date).toISOString(),this.usage.totalScans=(this.usage.totalScans||0)+1,this._saveUsage()}activate(e){if(e&&e.startsWith("THUBAN-TRIAL-")){const t=validateTrialKey(e);return t?t.expired?{success:!1,error:`Trial key expired on ${new Date(t.expiresAt).toLocaleDateString("en-GB")}. Upgrade at thuban.dev/pricing`}:(this.license={key:e,tier:"trial",activatedAt:(new Date).toISOString(),machineId:this.machineId,trialExpiresAt:t.expiresAt,trialEmail:t.email,trialName:t.name},this._saveLicense(),{success:!0,tier:"trial",tierName:"Trial (Pro features)",daysRemaining:t.daysRemaining,expiresAt:t.expiresAt}):{success:!1,error:"Invalid trial key format or signature"}}const t=this._validateKey(e);return t?(this.license={key:e,tier:t.tier,activatedAt:(new Date).toISOString(),machineId:this.machineId},this._saveLicense(),{success:!0,tier:t.tier,tierName:TIERS[t.tier]?.name||t.tier}):{success:!1,error:"Invalid license key format"}}deactivate(){return this.license={},this._saveLicense(),{success:!0}}getStatus(){const e=this.getTier(),t=this.getTierConfig(),s=this.canScan();let r=!1;return r="true"===process.env.THUBAN_DEV_MODE&&!__filename.includes("node_modules"),{tier:e,tierName:t.name,machineId:this.machineId.substring(0,8)+"...",licensed:"free"!==e,devMode:r,scansUsed:r?0:s.used||0,scansRemaining:s.remaining,scansLimit:r?1/0:s.limit||t.scansPerMonth,totalScans:this.usage.totalScans||0,..."trial"===e&&this._trialInfo?{trialDaysRemaining:this._trialInfo.daysRemaining,trialExpiresAt:this._trialInfo.expiresAt,trialName:this._trialInfo.name,trialEmail:this._trialInfo.email}:{},...this._trialExpired?{trialExpired:!0}:{},features:{fullDetails:t.showFullDetails,dashboard:t.showDashboard,autoFix:t.showAutoFix,ciAction:t.showCIAction,scheduledScans:"free"!==e&&"trial"!==e}}}canUseProFeature(e="This feature"){const t=this.getTier();return"free"===t?{allowed:!1,message:`${e} is available on Thuban Pro and above.`}:{allowed:!0,tier:t}}_ensureDir(){try{fs.existsSync(THUBAN_DIR)||fs.mkdirSync(THUBAN_DIR,{recursive:!0})}catch(e){}}_getMachineId(){const e=[os.hostname(),os.userInfo().username,os.platform(),os.arch()].join("|");try{const t=os.networkInterfaces(),s=Object.values(t).flat().filter(e=>!e.internal&&e.mac&&"00:00:00:00:00:00"!==e.mac).map(e=>e.mac).sort();if(s.length>0)return crypto.createHash("sha256").update(e+"|"+s[0]).digest("hex")}catch(e){}return crypto.createHash("sha256").update(e).digest("hex")}_loadUsage(){try{return JSON.parse(fs.readFileSync(USAGE_FILE,"utf-8"))}catch(e){return{scans:{},totalScans:0}}}_atomicWriteSync(e,t){const s=e+".tmp."+process.pid+"."+Date.now();try{fs.writeFileSync(s,t,"utf-8"),fs.renameSync(s,e)}catch(e){try{fs.unlinkSync(s)}catch{}}}_saveUsage(){try{this._atomicWriteSync(USAGE_FILE,JSON.stringify(this.usage,null,2))}catch(e){}}_loadLicense(){try{return JSON.parse(fs.readFileSync(LICENSE_FILE,"utf-8"))}catch(e){return{}}}_saveLicense(){try{this._atomicWriteSync(LICENSE_FILE,JSON.stringify(this.license,null,2))}catch(e){}}_validateKey(e){if(!e||"string"!=typeof e)return null;const t=e.match(/^THUBAN-(FREE|PRO|TEAM|ENT)-([A-Za-z0-9]{16})-([A-Fa-f0-9]{8,})$/);if(!t)return null;const s=t[1],r=t[2],a=t[3],i={FREE:"free",PRO:"pro",TEAM:"team",ENT:"enterprise"};try{const e=crypto.createPublicKey({key:Buffer.from(ED25519_PUBLIC_KEY_DER_B64,"base64"),format:"der",type:"spki"}),t=Buffer.from(`THUBAN-${s}-${r}`),n=Buffer.from(a,"hex");if(crypto.verify(null,t,e,n))return{tier:i[s]||"free",valid:!0,method:"ed25519"}}catch(e){}return null}_currentMonth(){const e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}`}_nextMonthDate(){const e=new Date;return new Date(e.getFullYear(),e.getMonth()+1,1).toISOString().split("T")[0]}static generateKey(e="PRO"){const t=process.env.THUBAN_SIGNING_PRIVATE_KEY;if(!t)throw new Error("THUBAN_SIGNING_PRIVATE_KEY environment variable is required to generate license keys. This keeps the signing key out of source control and off end-user machines.");const s=crypto.createPrivateKey({key:Buffer.from(t,"base64"),format:"der",type:"pkcs8"}),r=crypto.randomBytes(8).toString("hex"),a=Buffer.from(`THUBAN-${e}-${r}`);return`THUBAN-${e}-${r}-${crypto.sign(null,a,s).toString("hex")}`}}module.exports=LicenseManager,module.exports.validateTrialKey=validateTrialKey;
|