vibecheck-ai 2.0.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/.generated +25 -0
- package/bin/_deprecations.js +463 -0
- package/bin/_router.js +46 -0
- package/bin/cli-hygiene.js +241 -0
- package/bin/dev/run-v2-torture.js +30 -0
- package/bin/registry.js +656 -0
- package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
- package/bin/runners/ENHANCEMENT_GUIDE.md +121 -0
- package/bin/runners/REPORT_AUDIT.md +64 -0
- package/bin/runners/cli-utils.js +1070 -0
- package/bin/runners/context/ai-task-decomposer.js +337 -0
- package/bin/runners/context/analyzer.js +513 -0
- package/bin/runners/context/api-contracts.js +427 -0
- package/bin/runners/context/context-diff.js +342 -0
- package/bin/runners/context/context-pruner.js +291 -0
- package/bin/runners/context/dependency-graph.js +414 -0
- package/bin/runners/context/generators/claude.js +107 -0
- package/bin/runners/context/generators/codex.js +108 -0
- package/bin/runners/context/generators/copilot.js +119 -0
- package/bin/runners/context/generators/cursor-enhanced.js +2525 -0
- package/bin/runners/context/generators/cursor.js +514 -0
- package/bin/runners/context/generators/mcp.js +169 -0
- package/bin/runners/context/generators/windsurf.js +180 -0
- package/bin/runners/context/git-context.js +304 -0
- package/bin/runners/context/index.js +1110 -0
- package/bin/runners/context/insights.js +173 -0
- package/bin/runners/context/mcp-server/generate-rules.js +337 -0
- package/bin/runners/context/mcp-server/index.js +1176 -0
- package/bin/runners/context/mcp-server/package.json +24 -0
- package/bin/runners/context/memory.js +200 -0
- package/bin/runners/context/monorepo.js +215 -0
- package/bin/runners/context/multi-repo-federation.js +404 -0
- package/bin/runners/context/patterns.js +253 -0
- package/bin/runners/context/proof-context.js +1264 -0
- package/bin/runners/context/security-scanner.js +541 -0
- package/bin/runners/context/semantic-search.js +350 -0
- package/bin/runners/context/shared.js +264 -0
- package/bin/runners/context/team-conventions.js +336 -0
- package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -0
- package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +488 -0
- package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
- package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
- package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
- package/bin/runners/lib/agent-firewall/claims/extractor.js +303 -0
- package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
- package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
- package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
- package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
- package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
- package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
- package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
- package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +127 -0
- package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +213 -0
- package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
- package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
- package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
- package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
- package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
- package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
- package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
- package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
- package/bin/runners/lib/agent-firewall/index.js +200 -0
- package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
- package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
- package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -0
- package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
- package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
- package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
- package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
- package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
- package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
- package/bin/runners/lib/agent-firewall/interceptor/base.js +308 -0
- package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +90 -0
- package/bin/runners/lib/agent-firewall/policy/engine.js +103 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +451 -0
- package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +79 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +227 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +191 -0
- package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
- package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
- package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
- package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
- package/bin/runners/lib/agent-firewall/session/index.js +26 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +137 -0
- package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
- package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
- package/bin/runners/lib/ai-bridge.js +416 -0
- package/bin/runners/lib/analysis-core.js +309 -0
- package/bin/runners/lib/analyzers.js +2500 -0
- package/bin/runners/lib/api-client.js +269 -0
- package/bin/runners/lib/approve-output.js +235 -0
- package/bin/runners/lib/artifact-envelope.js +540 -0
- package/bin/runners/lib/assets/vibecheck-logo.png +0 -0
- package/bin/runners/lib/audit-bridge.js +391 -0
- package/bin/runners/lib/auth-shared.js +977 -0
- package/bin/runners/lib/auth-truth.js +193 -0
- package/bin/runners/lib/auth.js +215 -0
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/backup.js +62 -0
- package/bin/runners/lib/billing.js +107 -0
- package/bin/runners/lib/checkpoint.js +941 -0
- package/bin/runners/lib/claims.js +118 -0
- package/bin/runners/lib/classify-output.js +204 -0
- package/bin/runners/lib/cleanup/engine.js +571 -0
- package/bin/runners/lib/cleanup/index.js +53 -0
- package/bin/runners/lib/cleanup/output.js +375 -0
- package/bin/runners/lib/cleanup/rules.js +1060 -0
- package/bin/runners/lib/cli-output.js +400 -0
- package/bin/runners/lib/cli-ui.js +540 -0
- package/bin/runners/lib/compliance-bridge-new.js +0 -0
- package/bin/runners/lib/compliance-bridge.js +165 -0
- package/bin/runners/lib/contracts/auth-contract.js +202 -0
- package/bin/runners/lib/contracts/env-contract.js +181 -0
- package/bin/runners/lib/contracts/external-contract.js +206 -0
- package/bin/runners/lib/contracts/guard.js +168 -0
- package/bin/runners/lib/contracts/index.js +89 -0
- package/bin/runners/lib/contracts/plan-validator.js +311 -0
- package/bin/runners/lib/contracts/route-contract.js +199 -0
- package/bin/runners/lib/contracts.js +804 -0
- package/bin/runners/lib/default-config.js +127 -0
- package/bin/runners/lib/detect.js +89 -0
- package/bin/runners/lib/detectors-v2.js +622 -0
- package/bin/runners/lib/doctor/autofix.js +254 -0
- package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
- package/bin/runners/lib/doctor/failure-signatures.js +526 -0
- package/bin/runners/lib/doctor/fix-script.js +336 -0
- package/bin/runners/lib/doctor/index.js +37 -0
- package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
- package/bin/runners/lib/doctor/modules/index.js +105 -0
- package/bin/runners/lib/doctor/modules/network.js +250 -0
- package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
- package/bin/runners/lib/doctor/modules/project.js +312 -0
- package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
- package/bin/runners/lib/doctor/modules/runtime.js +224 -0
- package/bin/runners/lib/doctor/modules/security.js +350 -0
- package/bin/runners/lib/doctor/modules/system.js +213 -0
- package/bin/runners/lib/doctor/modules/vibecheck.js +394 -0
- package/bin/runners/lib/doctor/reporter.js +262 -0
- package/bin/runners/lib/doctor/safe-repair.js +384 -0
- package/bin/runners/lib/doctor/service.js +262 -0
- package/bin/runners/lib/doctor/types.js +113 -0
- package/bin/runners/lib/doctor/ui.js +263 -0
- package/bin/runners/lib/doctor-enhanced.js +233 -0
- package/bin/runners/lib/doctor-output.js +226 -0
- package/bin/runners/lib/doctor-v2.js +608 -0
- package/bin/runners/lib/drift.js +425 -0
- package/bin/runners/lib/enforcement.js +72 -0
- package/bin/runners/lib/engine/ast-cache.js +210 -0
- package/bin/runners/lib/engine/auth-extractor.js +211 -0
- package/bin/runners/lib/engine/billing-extractor.js +112 -0
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
- package/bin/runners/lib/engine/env-extractor.js +207 -0
- package/bin/runners/lib/engine/express-extractor.js +208 -0
- package/bin/runners/lib/engine/extractors.js +849 -0
- package/bin/runners/lib/engine/index.js +207 -0
- package/bin/runners/lib/engine/repo-index.js +514 -0
- package/bin/runners/lib/engine/types.js +124 -0
- package/bin/runners/lib/engines/accessibility-engine.js +190 -0
- package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
- package/bin/runners/lib/engines/ast-cache.js +99 -0
- package/bin/runners/lib/engines/attack-detector.js +1192 -0
- package/bin/runners/lib/engines/code-quality-engine.js +255 -0
- package/bin/runners/lib/engines/console-logs-engine.js +115 -0
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
- package/bin/runners/lib/engines/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
- package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
- package/bin/runners/lib/engines/file-filter.js +131 -0
- package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
- package/bin/runners/lib/engines/mock-data-engine.js +272 -0
- package/bin/runners/lib/engines/parallel-processor.js +71 -0
- package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
- package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
- package/bin/runners/lib/engines/type-aware-engine.js +152 -0
- package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
- package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
- package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
- package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
- package/bin/runners/lib/enterprise-detect.js +603 -0
- package/bin/runners/lib/enterprise-init.js +942 -0
- package/bin/runners/lib/entitlements-v2.js +265 -0
- package/bin/runners/lib/entitlements.generated.js +0 -0
- package/bin/runners/lib/entitlements.js +340 -0
- package/bin/runners/lib/env-resolver.js +417 -0
- package/bin/runners/lib/env-template.js +66 -0
- package/bin/runners/lib/env.js +189 -0
- package/bin/runners/lib/error-handler.js +368 -0
- package/bin/runners/lib/error-messages.js +289 -0
- package/bin/runners/lib/evidence-pack.js +684 -0
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/extractors/client-calls.js +990 -0
- package/bin/runners/lib/extractors/fastify-route-dump.js +573 -0
- package/bin/runners/lib/extractors/fastify-routes.js +426 -0
- package/bin/runners/lib/extractors/index.js +363 -0
- package/bin/runners/lib/extractors/next-routes.js +524 -0
- package/bin/runners/lib/extractors/proof-graph.js +431 -0
- package/bin/runners/lib/extractors/route-matcher.js +451 -0
- package/bin/runners/lib/extractors/truthpack-v2.js +377 -0
- package/bin/runners/lib/extractors/ui-bindings.js +547 -0
- package/bin/runners/lib/finding-id.js +69 -0
- package/bin/runners/lib/finding-sorter.js +89 -0
- package/bin/runners/lib/findings-schema.js +281 -0
- package/bin/runners/lib/fingerprint.js +377 -0
- package/bin/runners/lib/firewall-prompt.js +50 -0
- package/bin/runners/lib/fix-output.js +228 -0
- package/bin/runners/lib/global-flags.js +250 -0
- package/bin/runners/lib/graph/graph-builder.js +265 -0
- package/bin/runners/lib/graph/html-renderer.js +413 -0
- package/bin/runners/lib/graph/index.js +32 -0
- package/bin/runners/lib/graph/runtime-collector.js +215 -0
- package/bin/runners/lib/graph/static-extractor.js +518 -0
- package/bin/runners/lib/help-formatter.js +413 -0
- package/bin/runners/lib/html-proof-report.js +913 -0
- package/bin/runners/lib/html-report.js +650 -0
- package/bin/runners/lib/init-wizard.js +601 -0
- package/bin/runners/lib/interactive-menu.js +1496 -0
- package/bin/runners/lib/json-output.js +76 -0
- package/bin/runners/lib/llm.js +75 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/meter.js +61 -0
- package/bin/runners/lib/missions/briefing.js +427 -0
- package/bin/runners/lib/missions/checkpoint.js +753 -0
- package/bin/runners/lib/missions/evidence.js +126 -0
- package/bin/runners/lib/missions/hardening.js +851 -0
- package/bin/runners/lib/missions/plan.js +648 -0
- package/bin/runners/lib/missions/safety-gates.js +645 -0
- package/bin/runners/lib/missions/schema.js +478 -0
- package/bin/runners/lib/missions/templates.js +317 -0
- package/bin/runners/lib/next-action.js +560 -0
- package/bin/runners/lib/packs/bundle.js +675 -0
- package/bin/runners/lib/packs/evidence-pack.js +671 -0
- package/bin/runners/lib/packs/pack-factory.js +837 -0
- package/bin/runners/lib/packs/permissions-pack.js +686 -0
- package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
- package/bin/runners/lib/patch.js +40 -0
- package/bin/runners/lib/permissions/auth-model.js +213 -0
- package/bin/runners/lib/permissions/idor-prover.js +205 -0
- package/bin/runners/lib/permissions/index.js +45 -0
- package/bin/runners/lib/permissions/matrix-builder.js +198 -0
- package/bin/runners/lib/pkgjson.js +28 -0
- package/bin/runners/lib/policy.js +295 -0
- package/bin/runners/lib/polish/accessibility.js +62 -0
- package/bin/runners/lib/polish/analyzer.js +93 -0
- package/bin/runners/lib/polish/backend.js +87 -0
- package/bin/runners/lib/polish/configuration.js +83 -0
- package/bin/runners/lib/polish/documentation.js +83 -0
- package/bin/runners/lib/polish/frontend.js +817 -0
- package/bin/runners/lib/polish/index.js +27 -0
- package/bin/runners/lib/polish/infrastructure.js +80 -0
- package/bin/runners/lib/polish/internationalization.js +85 -0
- package/bin/runners/lib/polish/libraries.js +180 -0
- package/bin/runners/lib/polish/observability.js +75 -0
- package/bin/runners/lib/polish/performance.js +64 -0
- package/bin/runners/lib/polish/privacy.js +110 -0
- package/bin/runners/lib/polish/resilience.js +92 -0
- package/bin/runners/lib/polish/security.js +78 -0
- package/bin/runners/lib/polish/seo.js +71 -0
- package/bin/runners/lib/polish/styles.js +62 -0
- package/bin/runners/lib/polish/utils.js +104 -0
- package/bin/runners/lib/preflight.js +142 -0
- package/bin/runners/lib/prerequisites.js +149 -0
- package/bin/runners/lib/prove-output.js +220 -0
- package/bin/runners/lib/reality/correlation-detectors.js +359 -0
- package/bin/runners/lib/reality/index.js +318 -0
- package/bin/runners/lib/reality/request-hashing.js +416 -0
- package/bin/runners/lib/reality/request-mapper.js +453 -0
- package/bin/runners/lib/reality/safety-rails.js +463 -0
- package/bin/runners/lib/reality/semantic-snapshot.js +408 -0
- package/bin/runners/lib/reality/toast-detector.js +393 -0
- package/bin/runners/lib/reality-findings.js +84 -0
- package/bin/runners/lib/reality-output.js +231 -0
- package/bin/runners/lib/receipts.js +179 -0
- package/bin/runners/lib/redact.js +29 -0
- package/bin/runners/lib/replay/capsule-manager.js +154 -0
- package/bin/runners/lib/replay/index.js +263 -0
- package/bin/runners/lib/replay/player.js +348 -0
- package/bin/runners/lib/replay/recorder.js +331 -0
- package/bin/runners/lib/report-engine.js +626 -0
- package/bin/runners/lib/report-html.js +1233 -0
- package/bin/runners/lib/report-output.js +366 -0
- package/bin/runners/lib/report-templates.js +967 -0
- package/bin/runners/lib/report.js +135 -0
- package/bin/runners/lib/route-detection.js +1209 -0
- package/bin/runners/lib/route-truth.js +1322 -0
- package/bin/runners/lib/safelist/index.js +96 -0
- package/bin/runners/lib/safelist/integration.js +334 -0
- package/bin/runners/lib/safelist/matcher.js +696 -0
- package/bin/runners/lib/safelist/schema.js +948 -0
- package/bin/runners/lib/safelist/store.js +438 -0
- package/bin/runners/lib/sandbox/index.js +59 -0
- package/bin/runners/lib/sandbox/proof-chain.js +399 -0
- package/bin/runners/lib/sandbox/sandbox-runner.js +205 -0
- package/bin/runners/lib/sandbox/worktree.js +174 -0
- package/bin/runners/lib/scan-cache.js +330 -0
- package/bin/runners/lib/scan-output-schema.js +344 -0
- package/bin/runners/lib/scan-output.js +631 -0
- package/bin/runners/lib/scan-runner.js +135 -0
- package/bin/runners/lib/schema-validator.js +350 -0
- package/bin/runners/lib/schemas/ajv-validator.js +464 -0
- package/bin/runners/lib/schemas/contracts.schema.json +160 -0
- package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
- package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
- package/bin/runners/lib/schemas/finding.schema.json +100 -0
- package/bin/runners/lib/schemas/mission-pack.schema.json +206 -0
- package/bin/runners/lib/schemas/proof-graph.schema.json +176 -0
- package/bin/runners/lib/schemas/reality-report.schema.json +162 -0
- package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
- package/bin/runners/lib/schemas/run-request.schema.json +108 -0
- package/bin/runners/lib/schemas/share-pack.schema.json +180 -0
- package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
- package/bin/runners/lib/schemas/ship-report.schema.json +117 -0
- package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -0
- package/bin/runners/lib/schemas/validator.js +465 -0
- package/bin/runners/lib/schemas/verdict.schema.json +140 -0
- package/bin/runners/lib/score-history.js +282 -0
- package/bin/runners/lib/security-bridge.js +249 -0
- package/bin/runners/lib/server-usage.js +513 -0
- package/bin/runners/lib/share-pack.js +239 -0
- package/bin/runners/lib/ship-gate.js +832 -0
- package/bin/runners/lib/ship-manifest.js +1153 -0
- package/bin/runners/lib/ship-output-enterprise.js +239 -0
- package/bin/runners/lib/ship-output.js +1128 -0
- package/bin/runners/lib/snippets.js +67 -0
- package/bin/runners/lib/status-output.js +340 -0
- package/bin/runners/lib/terminal-ui.js +356 -0
- package/bin/runners/lib/truth.js +1691 -0
- package/bin/runners/lib/ui.js +562 -0
- package/bin/runners/lib/unified-cli-output.js +947 -0
- package/bin/runners/lib/unified-output.js +197 -0
- package/bin/runners/lib/upsell.js +410 -0
- package/bin/runners/lib/usage.js +153 -0
- package/bin/runners/lib/validate-patch.js +156 -0
- package/bin/runners/lib/verdict-engine.js +628 -0
- package/bin/runners/lib/verification.js +345 -0
- package/bin/runners/lib/why-tree.js +650 -0
- package/bin/runners/reality/engine.js +917 -0
- package/bin/runners/reality/flows.js +122 -0
- package/bin/runners/reality/report.js +378 -0
- package/bin/runners/reality/session.js +193 -0
- package/bin/runners/runAIAgent.js +229 -0
- package/bin/runners/runAgent.d.ts +5 -0
- package/bin/runners/runAgent.js +161 -0
- package/bin/runners/runAllowlist.js +418 -0
- package/bin/runners/runApprove.js +320 -0
- package/bin/runners/runAudit.js +692 -0
- package/bin/runners/runAuth.js +731 -0
- package/bin/runners/runCI.js +353 -0
- package/bin/runners/runCheckpoint.js +530 -0
- package/bin/runners/runClassify.js +928 -0
- package/bin/runners/runCleanup.js +343 -0
- package/bin/runners/runContext.d.ts +4 -0
- package/bin/runners/runContext.js +175 -0
- package/bin/runners/runDoctor.js +877 -0
- package/bin/runners/runEvidencePack.js +362 -0
- package/bin/runners/runFirewall.d.ts +5 -0
- package/bin/runners/runFirewall.js +134 -0
- package/bin/runners/runFirewallHook.d.ts +5 -0
- package/bin/runners/runFirewallHook.js +56 -0
- package/bin/runners/runFix.js +1355 -0
- package/bin/runners/runForge.js +451 -0
- package/bin/runners/runGuard.js +262 -0
- package/bin/runners/runInit.js +1927 -0
- package/bin/runners/runIntent.js +906 -0
- package/bin/runners/runKickoff.js +878 -0
- package/bin/runners/runLabs.js +424 -0
- package/bin/runners/runLaunch.js +2000 -0
- package/bin/runners/runLink.js +785 -0
- package/bin/runners/runMcp.js +1875 -0
- package/bin/runners/runPacks.js +2089 -0
- package/bin/runners/runPolish.d.ts +4 -0
- package/bin/runners/runPolish.js +390 -0
- package/bin/runners/runPromptFirewall.js +211 -0
- package/bin/runners/runProve.js +1411 -0
- package/bin/runners/runQuickstart.js +531 -0
- package/bin/runners/runReality.js +2260 -0
- package/bin/runners/runReport.js +726 -0
- package/bin/runners/runRuntime.js +110 -0
- package/bin/runners/runSafelist.js +1190 -0
- package/bin/runners/runScan.js +688 -0
- package/bin/runners/runShield.js +1282 -0
- package/bin/runners/runShip.js +1660 -0
- package/bin/runners/runTruth.d.ts +5 -0
- package/bin/runners/runTruth.js +101 -0
- package/bin/runners/runValidate.js +179 -0
- package/bin/runners/runWatch.js +478 -0
- package/bin/runners/utils.js +360 -0
- package/bin/scan.js +617 -0
- package/bin/vibecheck.js +1617 -0
- package/dist/guardrail/index.d.ts +2405 -0
- package/dist/guardrail/index.js +9747 -0
- package/dist/guardrail/index.js.map +1 -0
- package/dist/scanner/index.d.ts +282 -0
- package/dist/scanner/index.js +3395 -0
- package/dist/scanner/index.js.map +1 -0
- package/package.json +123 -104
- package/README.md +0 -491
- package/dist/index.js +0 -99711
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hardcoded Secrets Engine
|
|
3
|
+
* Detects API keys, tokens, passwords, and private keys in code.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { getAST, parseCode } = require("./ast-cache");
|
|
7
|
+
const traverse = require("@babel/traverse").default;
|
|
8
|
+
const t = require("@babel/types");
|
|
9
|
+
const { shouldExcludeFile, isTestContext, hasIgnoreDirective } = require("./file-filter");
|
|
10
|
+
|
|
11
|
+
// Enhanced patterns with more comprehensive detection
|
|
12
|
+
const SECRET_PATTERNS = [
|
|
13
|
+
{ name: "AWS Access Key", pattern: /AKIA[0-9A-Z]{16}/ },
|
|
14
|
+
{ name: "AWS Secret Key", pattern: /[0-9a-zA-Z/+]{40}/ },
|
|
15
|
+
{ name: "GitHub Token", pattern: /ghp_[0-9a-zA-Z]{36}/ },
|
|
16
|
+
{ name: "GitLab Token", pattern: /glpat-[0-9a-zA-Z\-_]{20,}/ },
|
|
17
|
+
{ name: "Slack Token", pattern: /xox[baprs]-[0-9a-zA-Z]{10,48}/ },
|
|
18
|
+
{ name: "Stripe Key", pattern: /sk_(live|test)_[0-9a-zA-Z]{24,}/ },
|
|
19
|
+
{ name: "Generic API Key", pattern: /[a-zA-Z0-9]{32,}/ },
|
|
20
|
+
{ name: "JWT Token", pattern: /eyJ[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+/ },
|
|
21
|
+
{ name: "Private Key", pattern: /-----BEGIN (RSA |EC )?PRIVATE KEY-----/ },
|
|
22
|
+
{ name: "Database URL", pattern: /(mongodb|postgresql|mysql):\/\/[^\\s]+/ },
|
|
23
|
+
{ name: "Password", pattern: /(password|passwd|pwd)\s*[:=]\s*['"][^'"]+['"]/i },
|
|
24
|
+
{ name: "Bearer Token", pattern: /Bearer\s+[a-zA-Z0-9\-_\.]+/i },
|
|
25
|
+
{ name: "OAuth Token", pattern: /ya29\.[0-9A-Za-z\-_]+/ },
|
|
26
|
+
{ name: "Twilio Key", pattern: /SK[0-9a-fA-F]{32}/ },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
function getContext(code, start, length = 80) {
|
|
30
|
+
const contextStart = Math.max(0, start - length / 2);
|
|
31
|
+
const contextEnd = Math.min(code.length, start + length / 2);
|
|
32
|
+
return code.slice(contextStart, contextEnd).replace(/\n/g, " ").trim();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isLikelyFalsePositive(value) {
|
|
36
|
+
// Exclude obvious placeholders
|
|
37
|
+
const placeholders = [
|
|
38
|
+
"YOUR_API_KEY",
|
|
39
|
+
"API_KEY_HERE",
|
|
40
|
+
"REPLACE_ME",
|
|
41
|
+
"CHANGE_ME",
|
|
42
|
+
"INSERT_KEY",
|
|
43
|
+
"TODO",
|
|
44
|
+
"EXAMPLE",
|
|
45
|
+
"SAMPLE",
|
|
46
|
+
"TEST",
|
|
47
|
+
"DUMMY",
|
|
48
|
+
];
|
|
49
|
+
const upper = String(value).toUpperCase();
|
|
50
|
+
return placeholders.some((p) => upper.includes(p));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function analyzeHardcodedSecrets(code, filePath) {
|
|
54
|
+
const findings = [];
|
|
55
|
+
|
|
56
|
+
if (shouldExcludeFile(filePath)) return findings;
|
|
57
|
+
if (isTestContext(code, filePath)) return findings;
|
|
58
|
+
if (hasIgnoreDirective(code, "hardcoded-secrets")) return findings;
|
|
59
|
+
|
|
60
|
+
const ast = getAST(code, filePath);
|
|
61
|
+
if (!ast) return findings;
|
|
62
|
+
|
|
63
|
+
const lines = code.split("\n");
|
|
64
|
+
|
|
65
|
+
// Check string literals for secrets
|
|
66
|
+
traverse(ast, {
|
|
67
|
+
StringLiteral(path) {
|
|
68
|
+
const value = path.node.value;
|
|
69
|
+
if (!value || value.length < 12) return;
|
|
70
|
+
if (isLikelyFalsePositive(value)) return;
|
|
71
|
+
|
|
72
|
+
for (const secretPattern of SECRET_PATTERNS) {
|
|
73
|
+
const match = value.match(secretPattern.pattern);
|
|
74
|
+
if (!match) continue;
|
|
75
|
+
|
|
76
|
+
const loc = path.node.loc?.start;
|
|
77
|
+
if (!loc) continue;
|
|
78
|
+
|
|
79
|
+
const line = loc.line;
|
|
80
|
+
const context = getContext(code, path.node.start || 0);
|
|
81
|
+
|
|
82
|
+
findings.push({
|
|
83
|
+
type: "hardcoded_secret",
|
|
84
|
+
severity: "BLOCK",
|
|
85
|
+
category: "Security",
|
|
86
|
+
file: filePath,
|
|
87
|
+
line,
|
|
88
|
+
column: loc.column,
|
|
89
|
+
title: `Hardcoded ${secretPattern.name} detected`,
|
|
90
|
+
message: `Found potential ${secretPattern.name} in string literal. Move to environment variables or secret manager.`,
|
|
91
|
+
codeSnippet: lines[line - 1]?.trim(),
|
|
92
|
+
evidence: context,
|
|
93
|
+
confidence: secretPattern.name === "Generic API Key" ? "low" : "high",
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
TemplateLiteral(path) {
|
|
99
|
+
// Template literals may contain secrets in raw strings (rare), but catch if a quasi looks like a token.
|
|
100
|
+
for (const quasi of path.node.quasis || []) {
|
|
101
|
+
const value = quasi.value?.cooked || "";
|
|
102
|
+
if (!value || value.length < 12) continue;
|
|
103
|
+
if (isLikelyFalsePositive(value)) continue;
|
|
104
|
+
|
|
105
|
+
for (const secretPattern of SECRET_PATTERNS) {
|
|
106
|
+
const match = value.match(secretPattern.pattern);
|
|
107
|
+
if (!match) continue;
|
|
108
|
+
|
|
109
|
+
const loc = quasi.loc?.start || path.node.loc?.start;
|
|
110
|
+
if (!loc) continue;
|
|
111
|
+
|
|
112
|
+
const line = loc.line;
|
|
113
|
+
const context = getContext(code, quasi.start || path.node.start || 0);
|
|
114
|
+
|
|
115
|
+
findings.push({
|
|
116
|
+
type: "hardcoded_secret",
|
|
117
|
+
severity: "BLOCK",
|
|
118
|
+
category: "Security",
|
|
119
|
+
file: filePath,
|
|
120
|
+
line,
|
|
121
|
+
column: loc.column,
|
|
122
|
+
title: `Hardcoded ${secretPattern.name} detected`,
|
|
123
|
+
message: `Found potential ${secretPattern.name} in template literal. Move to environment variables or secret manager.`,
|
|
124
|
+
codeSnippet: lines[line - 1]?.trim(),
|
|
125
|
+
evidence: context,
|
|
126
|
+
confidence: secretPattern.name === "Generic API Key" ? "low" : "high",
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return findings;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
analyzeHardcodedSecrets,
|
|
138
|
+
parseCode,
|
|
139
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Data Engine
|
|
3
|
+
* Detects mock, fake, or placeholder data in production code.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { getAST, parseCode } = require("./ast-cache");
|
|
7
|
+
const traverse = require("@babel/traverse").default;
|
|
8
|
+
const { shouldExcludeFile, isTestContext, hasIgnoreDirective } = require("./file-filter");
|
|
9
|
+
|
|
10
|
+
// Enhanced mock data patterns
|
|
11
|
+
const MOCK_PATTERNS = [
|
|
12
|
+
{ pattern: /mock/i, type: "mock_reference", message: "Mock reference found" },
|
|
13
|
+
{ pattern: /fake/i, type: "fake_data", message: "Fake data reference found" },
|
|
14
|
+
{ pattern: /dummy/i, type: "dummy_data", message: "Dummy data reference found" },
|
|
15
|
+
{ pattern: /test.*data/i, type: "test_data", message: "Test data reference found" },
|
|
16
|
+
{ pattern: /lorem ipsum/i, type: "lorem_ipsum", message: "Lorem ipsum placeholder found" },
|
|
17
|
+
{ pattern: /todo|fixme/i, type: "todo_fixme", message: "TODO/FIXME found in code" },
|
|
18
|
+
{ pattern: /placeholder/i, type: "placeholder", message: "Placeholder reference found" },
|
|
19
|
+
{ pattern: /example/i, type: "example_data", message: "Example reference found" },
|
|
20
|
+
{ pattern: /sample/i, type: "sample_data", message: "Sample data reference found" },
|
|
21
|
+
{ pattern: /hardcode/i, type: "hardcoded", message: "Hardcoded data reference found" },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
// Common mock data values
|
|
25
|
+
const MOCK_VALUES = [
|
|
26
|
+
"test",
|
|
27
|
+
"demo",
|
|
28
|
+
"example",
|
|
29
|
+
"sample",
|
|
30
|
+
"placeholder",
|
|
31
|
+
"lorem",
|
|
32
|
+
"ipsum",
|
|
33
|
+
"foo",
|
|
34
|
+
"bar",
|
|
35
|
+
"baz",
|
|
36
|
+
"mock",
|
|
37
|
+
"fake",
|
|
38
|
+
"dummy",
|
|
39
|
+
"12345",
|
|
40
|
+
"password",
|
|
41
|
+
"admin",
|
|
42
|
+
"user",
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
function analyzeMockData(code, filePath) {
|
|
46
|
+
const findings = [];
|
|
47
|
+
|
|
48
|
+
if (shouldExcludeFile(filePath)) return findings;
|
|
49
|
+
if (isTestContext(code, filePath)) return findings;
|
|
50
|
+
if (hasIgnoreDirective(code, "mock-data")) return findings;
|
|
51
|
+
|
|
52
|
+
const ast = getAST(code, filePath);
|
|
53
|
+
if (!ast) return findings;
|
|
54
|
+
|
|
55
|
+
const lines = code.split("\n");
|
|
56
|
+
|
|
57
|
+
// Check string literals for mock data
|
|
58
|
+
traverse(ast, {
|
|
59
|
+
StringLiteral(path) {
|
|
60
|
+
const value = path.node.value;
|
|
61
|
+
if (!value || value.length < 2) return;
|
|
62
|
+
|
|
63
|
+
// Check for common mock values (case-insensitive)
|
|
64
|
+
const lower = value.toLowerCase();
|
|
65
|
+
if (MOCK_VALUES.includes(lower)) {
|
|
66
|
+
const loc = path.node.loc?.start;
|
|
67
|
+
if (!loc) return;
|
|
68
|
+
|
|
69
|
+
findings.push({
|
|
70
|
+
type: "mock_value",
|
|
71
|
+
severity: "INFO",
|
|
72
|
+
category: "CodeQuality",
|
|
73
|
+
file: filePath,
|
|
74
|
+
line: loc.line,
|
|
75
|
+
column: loc.column,
|
|
76
|
+
title: "Potential mock value in string literal",
|
|
77
|
+
message: `String literal "${value}" looks like mock/placeholder data.`,
|
|
78
|
+
codeSnippet: lines[loc.line - 1]?.trim(),
|
|
79
|
+
confidence: "low",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check for mock patterns
|
|
84
|
+
for (const mockPattern of MOCK_PATTERNS) {
|
|
85
|
+
if (mockPattern.pattern.test(value)) {
|
|
86
|
+
const loc = path.node.loc?.start;
|
|
87
|
+
if (!loc) continue;
|
|
88
|
+
|
|
89
|
+
findings.push({
|
|
90
|
+
type: mockPattern.type,
|
|
91
|
+
severity: mockPattern.type === "todo_fixme" ? "WARN" : "INFO",
|
|
92
|
+
category: "CodeQuality",
|
|
93
|
+
file: filePath,
|
|
94
|
+
line: loc.line,
|
|
95
|
+
column: loc.column,
|
|
96
|
+
title: mockPattern.message,
|
|
97
|
+
message: `Found "${mockPattern.pattern}" in string literal: "${value}"`,
|
|
98
|
+
codeSnippet: lines[loc.line - 1]?.trim(),
|
|
99
|
+
confidence: "low",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
Identifier(path) {
|
|
106
|
+
const name = path.node.name;
|
|
107
|
+
if (!name) return;
|
|
108
|
+
|
|
109
|
+
// Check for mock patterns in variable names (avoid huge noise: only longer names)
|
|
110
|
+
if (name.length < 5) return;
|
|
111
|
+
|
|
112
|
+
for (const mockPattern of MOCK_PATTERNS) {
|
|
113
|
+
if (mockPattern.pattern.test(name)) {
|
|
114
|
+
const loc = path.node.loc?.start;
|
|
115
|
+
if (!loc) continue;
|
|
116
|
+
|
|
117
|
+
findings.push({
|
|
118
|
+
type: mockPattern.type,
|
|
119
|
+
severity: mockPattern.type === "todo_fixme" ? "WARN" : "INFO",
|
|
120
|
+
category: "CodeQuality",
|
|
121
|
+
file: filePath,
|
|
122
|
+
line: loc.line,
|
|
123
|
+
column: loc.column,
|
|
124
|
+
title: `Mock-like identifier: ${name}`,
|
|
125
|
+
message: `Identifier name suggests mock/placeholder data: "${name}"`,
|
|
126
|
+
codeSnippet: lines[loc.line - 1]?.trim(),
|
|
127
|
+
confidence: "low",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return findings;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
analyzeMockData,
|
|
139
|
+
parseCode,
|
|
140
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parallel Processor
|
|
3
|
+
* Utility to process a list of files concurrently with bounded parallelism.
|
|
4
|
+
*
|
|
5
|
+
* NOTE: The caller provides `processor(filePath)` which may return any value.
|
|
6
|
+
* We collect both results and errors without crashing the whole run.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const os = require("os");
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Run a promise with an optional timeout.
|
|
13
|
+
*/
|
|
14
|
+
async function withTimeout(promise, timeoutMs, label = "operation") {
|
|
15
|
+
if (!timeoutMs || timeoutMs <= 0) return promise;
|
|
16
|
+
|
|
17
|
+
let timer = null;
|
|
18
|
+
const timeout = new Promise((_, reject) => {
|
|
19
|
+
timer = setTimeout(() => {
|
|
20
|
+
const err = new Error(`${label} timed out after ${timeoutMs}ms`);
|
|
21
|
+
err.code = "ETIMEDOUT";
|
|
22
|
+
reject(err);
|
|
23
|
+
}, timeoutMs);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
return await Promise.race([promise, timeout]);
|
|
28
|
+
} finally {
|
|
29
|
+
if (timer) clearTimeout(timer);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Process files in parallel with bounded concurrency.
|
|
35
|
+
*
|
|
36
|
+
* @param {string[]} files
|
|
37
|
+
* @param {(filePath: string) => Promise<any>} processor
|
|
38
|
+
* @param {object} options
|
|
39
|
+
* @returns {Promise<{results: Array<{file: string, result: any}>, errors: Array<{file: string, error: Error}>, stats: object}>}
|
|
40
|
+
*/
|
|
41
|
+
async function processFilesInParallel(files, processor, options = {}) {
|
|
42
|
+
const concurrency =
|
|
43
|
+
Number.isFinite(options.concurrency) && options.concurrency > 0
|
|
44
|
+
? Math.floor(options.concurrency)
|
|
45
|
+
: Math.max(1, Math.min(os.cpus().length, 8));
|
|
46
|
+
|
|
47
|
+
const timeoutMs = Number.isFinite(options.timeoutMs) ? options.timeoutMs : 0;
|
|
48
|
+
const stopOnError = Boolean(options.stopOnError);
|
|
49
|
+
const onProgress = typeof options.onProgress === "function" ? options.onProgress : null;
|
|
50
|
+
const signal = options.signal;
|
|
51
|
+
|
|
52
|
+
const results = [];
|
|
53
|
+
const errors = [];
|
|
54
|
+
|
|
55
|
+
let cursor = 0;
|
|
56
|
+
let completed = 0;
|
|
57
|
+
const startedAt = Date.now();
|
|
58
|
+
|
|
59
|
+
function reportProgress(file, kind) {
|
|
60
|
+
if (!onProgress) return;
|
|
61
|
+
try {
|
|
62
|
+
onProgress({
|
|
63
|
+
kind,
|
|
64
|
+
file,
|
|
65
|
+
completed,
|
|
66
|
+
total: files.length,
|
|
67
|
+
errors: errors.length,
|
|
68
|
+
elapsedMs: Date.now() - startedAt,
|
|
69
|
+
});
|
|
70
|
+
} catch {
|
|
71
|
+
// ignore progress handler failures
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function runFile(filePath) {
|
|
76
|
+
if (signal?.aborted) {
|
|
77
|
+
const err = new Error("Aborted");
|
|
78
|
+
err.code = "ABORTED";
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const label = `process(${filePath})`;
|
|
83
|
+
const result = await withTimeout(Promise.resolve().then(() => processor(filePath)), timeoutMs, label);
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function worker(workerId) {
|
|
88
|
+
// eslint-disable-next-line no-constant-condition
|
|
89
|
+
while (true) {
|
|
90
|
+
if (signal?.aborted) break;
|
|
91
|
+
if (stopOnError && errors.length) break;
|
|
92
|
+
|
|
93
|
+
const i = cursor++;
|
|
94
|
+
if (i >= files.length) break;
|
|
95
|
+
|
|
96
|
+
const filePath = files[i];
|
|
97
|
+
reportProgress(filePath, "start");
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const result = await runFile(filePath);
|
|
101
|
+
results.push({ file: filePath, result });
|
|
102
|
+
} catch (error) {
|
|
103
|
+
errors.push({ file: filePath, error });
|
|
104
|
+
reportProgress(filePath, "error");
|
|
105
|
+
} finally {
|
|
106
|
+
completed++;
|
|
107
|
+
reportProgress(filePath, "done");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const workers = Array.from({ length: Math.min(concurrency, files.length) }, (_, i) => worker(i));
|
|
113
|
+
await Promise.all(workers);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
results,
|
|
117
|
+
errors,
|
|
118
|
+
stats: {
|
|
119
|
+
totalFiles: files.length,
|
|
120
|
+
processed: completed,
|
|
121
|
+
results: results.length,
|
|
122
|
+
errors: errors.length,
|
|
123
|
+
concurrency,
|
|
124
|
+
timeoutMs,
|
|
125
|
+
elapsedMs: Date.now() - startedAt,
|
|
126
|
+
aborted: Boolean(signal?.aborted),
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Process in sequential batches (useful when you want deterministic ordering).
|
|
133
|
+
*
|
|
134
|
+
* @param {string[]} files
|
|
135
|
+
* @param {(filePath: string) => Promise<any>} processor
|
|
136
|
+
* @param {number} batchSize
|
|
137
|
+
*/
|
|
138
|
+
async function processFilesInBatches(files, processor, batchSize = 10) {
|
|
139
|
+
const results = [];
|
|
140
|
+
const errors = [];
|
|
141
|
+
const size = Math.max(1, Number(batchSize) || 10);
|
|
142
|
+
|
|
143
|
+
for (let i = 0; i < files.length; i += size) {
|
|
144
|
+
const batch = files.slice(i, i + size);
|
|
145
|
+
const batchResults = await Promise.allSettled(batch.map((f) => Promise.resolve().then(() => processor(f))));
|
|
146
|
+
|
|
147
|
+
for (let j = 0; j < batchResults.length; j++) {
|
|
148
|
+
const file = batch[j];
|
|
149
|
+
const r = batchResults[j];
|
|
150
|
+
if (r.status === "fulfilled") {
|
|
151
|
+
results.push({ file, result: r.value });
|
|
152
|
+
} else {
|
|
153
|
+
errors.push({ file, error: r.reason });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { results, errors };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = {
|
|
162
|
+
processFilesInParallel,
|
|
163
|
+
processFilesInBatches,
|
|
164
|
+
};
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance Issues Engine
|
|
3
|
+
* Detects potential performance problems:
|
|
4
|
+
* - Nested loops
|
|
5
|
+
* - Potential memory leaks (event listeners without cleanup)
|
|
6
|
+
* - Expensive operations in render-like contexts (heuristic)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { getAST, parseCode } = require("./ast-cache");
|
|
10
|
+
const traverse = require("@babel/traverse").default;
|
|
11
|
+
const t = require("@babel/types");
|
|
12
|
+
const { shouldExcludeFile, isTestContext, hasIgnoreDirective } = require("./file-filter");
|
|
13
|
+
|
|
14
|
+
function snippetForLine(lines, line) {
|
|
15
|
+
return lines[line - 1] ? lines[line - 1].trim() : "";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isLoopStatement(node) {
|
|
19
|
+
return (
|
|
20
|
+
t.isForStatement(node) ||
|
|
21
|
+
t.isForInStatement(node) ||
|
|
22
|
+
t.isForOfStatement(node) ||
|
|
23
|
+
t.isWhileStatement(node) ||
|
|
24
|
+
t.isDoWhileStatement(node)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getEventName(callNode) {
|
|
29
|
+
const arg0 = callNode.arguments?.[0];
|
|
30
|
+
if (t.isStringLiteral(arg0)) return arg0.value;
|
|
31
|
+
if (t.isIdentifier(arg0)) return arg0.name;
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function calleePropertyName(callNode) {
|
|
36
|
+
const callee = callNode.callee;
|
|
37
|
+
if (t.isMemberExpression(callee) && t.isIdentifier(callee.property) && !callee.computed) return callee.property.name;
|
|
38
|
+
if (t.isIdentifier(callee)) return callee.name;
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function hasMatchingRemoveEventListener(fnPath, eventName) {
|
|
43
|
+
let found = false;
|
|
44
|
+
|
|
45
|
+
fnPath.traverse({
|
|
46
|
+
Function(inner) {
|
|
47
|
+
if (inner !== fnPath) inner.skip();
|
|
48
|
+
},
|
|
49
|
+
CallExpression(p) {
|
|
50
|
+
const name = calleePropertyName(p.node);
|
|
51
|
+
if (name !== "removeEventListener") return;
|
|
52
|
+
const ev = getEventName(p.node);
|
|
53
|
+
if (!eventName || !ev) {
|
|
54
|
+
// no event info: still counts as cleanup
|
|
55
|
+
found = true;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (ev === eventName) found = true;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return found;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isLikelyRenderContext(path) {
|
|
66
|
+
// Heuristic: inside a function named render, or a React component (PascalCase) returning JSX
|
|
67
|
+
const fn = path.getFunctionParent();
|
|
68
|
+
if (!fn) return false;
|
|
69
|
+
|
|
70
|
+
const node = fn.node;
|
|
71
|
+
let name = null;
|
|
72
|
+
|
|
73
|
+
if (t.isFunctionDeclaration(node) && node.id?.name) name = node.id.name;
|
|
74
|
+
if ((t.isFunctionExpression(node) || t.isArrowFunctionExpression(node)) && t.isVariableDeclarator(fn.parent) && t.isIdentifier(fn.parent.id)) {
|
|
75
|
+
name = fn.parent.id.name;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (name === "render") return true;
|
|
79
|
+
if (name && /^[A-Z]/.test(name)) return true; // component-ish
|
|
80
|
+
|
|
81
|
+
// If function returns JSX somewhere
|
|
82
|
+
let returnsJSX = false;
|
|
83
|
+
fn.traverse({
|
|
84
|
+
Function(inner) {
|
|
85
|
+
if (inner !== fn) inner.skip();
|
|
86
|
+
},
|
|
87
|
+
ReturnStatement(r) {
|
|
88
|
+
if (t.isJSXElement(r.node.argument) || t.isJSXFragment(r.node.argument)) returnsJSX = true;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return returnsJSX;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function analyzePerformanceIssues(code, filePath) {
|
|
96
|
+
const findings = [];
|
|
97
|
+
|
|
98
|
+
if (shouldExcludeFile(filePath)) return findings;
|
|
99
|
+
if (isTestContext(code, filePath)) return findings;
|
|
100
|
+
if (hasIgnoreDirective(code, "performance")) return findings;
|
|
101
|
+
|
|
102
|
+
const ast = getAST(code, filePath);
|
|
103
|
+
if (!ast) return findings;
|
|
104
|
+
|
|
105
|
+
const lines = code.split("\n");
|
|
106
|
+
|
|
107
|
+
traverse(ast, {
|
|
108
|
+
// Nested loops - only flag 3+ levels deep
|
|
109
|
+
enter(path) {
|
|
110
|
+
if (!isLoopStatement(path.node)) return;
|
|
111
|
+
|
|
112
|
+
// Count nesting depth
|
|
113
|
+
let depth = 0;
|
|
114
|
+
let current = path;
|
|
115
|
+
while (current) {
|
|
116
|
+
if (isLoopStatement(current.node)) {
|
|
117
|
+
depth++;
|
|
118
|
+
}
|
|
119
|
+
current = current.parentPath;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Only flag if 3 or more levels deep
|
|
123
|
+
if (depth < 3) return;
|
|
124
|
+
|
|
125
|
+
const loc = path.node.loc?.start;
|
|
126
|
+
if (!loc) return;
|
|
127
|
+
|
|
128
|
+
findings.push({
|
|
129
|
+
type: "nested_loop",
|
|
130
|
+
severity: "WARN",
|
|
131
|
+
category: "Performance",
|
|
132
|
+
file: filePath,
|
|
133
|
+
line: loc.line,
|
|
134
|
+
column: loc.column,
|
|
135
|
+
title: `Deeply nested loop (${depth} levels)`,
|
|
136
|
+
message: "Deeply nested loops can be expensive. Consider optimizing or using better data structures.",
|
|
137
|
+
codeSnippet: snippetForLine(lines, loc.line),
|
|
138
|
+
confidence: "med",
|
|
139
|
+
});
|
|
140
|
+
path.skip(); // avoid multiple nested loop reports in same subtree
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Event listeners without cleanup - only flag in component-like contexts
|
|
144
|
+
CallExpression(path) {
|
|
145
|
+
const callee = path.node.callee;
|
|
146
|
+
if (!t.isMemberExpression(callee)) return;
|
|
147
|
+
if (callee.computed) return;
|
|
148
|
+
if (!t.isIdentifier(callee.property, { name: "addEventListener" })) return;
|
|
149
|
+
|
|
150
|
+
const loc = path.node.loc?.start;
|
|
151
|
+
if (!loc) return;
|
|
152
|
+
|
|
153
|
+
// Skip if not in a component-like context (React, Vue, etc.)
|
|
154
|
+
const fn = path.getFunctionParent();
|
|
155
|
+
if (!fn) return;
|
|
156
|
+
|
|
157
|
+
// Only flag in component-like functions or useEffect-like hooks
|
|
158
|
+
const fnName = fn.node.id?.name || (fn.parent?.id?.name);
|
|
159
|
+
const isComponent = fnName && /^[A-Z]/.test(fnName);
|
|
160
|
+
const isEffectHook = fnName && /useEffect|useLayoutEffect|componentDidMount|componentWillUnmount/i.test(fnName);
|
|
161
|
+
|
|
162
|
+
if (!isComponent && !isEffectHook) return;
|
|
163
|
+
|
|
164
|
+
const evName = getEventName(path.node);
|
|
165
|
+
const hasCleanup = hasMatchingRemoveEventListener(fn, evName);
|
|
166
|
+
|
|
167
|
+
if (hasCleanup) return;
|
|
168
|
+
|
|
169
|
+
findings.push({
|
|
170
|
+
type: "potential_memory_leak",
|
|
171
|
+
severity: "WARN",
|
|
172
|
+
category: "Performance",
|
|
173
|
+
file: filePath,
|
|
174
|
+
line: loc.line,
|
|
175
|
+
column: loc.column,
|
|
176
|
+
title: "Event listener without cleanup",
|
|
177
|
+
message: "addEventListener() found without a matching removeEventListener() in the same function scope.",
|
|
178
|
+
codeSnippet: snippetForLine(lines, loc.line),
|
|
179
|
+
confidence: "low",
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
// Expensive operations in render-like contexts
|
|
184
|
+
CallExpression(path) {
|
|
185
|
+
const callee = path.node.callee;
|
|
186
|
+
const loc = path.node.loc?.start;
|
|
187
|
+
if (!loc) return;
|
|
188
|
+
|
|
189
|
+
if (!isLikelyRenderContext(path)) return;
|
|
190
|
+
|
|
191
|
+
// JSON.parse / stringify in render
|
|
192
|
+
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: "JSON" }) && t.isIdentifier(callee.property)) {
|
|
193
|
+
const m = callee.property.name;
|
|
194
|
+
if (m === "parse" || m === "stringify") {
|
|
195
|
+
findings.push({
|
|
196
|
+
type: "expensive_render_op",
|
|
197
|
+
severity: "INFO",
|
|
198
|
+
category: "Performance",
|
|
199
|
+
file: filePath,
|
|
200
|
+
line: loc.line,
|
|
201
|
+
column: loc.column,
|
|
202
|
+
title: `JSON.${m} in render context`,
|
|
203
|
+
message: "Consider moving JSON parsing/serialization out of render to avoid repeated work.",
|
|
204
|
+
codeSnippet: snippetForLine(lines, loc.line),
|
|
205
|
+
confidence: "low",
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Array.sort in render (mutates + expensive)
|
|
211
|
+
if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: "sort" })) {
|
|
212
|
+
findings.push({
|
|
213
|
+
type: "expensive_render_op",
|
|
214
|
+
severity: "INFO",
|
|
215
|
+
category: "Performance",
|
|
216
|
+
file: filePath,
|
|
217
|
+
line: loc.line,
|
|
218
|
+
column: loc.column,
|
|
219
|
+
title: "Array.sort in render context",
|
|
220
|
+
message: "Sorting during render can be expensive and mutates arrays. Consider sorting in memoized/selectors.",
|
|
221
|
+
codeSnippet: snippetForLine(lines, loc.line),
|
|
222
|
+
confidence: "low",
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return findings;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = {
|
|
232
|
+
analyzePerformanceIssues,
|
|
233
|
+
parseCode,
|
|
234
|
+
};
|