@howlil/ez-agents 3.4.2 → 4.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/README.md +735 -462
- package/agents/ez-architect-agent.md +267 -0
- package/agents/ez-backend-agent.md +303 -0
- package/agents/ez-chief-strategist.md +271 -0
- package/agents/ez-codebase-mapper.md +770 -770
- package/agents/ez-context-manager.md +319 -0
- package/agents/ez-debugger.md +1255 -1255
- package/agents/ez-design-expert.md +347 -0
- package/agents/ez-devops-agent.md +331 -0
- package/agents/ez-executor.md +487 -487
- package/agents/ez-frontend-agent.md +322 -0
- package/agents/ez-phase-researcher.md +553 -553
- package/agents/ez-planner.md +1307 -1307
- package/agents/ez-product-engineer.md +435 -0
- package/agents/ez-project-researcher.md +629 -629
- package/agents/ez-qa-agent.md +320 -0
- package/agents/ez-release-agent.md +333 -0
- package/agents/ez-requirements-agent.md +377 -0
- package/agents/ez-roadmapper.md +650 -650
- package/agents/ez-technical-writer.md +551 -0
- package/agents/ez-ux-expert.md +393 -0
- package/agents/ez-verifier.md +579 -579
- package/bin/guards/autonomy-guard.cjs +346 -0
- package/bin/guards/context-budget-guard.cjs +278 -0
- package/bin/guards/hallucination-guard.cjs +380 -0
- package/bin/guards/hidden-state-guard.cjs +182 -0
- package/bin/guards/team-overhead-guard.cjs +266 -0
- package/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/bin/install.js +3221 -3272
- package/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/bin/lib/archetype-detector.cjs +289 -0
- package/bin/lib/assistant-adapter.cjs +361 -0
- package/bin/lib/audit-exec.cjs +175 -0
- package/bin/lib/auth.cjs +176 -0
- package/bin/lib/backup-service.cjs +422 -0
- package/bin/lib/bdd-validator.cjs +622 -0
- package/bin/lib/business-flow-mapper.cjs +429 -0
- package/bin/lib/circuit-breaker.cjs +276 -0
- package/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/bin/lib/codebase-analyzer.cjs +241 -0
- package/bin/lib/commands.cjs +691 -0
- package/bin/lib/config.cjs +236 -0
- package/bin/lib/constraint-extractor.cjs +526 -0
- package/bin/lib/content-scanner.cjs +238 -0
- package/bin/lib/context-cache.cjs +154 -0
- package/bin/lib/context-compressor.cjs +102 -0
- package/bin/lib/context-deduplicator.cjs +105 -0
- package/bin/lib/context-errors.cjs +78 -0
- package/bin/lib/context-manager.cjs +338 -0
- package/bin/lib/context-metadata-tracker.cjs +140 -0
- package/bin/lib/context-relevance-scorer.cjs +99 -0
- package/bin/lib/core.cjs +507 -0
- package/bin/lib/cost-alerts.cjs +174 -0
- package/bin/lib/cost-tracker.cjs +275 -0
- package/bin/lib/crash-recovery.cjs +220 -0
- package/bin/lib/dependency-graph.cjs +319 -0
- package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/bin/lib/deploy/deploy-status.cjs +74 -0
- package/bin/lib/discussion-synthesizer.cjs +439 -0
- package/bin/lib/error-cache.cjs +114 -0
- package/bin/lib/error-registry.cjs +177 -0
- package/bin/lib/file-access.cjs +207 -0
- package/bin/lib/file-lock.cjs +236 -0
- package/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/bin/lib/finops/cost-reporter.cjs +132 -0
- package/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/bin/lib/finops/spot-manager.cjs +118 -0
- package/bin/lib/framework-detector.cjs +396 -0
- package/bin/lib/frontmatter.cjs +313 -0
- package/bin/lib/fs-utils.cjs +153 -0
- package/bin/lib/gate-executor.cjs +272 -0
- package/bin/lib/gates/README.md +374 -0
- package/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/bin/lib/gates/gate-03-code.cjs +635 -0
- package/bin/lib/gates/gate-04-security.cjs +829 -0
- package/bin/lib/git-errors.cjs +83 -0
- package/bin/lib/git-utils.cjs +321 -0
- package/bin/lib/git-workflow-engine.cjs +1157 -0
- package/bin/lib/health-check.cjs +227 -0
- package/bin/lib/index.cjs +279 -0
- package/bin/lib/init.cjs +725 -0
- package/bin/lib/lock-logger.cjs +194 -0
- package/bin/lib/lock-state.cjs +263 -0
- package/bin/lib/lockfile-validator.cjs +227 -0
- package/bin/lib/log-rotation.cjs +71 -0
- package/bin/lib/logger.cjs +125 -0
- package/bin/lib/memory-compression.cjs +256 -0
- package/bin/lib/milestone.cjs +247 -0
- package/bin/lib/model-provider.cjs +241 -0
- package/bin/lib/package-manager-detector.cjs +203 -0
- package/bin/lib/package-manager-executor.cjs +385 -0
- package/bin/lib/package-manager-service.cjs +216 -0
- package/bin/lib/perf/api-monitor.cjs +88 -0
- package/bin/lib/perf/db-optimizer.cjs +78 -0
- package/bin/lib/perf/frontend-performance.cjs +56 -0
- package/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/bin/lib/perf/perf-baseline.cjs +102 -0
- package/bin/lib/perf/perf-reporter.cjs +117 -0
- package/bin/lib/perf/regression-detector.cjs +92 -0
- package/bin/lib/phase.cjs +963 -0
- package/bin/lib/planning-write.cjs +123 -0
- package/bin/lib/project-reporter.cjs +565 -0
- package/bin/lib/quality-gate.cjs +332 -0
- package/bin/lib/quality-metrics.cjs +324 -0
- package/bin/lib/recovery-manager.cjs +98 -0
- package/bin/lib/release-validator.cjs +617 -0
- package/bin/lib/retry.cjs +119 -0
- package/bin/lib/roadmap.cjs +309 -0
- package/bin/lib/safe-exec.cjs +173 -0
- package/bin/lib/safe-path.cjs +130 -0
- package/bin/lib/security-errors.cjs +62 -0
- package/bin/lib/session-chain.cjs +304 -0
- package/bin/lib/session-errors.cjs +81 -0
- package/bin/lib/session-export.cjs +251 -0
- package/bin/lib/session-import.cjs +262 -0
- package/bin/lib/session-manager.cjs +280 -0
- package/bin/lib/skill-context.cjs +148 -0
- package/bin/lib/skill-matcher.cjs +236 -0
- package/bin/lib/skill-registry.cjs +360 -0
- package/bin/lib/skill-resolver.cjs +449 -0
- package/bin/lib/skill-triggers.cjs +90 -0
- package/bin/lib/skill-validator.cjs +270 -0
- package/bin/lib/skill-versioning.cjs +355 -0
- package/bin/lib/stack-detector.cjs +399 -0
- package/bin/lib/state.cjs +736 -0
- package/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/bin/lib/temp-file.cjs +239 -0
- package/bin/lib/template.cjs +223 -0
- package/bin/lib/test-file-lock.cjs +112 -0
- package/bin/lib/test-graceful.cjs +93 -0
- package/bin/lib/test-logger.cjs +60 -0
- package/bin/lib/test-safe-exec.cjs +38 -0
- package/bin/lib/test-safe-path.cjs +33 -0
- package/bin/lib/test-temp-file.cjs +125 -0
- package/bin/lib/tier-manager.cjs +428 -0
- package/bin/lib/timeout-exec.cjs +63 -0
- package/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/bin/lib/url-fetch.cjs +170 -0
- package/bin/lib/verify.cjs +863 -0
- package/bin/update.js +217 -214
- package/commands/deploy.cjs +53 -0
- package/commands/ez/add-tests.md +41 -41
- package/commands/ez/audit-milestone.md +36 -36
- package/commands/ez/complete-milestone.md +136 -136
- package/commands/ez/discuss-phase.md +90 -90
- package/commands/ez/execute-phase.md +52 -41
- package/commands/ez/help.md +22 -22
- package/commands/ez/map-codebase.md +71 -71
- package/commands/ez/new-milestone.md +44 -44
- package/commands/ez/new-project.md +51 -42
- package/commands/ez/plan-phase.md +53 -45
- package/commands/ez/progress.md +36 -24
- package/commands/ez/quick.md +45 -45
- package/commands/ez/resume-work.md +40 -40
- package/commands/ez/run-phase.md +580 -0
- package/commands/ez/settings.md +36 -36
- package/commands/ez/update.md +37 -37
- package/commands/ez/verify-work.md +402 -38
- package/commands/health-check.cjs +44 -0
- package/commands/rollback.cjs +47 -0
- package/ez-agents/bin/ez-tools.cjs +1692 -716
- package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
- package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
- package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
- package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
- package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
- package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
- package/ez-agents/bin/lib/audit-exec.cjs +166 -167
- package/ez-agents/bin/lib/auth.cjs +176 -176
- package/ez-agents/bin/lib/backup-service.cjs +422 -0
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -0
- package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
- package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
- package/ez-agents/bin/lib/commands.cjs +685 -685
- package/ez-agents/bin/lib/config.cjs +41 -1
- package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
- package/ez-agents/bin/lib/content-scanner.cjs +238 -0
- package/ez-agents/bin/lib/context-cache.cjs +154 -0
- package/ez-agents/bin/lib/context-errors.cjs +71 -0
- package/ez-agents/bin/lib/context-manager.cjs +220 -0
- package/ez-agents/bin/lib/core.cjs +507 -512
- package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
- package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
- package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
- package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
- package/ez-agents/bin/lib/discussion-synthesizer.cjs +458 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -0
- package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
- package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
- package/ez-agents/bin/lib/framework-detector.cjs +396 -0
- package/ez-agents/bin/lib/frontmatter.cjs +3 -1
- package/ez-agents/bin/lib/gates/README.md +374 -0
- package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
- package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
- package/ez-agents/bin/lib/git-errors.cjs +83 -0
- package/ez-agents/bin/lib/git-utils.cjs +118 -0
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
- package/ez-agents/bin/lib/health-check.cjs +162 -162
- package/ez-agents/bin/lib/index.cjs +40 -2
- package/ez-agents/bin/lib/init.cjs +0 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
- package/ez-agents/bin/lib/log-rotation.cjs +71 -0
- package/ez-agents/bin/lib/logger.cjs +99 -154
- package/ez-agents/bin/lib/memory-compression.cjs +256 -0
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
- package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
- package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
- package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
- package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
- package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
- package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
- package/ez-agents/bin/lib/project-reporter.cjs +502 -0
- package/ez-agents/bin/lib/quality-gate.cjs +332 -0
- package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
- package/ez-agents/bin/lib/release-validator.cjs +617 -0
- package/ez-agents/bin/lib/safe-exec.cjs +128 -214
- package/ez-agents/bin/lib/security-errors.cjs +62 -0
- package/ez-agents/bin/lib/session-chain.cjs +304 -0
- package/ez-agents/bin/lib/session-errors.cjs +81 -0
- package/ez-agents/bin/lib/session-export.cjs +251 -0
- package/ez-agents/bin/lib/session-import.cjs +262 -0
- package/ez-agents/bin/lib/session-manager.cjs +280 -0
- package/ez-agents/bin/lib/skill-context.cjs +148 -0
- package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
- package/ez-agents/bin/lib/skill-registry.cjs +341 -0
- package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
- package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
- package/ez-agents/bin/lib/skill-validator.cjs +270 -0
- package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
- package/ez-agents/bin/lib/stack-detector.cjs +399 -0
- package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/ez-agents/bin/lib/tier-manager.cjs +428 -0
- package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -0
- package/ez-agents/bin/lib/verify.cjs +863 -863
- package/ez-agents/references/decimal-phase-calculation.md +65 -65
- package/ez-agents/references/git-integration.md +248 -248
- package/ez-agents/references/git-planning-commit.md +38 -38
- package/ez-agents/references/metrics-schema.md +118 -0
- package/ez-agents/references/model-profile-resolution.md +34 -34
- package/ez-agents/references/model-profiles.md +93 -93
- package/ez-agents/references/phase-argument-parsing.md +61 -61
- package/ez-agents/references/planning-config.md +340 -200
- package/ez-agents/references/tier-strategy.md +103 -0
- package/ez-agents/references/ui-brand.md +160 -160
- package/ez-agents/references/verification-patterns.md +612 -612
- package/ez-agents/templates/DEBUG.md +164 -164
- package/ez-agents/templates/UAT.md +247 -247
- package/ez-agents/templates/agent-output-format.md +404 -0
- package/ez-agents/templates/bdd-feature.md +173 -0
- package/ez-agents/templates/codebase/architecture.md +255 -255
- package/ez-agents/templates/codebase/structure.md +285 -285
- package/ez-agents/templates/copilot-instructions.md +7 -7
- package/ez-agents/templates/debug-subagent-prompt.md +91 -91
- package/ez-agents/templates/discovery.md +146 -146
- package/ez-agents/templates/discussion.md +68 -0
- package/ez-agents/templates/handoff-protocol.md +294 -0
- package/ez-agents/templates/incident-runbook.md +205 -0
- package/ez-agents/templates/mode-workflow-templates.md +301 -0
- package/ez-agents/templates/phase-prompt.md +610 -610
- package/ez-agents/templates/planner-subagent-prompt.md +117 -117
- package/ez-agents/templates/project.md +184 -184
- package/ez-agents/templates/release-checklist.md +136 -0
- package/ez-agents/templates/research.md +552 -552
- package/ez-agents/templates/rollback-plan.md +201 -0
- package/ez-agents/templates/security-user-setup.md +244 -0
- package/ez-agents/templates/skill-validation-rules.md +476 -0
- package/ez-agents/templates/state.md +180 -176
- package/ez-agents/templates/summary-complex.md +59 -59
- package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
- package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
- package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
- package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
- package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
- package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
- package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
- package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
- package/ez-agents/workflows/audit-milestone.md +1 -1
- package/ez-agents/workflows/autonomous.md +131 -30
- package/ez-agents/workflows/complete-milestone.md +1 -1
- package/ez-agents/workflows/discuss-phase.md +1 -1
- package/ez-agents/workflows/execute-phase.md +169 -3
- package/ez-agents/workflows/help.md +86 -133
- package/ez-agents/workflows/hotfix.md +291 -0
- package/ez-agents/workflows/new-milestone.md +340 -11
- package/ez-agents/workflows/new-project.md +294 -318
- package/ez-agents/workflows/plan-phase.md +22 -40
- package/ez-agents/workflows/progress.md +15 -25
- package/ez-agents/workflows/release.md +253 -0
- package/ez-agents/workflows/resume-session.md +215 -0
- package/ez-agents/workflows/run-phase.md +531 -0
- package/ez-agents/workflows/settings.md +2 -35
- package/hooks/dist/ez-check-update.js +81 -81
- package/hooks/dist/ez-context-monitor.js +148 -141
- package/hooks/dist/ez-statusline.js +115 -115
- package/package.json +78 -64
- package/scripts/fix-qwen-installation.js +144 -144
- package/agents/ez-integration-checker.md +0 -443
- package/agents/ez-nyquist-auditor.md +0 -176
- package/agents/ez-plan-checker.md +0 -706
- package/agents/ez-research-synthesizer.md +0 -247
- package/agents/ez-ui-auditor.md +0 -439
- package/agents/ez-ui-checker.md +0 -300
- package/agents/ez-ui-researcher.md +0 -353
- package/commands/ez/add-phase.md +0 -43
- package/commands/ez/add-todo.md +0 -47
- package/commands/ez/auth.md +0 -87
- package/commands/ez/autonomous.md +0 -41
- package/commands/ez/check-todos.md +0 -45
- package/commands/ez/cleanup.md +0 -18
- package/commands/ez/debug.md +0 -168
- package/commands/ez/health.md +0 -22
- package/commands/ez/insert-phase.md +0 -32
- package/commands/ez/join-discord.md +0 -18
- package/commands/ez/list-phase-assumptions.md +0 -46
- package/commands/ez/pause-work.md +0 -38
- package/commands/ez/plan-milestone-gaps.md +0 -34
- package/commands/ez/reapply-patches.md +0 -124
- package/commands/ez/remove-phase.md +0 -31
- package/commands/ez/research-phase.md +0 -190
- package/commands/ez/set-profile.md +0 -34
- package/commands/ez/stats.md +0 -18
- package/commands/ez/ui-phase.md +0 -34
- package/commands/ez/ui-review.md +0 -32
- package/commands/ez/validate-phase.md +0 -35
- package/ez-agents/templates/UI-SPEC.md +0 -100
- package/ez-agents/templates/VALIDATION.md +0 -76
- package/ez-agents/templates/context.md +0 -352
- package/ez-agents/templates/verification-report.md +0 -322
- package/ez-agents/workflows/research-phase.md +0 -74
- package/ez-agents/workflows/ui-phase.md +0 -290
- package/ez-agents/workflows/ui-review.md +0 -157
- package/ez-agents/workflows/validate-phase.md +0 -167
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate 3: Code Quality
|
|
3
|
+
*
|
|
4
|
+
* Validates code quality patterns and detects overengineering.
|
|
5
|
+
*
|
|
6
|
+
* Checks:
|
|
7
|
+
* 1. Clean code rules (function length < 50 lines, nesting < 4 levels, naming conventions)
|
|
8
|
+
* 2. Code smell detector (magic numbers, long parameter lists, duplicate code)
|
|
9
|
+
* 3. Anti-overengineering (generic helpers, premature abstraction, unused interfaces)
|
|
10
|
+
*
|
|
11
|
+
* @module gates/gate-03-code
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { z } = require('zod');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Zod schema for a code file
|
|
18
|
+
* @type {z.ZodSchema}
|
|
19
|
+
*/
|
|
20
|
+
const codeFileSchema = z.object({
|
|
21
|
+
/** File path */
|
|
22
|
+
path: z.string(),
|
|
23
|
+
/** File content */
|
|
24
|
+
content: z.string(),
|
|
25
|
+
/** File language (e.g., 'javascript', 'typescript') */
|
|
26
|
+
language: z.string().optional(),
|
|
27
|
+
/** Function definitions in the file */
|
|
28
|
+
functions: z.array(z.object({
|
|
29
|
+
/** Function name */
|
|
30
|
+
name: z.string(),
|
|
31
|
+
/** Function start line */
|
|
32
|
+
startLine: z.number().int().min(0),
|
|
33
|
+
/** Function end line */
|
|
34
|
+
endLine: z.number().int().min(0),
|
|
35
|
+
/** Function body content */
|
|
36
|
+
body: z.string().optional(),
|
|
37
|
+
/** Function parameters */
|
|
38
|
+
parameters: z.array(z.string()).optional(),
|
|
39
|
+
})).optional(),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Zod schema for code metrics
|
|
44
|
+
* @type {z.ZodSchema}
|
|
45
|
+
*/
|
|
46
|
+
const codeMetricsSchema = z.object({
|
|
47
|
+
/** Total lines of code */
|
|
48
|
+
totalLines: z.number().int().min(0).optional(),
|
|
49
|
+
/** Code lines (excluding comments and blanks) */
|
|
50
|
+
codeLines: z.number().int().min(0).optional(),
|
|
51
|
+
/** Comment lines */
|
|
52
|
+
commentLines: z.number().int().min(0).optional(),
|
|
53
|
+
/** Average function length */
|
|
54
|
+
avgFunctionLength: z.number().nonnegative().optional(),
|
|
55
|
+
/** Maximum nesting depth */
|
|
56
|
+
maxNesting: z.number().int().min(0).optional(),
|
|
57
|
+
/** Number of magic numbers */
|
|
58
|
+
magicNumberCount: z.number().int().min(0).optional(),
|
|
59
|
+
/** Number of long parameter lists */
|
|
60
|
+
longParamListCount: z.number().int().min(0).optional(),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Zod schema for the gate context
|
|
65
|
+
* @type {z.ZodSchema}
|
|
66
|
+
*/
|
|
67
|
+
const gateContextSchema = z.object({
|
|
68
|
+
/** Array of code files to analyze */
|
|
69
|
+
files: z.array(codeFileSchema).optional(),
|
|
70
|
+
/** Pre-computed code metrics */
|
|
71
|
+
metrics: codeMetricsSchema.optional(),
|
|
72
|
+
/** Generic helper functions to check for sprawl */
|
|
73
|
+
genericHelpers: z.array(z.object({
|
|
74
|
+
/** Helper name */
|
|
75
|
+
name: z.string(),
|
|
76
|
+
/** Helper usage count */
|
|
77
|
+
usageCount: z.number().int().min(0).optional(),
|
|
78
|
+
/** Helper file path */
|
|
79
|
+
path: z.string().optional(),
|
|
80
|
+
})).optional(),
|
|
81
|
+
/** Named constants in the codebase */
|
|
82
|
+
namedConstants: z.array(z.object({
|
|
83
|
+
/** Constant name */
|
|
84
|
+
name: z.string(),
|
|
85
|
+
/** Constant value */
|
|
86
|
+
value: z.union([z.string(), z.number(), z.boolean()]),
|
|
87
|
+
})).optional(),
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Thresholds for code quality checks
|
|
92
|
+
*/
|
|
93
|
+
const THRESHOLDS = {
|
|
94
|
+
/** Maximum function length in lines */
|
|
95
|
+
maxFunctionLength: 50,
|
|
96
|
+
/** Maximum nesting depth */
|
|
97
|
+
maxNesting: 4,
|
|
98
|
+
/** Maximum parameters in function signature */
|
|
99
|
+
maxParameters: 5,
|
|
100
|
+
/** Minimum constant name length to be considered meaningful */
|
|
101
|
+
minConstantNameLength: 3,
|
|
102
|
+
/** Magic number threshold - numbers below this are ignored */
|
|
103
|
+
magicNumberIgnoreThreshold: 2,
|
|
104
|
+
/** Generic helper sprawl threshold */
|
|
105
|
+
genericHelperSprawlThreshold: 3,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Count lines in a string
|
|
110
|
+
* @param {string} content - Content to count lines in
|
|
111
|
+
* @returns {number}
|
|
112
|
+
*/
|
|
113
|
+
function countLines(content) {
|
|
114
|
+
if (!content || typeof content !== 'string') {
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
return content.split('\n').length;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Calculate function length in lines
|
|
122
|
+
* @param {string} functionBody - Function body content
|
|
123
|
+
* @returns {number}
|
|
124
|
+
*/
|
|
125
|
+
function calculateFunctionLength(functionBody) {
|
|
126
|
+
return countLines(functionBody);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Check if function exceeds maximum length
|
|
131
|
+
* @param {string} functionBody - Function body content
|
|
132
|
+
* @returns {{ exceeds: boolean, length: number }}
|
|
133
|
+
*/
|
|
134
|
+
function checkFunctionLength(functionBody) {
|
|
135
|
+
const length = calculateFunctionLength(functionBody);
|
|
136
|
+
return {
|
|
137
|
+
exceeds: length > THRESHOLDS.maxFunctionLength,
|
|
138
|
+
length,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Calculate nesting depth of code
|
|
144
|
+
*
|
|
145
|
+
* Counts nested blocks by tracking opening and closing braces.
|
|
146
|
+
* Handles common patterns: if/else, for, while, function, switch, try/catch
|
|
147
|
+
*
|
|
148
|
+
* @param {string} code - Code content to analyze
|
|
149
|
+
* @returns {number} Maximum nesting depth
|
|
150
|
+
*/
|
|
151
|
+
function calculateNestingDepth(code) {
|
|
152
|
+
if (!code || typeof code !== 'string') {
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let maxDepth = 0;
|
|
157
|
+
let currentDepth = 0;
|
|
158
|
+
|
|
159
|
+
// Track braces for nesting
|
|
160
|
+
for (let i = 0; i < code.length; i++) {
|
|
161
|
+
const char = code[i];
|
|
162
|
+
|
|
163
|
+
if (char === '{') {
|
|
164
|
+
currentDepth++;
|
|
165
|
+
if (currentDepth > maxDepth) {
|
|
166
|
+
maxDepth = currentDepth;
|
|
167
|
+
}
|
|
168
|
+
} else if (char === '}') {
|
|
169
|
+
currentDepth--;
|
|
170
|
+
if (currentDepth < 0) {
|
|
171
|
+
currentDepth = 0; // Handle unbalanced braces gracefully
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Subtract 1 because the outermost scope doesn't count as nesting
|
|
177
|
+
return Math.max(0, maxDepth - 1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if nesting depth exceeds threshold
|
|
182
|
+
* @param {string} code - Code content to analyze
|
|
183
|
+
* @returns {{ exceeds: boolean, depth: number }}
|
|
184
|
+
*/
|
|
185
|
+
function checkNestingDepth(code) {
|
|
186
|
+
const depth = calculateNestingDepth(code);
|
|
187
|
+
return {
|
|
188
|
+
exceeds: depth > THRESHOLDS.maxNesting,
|
|
189
|
+
depth,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Detect magic numbers in code
|
|
195
|
+
*
|
|
196
|
+
* Magic numbers are numeric literals that appear directly in code
|
|
197
|
+
* without being defined as named constants.
|
|
198
|
+
*
|
|
199
|
+
* Ignores:
|
|
200
|
+
* - 0 and 1 (commonly used as indices/flags)
|
|
201
|
+
* - Numbers in comments
|
|
202
|
+
* - Numbers in string literals
|
|
203
|
+
*
|
|
204
|
+
* @param {string} code - Code content to analyze
|
|
205
|
+
* @param {Array} namedConstants - Array of named constant values to exclude
|
|
206
|
+
* @returns {Array<{ line: number, value: number, suggestion: string }>}
|
|
207
|
+
*/
|
|
208
|
+
function detectMagicNumbers(code, namedConstants = []) {
|
|
209
|
+
const magicNumbers = [];
|
|
210
|
+
|
|
211
|
+
if (!code || typeof code !== 'string') {
|
|
212
|
+
return magicNumbers;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Extract constant values for comparison
|
|
216
|
+
const constantValues = new Set();
|
|
217
|
+
if (namedConstants && Array.isArray(namedConstants)) {
|
|
218
|
+
for (const constant of namedConstants) {
|
|
219
|
+
if (typeof constant.value === 'number') {
|
|
220
|
+
constantValues.add(constant.value);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const lines = code.split('\n');
|
|
226
|
+
|
|
227
|
+
for (let i = 0; i < lines.length; i++) {
|
|
228
|
+
const line = lines[i];
|
|
229
|
+
const lineNum = i + 1;
|
|
230
|
+
|
|
231
|
+
// Skip comments
|
|
232
|
+
if (line.trim().startsWith('//') || line.trim().startsWith('/*') || line.trim().startsWith('*')) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Remove string literals to avoid matching numbers in strings
|
|
237
|
+
const codeWithoutStrings = line.replace(/["'`].*?["'`]/g, '');
|
|
238
|
+
|
|
239
|
+
// Match numeric literals (integers and floats)
|
|
240
|
+
const numberPattern = /(?<!\w)(-?\d+\.?\d*)(?!\w)/g;
|
|
241
|
+
let match;
|
|
242
|
+
|
|
243
|
+
while ((match = numberPattern.exec(codeWithoutStrings)) !== null) {
|
|
244
|
+
const numStr = match[1];
|
|
245
|
+
const num = parseFloat(numStr);
|
|
246
|
+
|
|
247
|
+
// Skip 0, 1, 2 (commonly used as indices/flags)
|
|
248
|
+
if (Math.abs(num) <= THRESHOLDS.magicNumberIgnoreThreshold) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Skip if it's a named constant
|
|
253
|
+
if (constantValues.has(num)) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Generate suggested constant name
|
|
258
|
+
const suggestedName = suggestConstantName(num);
|
|
259
|
+
|
|
260
|
+
magicNumbers.push({
|
|
261
|
+
line: lineNum,
|
|
262
|
+
value: num,
|
|
263
|
+
suggestion: suggestedName,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return magicNumbers;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Suggest a constant name for a magic number
|
|
273
|
+
* @param {number} value - The magic number value
|
|
274
|
+
* @returns {string} Suggested constant name
|
|
275
|
+
*/
|
|
276
|
+
function suggestConstantName(value) {
|
|
277
|
+
// Common values with semantic meaning
|
|
278
|
+
const commonConstants = {
|
|
279
|
+
7: 'DAYS_IN_WEEK',
|
|
280
|
+
24: 'HOURS_IN_DAY',
|
|
281
|
+
60: 'MINUTES_IN_HOUR',
|
|
282
|
+
100: 'PERCENTAGE_SCALE',
|
|
283
|
+
1000: 'MILLISECONDS_IN_SECOND',
|
|
284
|
+
365: 'DAYS_IN_YEAR',
|
|
285
|
+
404: 'HTTP_NOT_FOUND',
|
|
286
|
+
500: 'HTTP_SERVER_ERROR',
|
|
287
|
+
200: 'HTTP_OK',
|
|
288
|
+
80: 'HTTP_PORT',
|
|
289
|
+
443: 'HTTPS_PORT',
|
|
290
|
+
3000: 'DEFAULT_PORT',
|
|
291
|
+
10: 'DEFAULT_LIMIT',
|
|
292
|
+
50: 'DEFAULT_PAGE_SIZE',
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
if (commonConstants[value]) {
|
|
296
|
+
return commonConstants[value];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Generic suggestion
|
|
300
|
+
return `VALUE_${value.toString().replace('.', '_').replace('-', 'NEG_')}`;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Check for long parameter lists
|
|
305
|
+
*
|
|
306
|
+
* Functions with more than THRESHOLDS.maxParameters parameters
|
|
307
|
+
* are considered to have a code smell.
|
|
308
|
+
*
|
|
309
|
+
* @param {Array} parameters - Array of parameter names
|
|
310
|
+
* @returns {{ exceeds: boolean, count: number }}
|
|
311
|
+
*/
|
|
312
|
+
function checkParameterList(parameters) {
|
|
313
|
+
const count = parameters ? parameters.length : 0;
|
|
314
|
+
return {
|
|
315
|
+
exceeds: count > THRESHOLDS.maxParameters,
|
|
316
|
+
count,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Detect generic helper sprawl
|
|
322
|
+
*
|
|
323
|
+
* Generic helpers are functions with vague names like 'utils', 'helpers', 'common'
|
|
324
|
+
* that often indicate poor organization and overengineering.
|
|
325
|
+
*
|
|
326
|
+
* @param {Array} genericHelpers - Array of generic helper definitions
|
|
327
|
+
* @returns {Array<{ name: string, usageCount: number, issue: string }>}
|
|
328
|
+
*/
|
|
329
|
+
function detectGenericHelperSprawl(genericHelpers) {
|
|
330
|
+
const issues = [];
|
|
331
|
+
|
|
332
|
+
if (!genericHelpers || !Array.isArray(genericHelpers)) {
|
|
333
|
+
return issues;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Patterns that indicate generic/unclear helper names
|
|
337
|
+
const genericPatterns = [
|
|
338
|
+
/^utils?$/i,
|
|
339
|
+
/^helpers?$/i,
|
|
340
|
+
/^common$/i,
|
|
341
|
+
/^shared$/i,
|
|
342
|
+
/^misc$/i,
|
|
343
|
+
/^miscellaneous$/i,
|
|
344
|
+
/^general$/i,
|
|
345
|
+
/^utility$/i,
|
|
346
|
+
/^utilities$/i,
|
|
347
|
+
/^functions?$/i,
|
|
348
|
+
/^tools?$/i,
|
|
349
|
+
/^helpers?$/i,
|
|
350
|
+
];
|
|
351
|
+
|
|
352
|
+
for (const helper of genericHelpers) {
|
|
353
|
+
const name = helper.name || '';
|
|
354
|
+
|
|
355
|
+
// Check if name matches generic patterns
|
|
356
|
+
const isGeneric = genericPatterns.some(pattern => pattern.test(name));
|
|
357
|
+
|
|
358
|
+
if (isGeneric) {
|
|
359
|
+
const usageCount = helper.usageCount ?? 0;
|
|
360
|
+
|
|
361
|
+
// Flag if used in many places (sprawl) or has vague name
|
|
362
|
+
if (usageCount >= THRESHOLDS.genericHelperSprawlThreshold) {
|
|
363
|
+
issues.push({
|
|
364
|
+
name,
|
|
365
|
+
usageCount,
|
|
366
|
+
issue: `Generic helper '${name}' used in ${usageCount} locations. Consider splitting into specific modules.`,
|
|
367
|
+
});
|
|
368
|
+
} else if (usageCount === 0) {
|
|
369
|
+
issues.push({
|
|
370
|
+
name,
|
|
371
|
+
usageCount,
|
|
372
|
+
issue: `Unused generic helper '${name}'. Remove or integrate into specific modules.`,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return issues;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Detect premature abstraction patterns
|
|
383
|
+
*
|
|
384
|
+
* Premature abstractions include:
|
|
385
|
+
* - Interfaces/classes with no implementations
|
|
386
|
+
* - Abstract base classes with single child
|
|
387
|
+
* - Factory patterns for single-instance objects
|
|
388
|
+
* - Strategy pattern with single strategy
|
|
389
|
+
*
|
|
390
|
+
* @param {string} code - Code content to analyze
|
|
391
|
+
* @returns {Array<{ type: string, name: string, line: number, issue: string }>}
|
|
392
|
+
*/
|
|
393
|
+
function detectPrematureAbstraction(code) {
|
|
394
|
+
const issues = [];
|
|
395
|
+
|
|
396
|
+
if (!code || typeof code !== 'string') {
|
|
397
|
+
return issues;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const lines = code.split('\n');
|
|
401
|
+
|
|
402
|
+
// Track interface/abstract class definitions
|
|
403
|
+
const interfaces = new Map(); // name -> line
|
|
404
|
+
const abstractClasses = new Map(); // name -> line
|
|
405
|
+
const implementations = new Set();
|
|
406
|
+
|
|
407
|
+
for (let i = 0; i < lines.length; i++) {
|
|
408
|
+
const line = lines[i];
|
|
409
|
+
const lineNum = i + 1;
|
|
410
|
+
|
|
411
|
+
// Detect interface declarations
|
|
412
|
+
const interfaceMatch = line.match(/interface\s+(\w+)/);
|
|
413
|
+
if (interfaceMatch) {
|
|
414
|
+
interfaces.set(interfaceMatch[1], lineNum);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Detect abstract class declarations
|
|
418
|
+
const abstractClassMatch = line.match(/abstract\s+class\s+(\w+)/);
|
|
419
|
+
if (abstractClassMatch) {
|
|
420
|
+
abstractClasses.set(abstractClassMatch[1], lineNum);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Detect implementations
|
|
424
|
+
const implementsMatch = line.match(/implements\s+(\w+)/);
|
|
425
|
+
if (implementsMatch) {
|
|
426
|
+
implementations.add(implementsMatch[1]);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const extendsMatch = line.match(/extends\s+(\w+)/);
|
|
430
|
+
if (extendsMatch) {
|
|
431
|
+
// Check if extending an abstract class
|
|
432
|
+
if (abstractClasses.has(extendsMatch[1])) {
|
|
433
|
+
// Mark as having implementation
|
|
434
|
+
abstractClasses.set(extendsMatch[1], null); // null means has implementation
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Check for interfaces without implementations
|
|
440
|
+
for (const [name, line] of interfaces) {
|
|
441
|
+
if (!implementations.has(name)) {
|
|
442
|
+
issues.push({
|
|
443
|
+
type: 'interface',
|
|
444
|
+
name,
|
|
445
|
+
line,
|
|
446
|
+
issue: `Interface '${name}' has no implementations. Consider removing or adding implementation.`,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Check for abstract classes without concrete implementations
|
|
452
|
+
for (const [name, line] of abstractClasses) {
|
|
453
|
+
if (line !== null) {
|
|
454
|
+
issues.push({
|
|
455
|
+
type: 'abstract-class',
|
|
456
|
+
name,
|
|
457
|
+
line,
|
|
458
|
+
issue: `Abstract class '${name}' has no concrete implementations. Consider removing or adding implementation.`,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return issues;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Analyze code file for quality issues
|
|
468
|
+
* @param {Object} file - Code file object
|
|
469
|
+
* @param {Array} namedConstants - Named constants for magic number detection
|
|
470
|
+
* @returns {{ errors: Array, warnings: Array }}
|
|
471
|
+
*/
|
|
472
|
+
function analyzeCodeFile(file, namedConstants = []) {
|
|
473
|
+
const errors = [];
|
|
474
|
+
const warnings = [];
|
|
475
|
+
|
|
476
|
+
if (!file || !file.content) {
|
|
477
|
+
return { errors, warnings };
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const filePath = file.path || 'unknown';
|
|
481
|
+
|
|
482
|
+
// Check functions if provided
|
|
483
|
+
if (file.functions && Array.isArray(file.functions)) {
|
|
484
|
+
for (const func of file.functions) {
|
|
485
|
+
const funcPath = `${filePath}:${func.name}`;
|
|
486
|
+
|
|
487
|
+
// Check function length
|
|
488
|
+
if (func.body) {
|
|
489
|
+
const lengthCheck = checkFunctionLength(func.body);
|
|
490
|
+
if (lengthCheck.exceeds) {
|
|
491
|
+
errors.push({
|
|
492
|
+
path: funcPath,
|
|
493
|
+
message: `Function '${func.name}' is ${lengthCheck.length} lines (max: ${THRESHOLDS.maxFunctionLength}). Consider breaking into smaller functions.`,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Check parameter list
|
|
499
|
+
if (func.parameters) {
|
|
500
|
+
const paramCheck = checkParameterList(func.parameters);
|
|
501
|
+
if (paramCheck.exceeds) {
|
|
502
|
+
warnings.push({
|
|
503
|
+
path: funcPath,
|
|
504
|
+
message: `Function '${func.name}' has ${paramCheck.count} parameters (max recommended: ${THRESHOLDS.maxParameters}). Consider using an options object.`,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Check nesting depth
|
|
512
|
+
const nestingCheck = checkNestingDepth(file.content);
|
|
513
|
+
if (nestingCheck.exceeds) {
|
|
514
|
+
errors.push({
|
|
515
|
+
path: filePath,
|
|
516
|
+
message: `Nesting depth of ${nestingCheck.depth} exceeds maximum (${THRESHOLDS.maxNesting}). Consider refactoring to reduce complexity.`,
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Check for magic numbers
|
|
521
|
+
const magicNumbers = detectMagicNumbers(file.content, namedConstants);
|
|
522
|
+
for (const magic of magicNumbers) {
|
|
523
|
+
warnings.push({
|
|
524
|
+
path: `${filePath}:${magic.line}`,
|
|
525
|
+
message: `Magic number ${magic.value} found. Consider defining as named constant (e.g., ${magic.suggestion}).`,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Check for premature abstraction
|
|
530
|
+
const abstractions = detectPrematureAbstraction(file.content);
|
|
531
|
+
for (const abs of abstractions) {
|
|
532
|
+
warnings.push({
|
|
533
|
+
path: `${filePath}:${abs.line}`,
|
|
534
|
+
message: abs.issue,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return { errors, warnings };
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Gate 3 Executor: Code Quality Check
|
|
543
|
+
*
|
|
544
|
+
* @param {Object} context - Gate context (validated against gateContextSchema)
|
|
545
|
+
* @returns {Promise<{ passed: boolean, errors: Array<{path: string, message: string}>, warnings: string[] }>}
|
|
546
|
+
*/
|
|
547
|
+
async function executeGate3(context) {
|
|
548
|
+
const errors = [];
|
|
549
|
+
const warnings = [];
|
|
550
|
+
|
|
551
|
+
// Extract named constants for reference
|
|
552
|
+
const namedConstants = context.namedConstants || [];
|
|
553
|
+
|
|
554
|
+
// Analyze each file
|
|
555
|
+
if (context.files && Array.isArray(context.files)) {
|
|
556
|
+
for (const file of context.files) {
|
|
557
|
+
const result = analyzeCodeFile(file, namedConstants);
|
|
558
|
+
errors.push(...result.errors);
|
|
559
|
+
warnings.push(...result.warnings.map(w =>
|
|
560
|
+
typeof w === 'string' ? w : `${w.path}: ${w.message}`
|
|
561
|
+
));
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Check for generic helper sprawl
|
|
566
|
+
if (context.genericHelpers && Array.isArray(context.genericHelpers)) {
|
|
567
|
+
const sprawlIssues = detectGenericHelperSprawl(context.genericHelpers);
|
|
568
|
+
for (const issue of sprawlIssues) {
|
|
569
|
+
warnings.push(issue.issue);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// Use pre-computed metrics if provided
|
|
574
|
+
if (context.metrics) {
|
|
575
|
+
const metrics = context.metrics;
|
|
576
|
+
|
|
577
|
+
if (metrics.maxNesting !== undefined && metrics.maxNesting > THRESHOLDS.maxNesting) {
|
|
578
|
+
errors.push({
|
|
579
|
+
path: 'metrics.maxNesting',
|
|
580
|
+
message: `Maximum nesting depth (${metrics.maxNesting}) exceeds threshold (${THRESHOLDS.maxNesting}).`,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (metrics.avgFunctionLength !== undefined && metrics.avgFunctionLength > THRESHOLDS.maxFunctionLength) {
|
|
585
|
+
errors.push({
|
|
586
|
+
path: 'metrics.avgFunctionLength',
|
|
587
|
+
message: `Average function length (${metrics.avgFunctionLength}) exceeds threshold (${THRESHOLDS.maxFunctionLength}).`,
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (metrics.magicNumberCount !== undefined && metrics.magicNumberCount > 0) {
|
|
592
|
+
warnings.push(`Found ${metrics.magicNumberCount} magic numbers. Consider using named constants.`);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (metrics.longParamListCount !== undefined && metrics.longParamListCount > 0) {
|
|
596
|
+
warnings.push(`Found ${metrics.longParamListCount} functions with long parameter lists.`);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return {
|
|
601
|
+
passed: errors.length === 0,
|
|
602
|
+
errors,
|
|
603
|
+
warnings,
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Create and register Gate 3 with a QualityGate instance
|
|
609
|
+
*
|
|
610
|
+
* @param {QualityGate} gateCoordinator - QualityGate coordinator instance
|
|
611
|
+
* @returns {void}
|
|
612
|
+
*/
|
|
613
|
+
function registerGate3(gateCoordinator) {
|
|
614
|
+
gateCoordinator.registerGate('gate-03-code', gateContextSchema, executeGate3);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
module.exports = {
|
|
618
|
+
executeGate3,
|
|
619
|
+
registerGate3,
|
|
620
|
+
codeFileSchema,
|
|
621
|
+
codeMetricsSchema,
|
|
622
|
+
gateContextSchema,
|
|
623
|
+
THRESHOLDS,
|
|
624
|
+
countLines,
|
|
625
|
+
calculateFunctionLength,
|
|
626
|
+
checkFunctionLength,
|
|
627
|
+
calculateNestingDepth,
|
|
628
|
+
checkNestingDepth,
|
|
629
|
+
detectMagicNumbers,
|
|
630
|
+
suggestConstantName,
|
|
631
|
+
checkParameterList,
|
|
632
|
+
detectGenericHelperSprawl,
|
|
633
|
+
detectPrematureAbstraction,
|
|
634
|
+
analyzeCodeFile,
|
|
635
|
+
};
|