aios-core 2.1.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/.aios-core/.session/current-session.json +14 -0
- package/.aios-core/cli/commands/generate/index.js +222 -0
- package/.aios-core/cli/commands/manifest/index.js +46 -0
- package/.aios-core/cli/commands/manifest/regenerate.js +96 -0
- package/.aios-core/cli/commands/manifest/validate.js +66 -0
- package/.aios-core/cli/commands/mcp/add.js +234 -0
- package/.aios-core/cli/commands/mcp/index.js +76 -0
- package/.aios-core/cli/commands/mcp/link.js +217 -0
- package/.aios-core/cli/commands/mcp/setup.js +164 -0
- package/.aios-core/cli/commands/mcp/status.js +183 -0
- package/.aios-core/cli/commands/metrics/cleanup.js +91 -0
- package/.aios-core/cli/commands/metrics/index.js +65 -0
- package/.aios-core/cli/commands/metrics/record.js +154 -0
- package/.aios-core/cli/commands/metrics/seed.js +126 -0
- package/.aios-core/cli/commands/metrics/show.js +209 -0
- package/.aios-core/cli/commands/migrate/analyze.js +353 -0
- package/.aios-core/cli/commands/migrate/backup.js +352 -0
- package/.aios-core/cli/commands/migrate/execute.js +292 -0
- package/.aios-core/cli/commands/migrate/index.js +441 -0
- package/.aios-core/cli/commands/migrate/rollback.js +323 -0
- package/.aios-core/cli/commands/migrate/update-imports.js +396 -0
- package/.aios-core/cli/commands/migrate/validate.js +452 -0
- package/.aios-core/cli/commands/qa/index.js +56 -0
- package/.aios-core/cli/commands/qa/run.js +163 -0
- package/.aios-core/cli/commands/qa/status.js +195 -0
- package/.aios-core/cli/commands/workers/formatters/info-formatter.js +274 -0
- package/.aios-core/cli/commands/workers/formatters/list-table.js +265 -0
- package/.aios-core/cli/commands/workers/formatters/list-tree.js +159 -0
- package/.aios-core/cli/commands/workers/index.js +56 -0
- package/.aios-core/cli/commands/workers/info.js +194 -0
- package/.aios-core/cli/commands/workers/list.js +214 -0
- package/.aios-core/cli/commands/workers/search-filters.js +185 -0
- package/.aios-core/cli/commands/workers/search-keyword.js +310 -0
- package/.aios-core/cli/commands/workers/search-semantic.js +293 -0
- package/.aios-core/cli/commands/workers/search.js +154 -0
- package/.aios-core/cli/commands/workers/utils/pagination.js +102 -0
- package/.aios-core/cli/index.js +128 -0
- package/.aios-core/cli/utils/output-formatter-cli.js +232 -0
- package/.aios-core/cli/utils/score-calculator.js +221 -0
- package/.aios-core/core/README.md +229 -0
- package/.aios-core/core/config/config-cache.js +233 -0
- package/.aios-core/core/config/config-loader.js +277 -0
- package/.aios-core/core/data/agent-config-requirements.yaml +368 -0
- package/.aios-core/core/data/aios-kb.md +924 -0
- package/.aios-core/core/data/workflow-patterns.yaml +267 -0
- package/.aios-core/core/docs/SHARD-TRANSLATION-GUIDE.md +335 -0
- package/.aios-core/core/docs/component-creation-guide.md +458 -0
- package/.aios-core/core/docs/session-update-pattern.md +307 -0
- package/.aios-core/core/docs/template-syntax.md +267 -0
- package/.aios-core/core/docs/troubleshooting-guide.md +625 -0
- package/.aios-core/core/elicitation/agent-elicitation.js +272 -0
- package/.aios-core/core/elicitation/elicitation-engine.js +479 -0
- package/.aios-core/core/elicitation/session-manager.js +320 -0
- package/.aios-core/core/elicitation/task-elicitation.js +281 -0
- package/.aios-core/core/elicitation/workflow-elicitation.js +315 -0
- package/.aios-core/core/index.esm.js +42 -0
- package/.aios-core/core/index.js +76 -0
- package/.aios-core/core/manifest/manifest-generator.js +386 -0
- package/.aios-core/core/manifest/manifest-validator.js +429 -0
- package/.aios-core/core/mcp/config-migrator.js +340 -0
- package/.aios-core/core/mcp/global-config-manager.js +369 -0
- package/.aios-core/core/mcp/index.js +34 -0
- package/.aios-core/core/mcp/os-detector.js +188 -0
- package/.aios-core/core/mcp/symlink-manager.js +413 -0
- package/.aios-core/core/migration/migration-config.yaml +83 -0
- package/.aios-core/core/migration/module-mapping.yaml +89 -0
- package/.aios-core/core/quality-gates/base-layer.js +134 -0
- package/.aios-core/core/quality-gates/checklist-generator.js +329 -0
- package/.aios-core/core/quality-gates/focus-area-recommender.js +359 -0
- package/.aios-core/core/quality-gates/human-review-orchestrator.js +529 -0
- package/.aios-core/core/quality-gates/layer1-precommit.js +336 -0
- package/.aios-core/core/quality-gates/layer2-pr-automation.js +324 -0
- package/.aios-core/core/quality-gates/layer3-human-review.js +348 -0
- package/.aios-core/core/quality-gates/notification-manager.js +550 -0
- package/.aios-core/core/quality-gates/quality-gate-config.yaml +86 -0
- package/.aios-core/core/quality-gates/quality-gate-manager.js +601 -0
- package/.aios-core/core/registry/README.md +179 -0
- package/.aios-core/core/registry/build-registry.js +452 -0
- package/.aios-core/core/registry/registry-loader.js +330 -0
- package/.aios-core/core/registry/registry-schema.json +166 -0
- package/.aios-core/core/registry/service-registry.json +6586 -0
- package/.aios-core/core/registry/validate-registry.js +340 -0
- package/.aios-core/core/session/context-detector.js +229 -0
- package/.aios-core/core/session/context-loader.js +288 -0
- package/.aios-core/core/utils/output-formatter.js +298 -0
- package/.aios-core/core/utils/security-utils.js +333 -0
- package/.aios-core/core/utils/yaml-validator.js +419 -0
- package/.aios-core/core-config.yaml +382 -0
- package/.aios-core/data/agent-config-requirements.yaml +368 -0
- package/.aios-core/data/aios-kb.md +924 -0
- package/.aios-core/data/technical-preferences.md +4 -0
- package/.aios-core/data/workflow-patterns.yaml +267 -0
- package/.aios-core/development/README.md +142 -0
- package/.aios-core/development/agent-teams/team-all.yaml +15 -0
- package/.aios-core/development/agent-teams/team-fullstack.yaml +18 -0
- package/.aios-core/development/agent-teams/team-ide-minimal.yaml +10 -0
- package/.aios-core/development/agent-teams/team-no-ui.yaml +13 -0
- package/.aios-core/development/agent-teams/team-qa-focused.yaml +155 -0
- package/.aios-core/development/agents/aios-master.md +339 -0
- package/.aios-core/development/agents/analyst.md +195 -0
- package/.aios-core/development/agents/architect.md +359 -0
- package/.aios-core/development/agents/data-engineer.md +468 -0
- package/.aios-core/development/agents/dev.md +390 -0
- package/.aios-core/development/agents/devops.md +398 -0
- package/.aios-core/development/agents/pm.md +198 -0
- package/.aios-core/development/agents/po.md +256 -0
- package/.aios-core/development/agents/qa.md +312 -0
- package/.aios-core/development/agents/sm.md +220 -0
- package/.aios-core/development/agents/ux-design-expert.md +451 -0
- package/.aios-core/development/scripts/agent-assignment-resolver.js +231 -0
- package/.aios-core/development/scripts/agent-config-loader.js +624 -0
- package/.aios-core/development/scripts/agent-exit-hooks.js +96 -0
- package/.aios-core/development/scripts/apply-inline-greeting-all-agents.js +146 -0
- package/.aios-core/development/scripts/audit-agent-config.js +380 -0
- package/.aios-core/development/scripts/backlog-manager.js +404 -0
- package/.aios-core/development/scripts/batch-update-agents-session-context.js +95 -0
- package/.aios-core/development/scripts/decision-context.js +228 -0
- package/.aios-core/development/scripts/decision-log-generator.js +293 -0
- package/.aios-core/development/scripts/decision-log-indexer.js +284 -0
- package/.aios-core/development/scripts/decision-recorder.js +168 -0
- package/.aios-core/development/scripts/dev-context-loader.js +297 -0
- package/.aios-core/development/scripts/generate-greeting.js +160 -0
- package/.aios-core/development/scripts/greeting-builder.js +866 -0
- package/.aios-core/development/scripts/greeting-config-cli.js +85 -0
- package/.aios-core/development/scripts/greeting-preference-manager.js +145 -0
- package/.aios-core/development/scripts/migrate-task-to-v2.js +377 -0
- package/.aios-core/development/scripts/story-index-generator.js +337 -0
- package/.aios-core/development/scripts/story-manager.js +375 -0
- package/.aios-core/development/scripts/story-update-hook.js +259 -0
- package/.aios-core/development/scripts/task-identifier-resolver.js +145 -0
- package/.aios-core/development/scripts/test-greeting-system.js +142 -0
- package/.aios-core/development/scripts/validate-task-v2.js +319 -0
- package/.aios-core/development/scripts/workflow-navigator.js +214 -0
- package/.aios-core/development/tasks/add-mcp.md +319 -0
- package/.aios-core/development/tasks/advanced-elicitation.md +319 -0
- package/.aios-core/development/tasks/analyst-facilitate-brainstorming.md +342 -0
- package/.aios-core/development/tasks/analyze-framework.md +697 -0
- package/.aios-core/development/tasks/analyze-performance.md +637 -0
- package/.aios-core/development/tasks/apply-qa-fixes.md +340 -0
- package/.aios-core/development/tasks/architect-analyze-impact.md +827 -0
- package/.aios-core/development/tasks/audit-codebase.md +429 -0
- package/.aios-core/development/tasks/audit-tailwind-config.md +270 -0
- package/.aios-core/development/tasks/audit-utilities.md +358 -0
- package/.aios-core/development/tasks/bootstrap-shadcn-library.md +286 -0
- package/.aios-core/development/tasks/brownfield-create-epic.md +486 -0
- package/.aios-core/development/tasks/brownfield-create-story.md +357 -0
- package/.aios-core/development/tasks/build-component.md +478 -0
- package/.aios-core/development/tasks/calculate-roi.md +455 -0
- package/.aios-core/development/tasks/ci-cd-configuration.md +764 -0
- package/.aios-core/development/tasks/cleanup-utilities.md +670 -0
- package/.aios-core/development/tasks/collaborative-edit.md +1109 -0
- package/.aios-core/development/tasks/compose-molecule.md +284 -0
- package/.aios-core/development/tasks/consolidate-patterns.md +414 -0
- package/.aios-core/development/tasks/correct-course.md +280 -0
- package/.aios-core/development/tasks/create-agent.md +322 -0
- package/.aios-core/development/tasks/create-brownfield-story.md +727 -0
- package/.aios-core/development/tasks/create-deep-research-prompt.md +499 -0
- package/.aios-core/development/tasks/create-doc.md +316 -0
- package/.aios-core/development/tasks/create-next-story.md +774 -0
- package/.aios-core/development/tasks/create-suite.md +284 -0
- package/.aios-core/development/tasks/create-task.md +372 -0
- package/.aios-core/development/tasks/create-workflow.md +371 -0
- package/.aios-core/development/tasks/db-analyze-hotpaths.md +572 -0
- package/.aios-core/development/tasks/db-apply-migration.md +381 -0
- package/.aios-core/development/tasks/db-bootstrap.md +642 -0
- package/.aios-core/development/tasks/db-domain-modeling.md +693 -0
- package/.aios-core/development/tasks/db-dry-run.md +293 -0
- package/.aios-core/development/tasks/db-env-check.md +260 -0
- package/.aios-core/development/tasks/db-expansion-pack-integration.md +663 -0
- package/.aios-core/development/tasks/db-explain.md +631 -0
- package/.aios-core/development/tasks/db-impersonate.md +495 -0
- package/.aios-core/development/tasks/db-load-csv.md +593 -0
- package/.aios-core/development/tasks/db-policy-apply.md +653 -0
- package/.aios-core/development/tasks/db-rls-audit.md +411 -0
- package/.aios-core/development/tasks/db-rollback.md +739 -0
- package/.aios-core/development/tasks/db-run-sql.md +613 -0
- package/.aios-core/development/tasks/db-schema-audit.md +1011 -0
- package/.aios-core/development/tasks/db-seed.md +390 -0
- package/.aios-core/development/tasks/db-smoke-test.md +351 -0
- package/.aios-core/development/tasks/db-snapshot.md +569 -0
- package/.aios-core/development/tasks/db-supabase-setup.md +712 -0
- package/.aios-core/development/tasks/db-verify-order.md +515 -0
- package/.aios-core/development/tasks/deprecate-component.md +957 -0
- package/.aios-core/development/tasks/dev-apply-qa-fixes.md +318 -0
- package/.aios-core/development/tasks/dev-backlog-debt.md +469 -0
- package/.aios-core/development/tasks/dev-develop-story.md +846 -0
- package/.aios-core/development/tasks/dev-improve-code-quality.md +873 -0
- package/.aios-core/development/tasks/dev-optimize-performance.md +1034 -0
- package/.aios-core/development/tasks/dev-suggest-refactoring.md +871 -0
- package/.aios-core/development/tasks/dev-validate-next-story.md +349 -0
- package/.aios-core/development/tasks/document-project.md +553 -0
- package/.aios-core/development/tasks/environment-bootstrap.md +1311 -0
- package/.aios-core/development/tasks/execute-checklist.md +301 -0
- package/.aios-core/development/tasks/export-design-tokens-dtcg.md +274 -0
- package/.aios-core/development/tasks/extend-pattern.md +269 -0
- package/.aios-core/development/tasks/extract-tokens.md +467 -0
- package/.aios-core/development/tasks/facilitate-brainstorming-session.md +518 -0
- package/.aios-core/development/tasks/generate-ai-frontend-prompt.md +261 -0
- package/.aios-core/development/tasks/generate-documentation.md +284 -0
- package/.aios-core/development/tasks/generate-migration-strategy.md +522 -0
- package/.aios-core/development/tasks/generate-shock-report.md +501 -0
- package/.aios-core/development/tasks/github-devops-github-pr-automation.md +427 -0
- package/.aios-core/development/tasks/github-devops-pre-push-quality-gate.md +733 -0
- package/.aios-core/development/tasks/github-devops-repository-cleanup.md +374 -0
- package/.aios-core/development/tasks/github-devops-version-management.md +483 -0
- package/.aios-core/development/tasks/improve-self.md +823 -0
- package/.aios-core/development/tasks/index-docs.md +388 -0
- package/.aios-core/development/tasks/init-project-status.md +506 -0
- package/.aios-core/development/tasks/integrate-expansion-pack.md +314 -0
- package/.aios-core/development/tasks/kb-mode-interaction.md +284 -0
- package/.aios-core/development/tasks/learn-patterns.md +901 -0
- package/.aios-core/development/tasks/mcp-workflow.md +437 -0
- package/.aios-core/development/tasks/modify-agent.md +382 -0
- package/.aios-core/development/tasks/modify-task.md +425 -0
- package/.aios-core/development/tasks/modify-workflow.md +466 -0
- package/.aios-core/development/tasks/po-backlog-add.md +370 -0
- package/.aios-core/development/tasks/po-manage-story-backlog.md +523 -0
- package/.aios-core/development/tasks/po-pull-story-from-clickup.md +540 -0
- package/.aios-core/development/tasks/po-pull-story.md +316 -0
- package/.aios-core/development/tasks/po-stories-index.md +351 -0
- package/.aios-core/development/tasks/po-sync-story-to-clickup.md +457 -0
- package/.aios-core/development/tasks/po-sync-story.md +303 -0
- package/.aios-core/development/tasks/pr-automation.md +701 -0
- package/.aios-core/development/tasks/propose-modification.md +843 -0
- package/.aios-core/development/tasks/qa-backlog-add-followup.md +425 -0
- package/.aios-core/development/tasks/qa-gate.md +374 -0
- package/.aios-core/development/tasks/qa-generate-tests.md +1175 -0
- package/.aios-core/development/tasks/qa-nfr-assess.md +558 -0
- package/.aios-core/development/tasks/qa-review-proposal.md +1158 -0
- package/.aios-core/development/tasks/qa-review-story.md +683 -0
- package/.aios-core/development/tasks/qa-risk-profile.md +567 -0
- package/.aios-core/development/tasks/qa-run-tests.md +277 -0
- package/.aios-core/development/tasks/qa-test-design.md +388 -0
- package/.aios-core/development/tasks/qa-trace-requirements.md +477 -0
- package/.aios-core/development/tasks/release-management.md +723 -0
- package/.aios-core/development/tasks/security-audit.md +554 -0
- package/.aios-core/development/tasks/security-scan.md +790 -0
- package/.aios-core/development/tasks/setup-database.md +741 -0
- package/.aios-core/development/tasks/setup-design-system.md +462 -0
- package/.aios-core/development/tasks/setup-github.md +874 -0
- package/.aios-core/development/tasks/setup-llm-routing.md +229 -0
- package/.aios-core/development/tasks/setup-mcp-docker.md +584 -0
- package/.aios-core/development/tasks/shard-doc.md +538 -0
- package/.aios-core/development/tasks/sm-create-next-story.md +480 -0
- package/.aios-core/development/tasks/sync-documentation.md +865 -0
- package/.aios-core/development/tasks/tailwind-upgrade.md +294 -0
- package/.aios-core/development/tasks/test-as-user.md +621 -0
- package/.aios-core/development/tasks/test-validation-task.md +171 -0
- package/.aios-core/development/tasks/undo-last.md +347 -0
- package/.aios-core/development/tasks/update-manifest.md +410 -0
- package/.aios-core/development/tasks/ux-create-wireframe.md +617 -0
- package/.aios-core/development/tasks/ux-ds-scan-artifact.md +672 -0
- package/.aios-core/development/tasks/ux-user-research.md +559 -0
- package/.aios-core/development/tasks/validate-next-story.md +423 -0
- package/.aios-core/development/tasks/validate-structure.md +243 -0
- package/.aios-core/development/workflows/README.md +84 -0
- package/.aios-core/development/workflows/brownfield-fullstack.yaml +297 -0
- package/.aios-core/development/workflows/brownfield-service.yaml +187 -0
- package/.aios-core/development/workflows/brownfield-ui.yaml +197 -0
- package/.aios-core/development/workflows/greenfield-fullstack.yaml +333 -0
- package/.aios-core/development/workflows/greenfield-service.yaml +206 -0
- package/.aios-core/development/workflows/greenfield-ui.yaml +235 -0
- package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +335 -0
- package/.aios-core/docs/component-creation-guide.md +458 -0
- package/.aios-core/docs/session-update-pattern.md +307 -0
- package/.aios-core/docs/standards/AGENT-PERSONALIZATION-STANDARD-V1.md +572 -0
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-QUICK-REFERENCE.md +185 -0
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +354 -0
- package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +1963 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +821 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +1190 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +439 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +1339 -0
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +5398 -0
- package/.aios-core/docs/standards/EXECUTOR-DECISION-TREE.md +697 -0
- package/.aios-core/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +511 -0
- package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +556 -0
- package/.aios-core/docs/standards/STANDARDS-INDEX.md +210 -0
- package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +550 -0
- package/.aios-core/docs/standards/TASK-FORMAT-SPECIFICATION-V1.md +1414 -0
- package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +523 -0
- package/.aios-core/docs/template-syntax.md +267 -0
- package/.aios-core/docs/troubleshooting-guide.md +625 -0
- package/.aios-core/elicitation/agent-elicitation.js +272 -0
- package/.aios-core/elicitation/task-elicitation.js +281 -0
- package/.aios-core/elicitation/workflow-elicitation.js +315 -0
- package/.aios-core/index.d.ts +8 -0
- package/.aios-core/index.esm.js +16 -0
- package/.aios-core/index.js +16 -0
- package/.aios-core/infrastructure/README.md +126 -0
- package/.aios-core/infrastructure/index.js +199 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/README.md +59 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/clickup-adapter.js +345 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/github-adapter.js +392 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/jira-adapter.js +448 -0
- package/.aios-core/infrastructure/integrations/pm-adapters/local-adapter.js +175 -0
- package/.aios-core/infrastructure/scripts/_archived/final-todo-count.js +122 -0
- package/.aios-core/infrastructure/scripts/_archived/fix-yaml-formatting.js +89 -0
- package/.aios-core/infrastructure/scripts/_archived/migration-generator.js +780 -0
- package/.aios-core/infrastructure/scripts/_archived/migration-path-generator.js +950 -0
- package/.aios-core/infrastructure/scripts/_archived/phase2-entrada-saida-errors.js +425 -0
- package/.aios-core/infrastructure/scripts/_archived/phase2-spot-check.js +132 -0
- package/.aios-core/infrastructure/scripts/_archived/phase3-tools-scripts-validation.js +381 -0
- package/.aios-core/infrastructure/scripts/_archived/phase4-metadata-performance.js +203 -0
- package/.aios-core/infrastructure/scripts/_archived/test-yaml-parsing.js +24 -0
- package/.aios-core/infrastructure/scripts/_archived/verify-yaml-fix.js +51 -0
- package/.aios-core/infrastructure/scripts/aios-validator.js +294 -0
- package/.aios-core/infrastructure/scripts/approval-workflow.js +643 -0
- package/.aios-core/infrastructure/scripts/atomic-layer-classifier.js +308 -0
- package/.aios-core/infrastructure/scripts/backup-manager.js +607 -0
- package/.aios-core/infrastructure/scripts/batch-creator.js +608 -0
- package/.aios-core/infrastructure/scripts/branch-manager.js +391 -0
- package/.aios-core/infrastructure/scripts/capability-analyzer.js +535 -0
- package/.aios-core/infrastructure/scripts/clickup-helpers.js +226 -0
- package/.aios-core/infrastructure/scripts/code-quality-improver.js +1312 -0
- package/.aios-core/infrastructure/scripts/commit-message-generator.js +850 -0
- package/.aios-core/infrastructure/scripts/component-generator.js +738 -0
- package/.aios-core/infrastructure/scripts/component-metadata.js +627 -0
- package/.aios-core/infrastructure/scripts/component-search.js +277 -0
- package/.aios-core/infrastructure/scripts/config-cache.js +322 -0
- package/.aios-core/infrastructure/scripts/config-loader.js +349 -0
- package/.aios-core/infrastructure/scripts/conflict-resolver.js +675 -0
- package/.aios-core/infrastructure/scripts/coverage-analyzer.js +882 -0
- package/.aios-core/infrastructure/scripts/dependency-analyzer.js +638 -0
- package/.aios-core/infrastructure/scripts/dependency-impact-analyzer.js +703 -0
- package/.aios-core/infrastructure/scripts/diff-generator.js +129 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/brownfield-analyzer.js +501 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/config-generator.js +329 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/deployment-config-loader.js +282 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/doc-generator.js +331 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/gitignore-generator.js +313 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/index.js +74 -0
- package/.aios-core/infrastructure/scripts/documentation-integrity/mode-detector.js +358 -0
- package/.aios-core/infrastructure/scripts/documentation-synchronizer.js +1432 -0
- package/.aios-core/infrastructure/scripts/framework-analyzer.js +746 -0
- package/.aios-core/infrastructure/scripts/git-config-detector.js +293 -0
- package/.aios-core/infrastructure/scripts/git-wrapper.js +443 -0
- package/.aios-core/infrastructure/scripts/improvement-engine.js +758 -0
- package/.aios-core/infrastructure/scripts/improvement-validator.js +710 -0
- package/.aios-core/infrastructure/scripts/llm-routing/install-llm-routing.js +267 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-free.cmd +80 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-free.sh +62 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-max.cmd +26 -0
- package/.aios-core/infrastructure/scripts/llm-routing/templates/claude-max.sh +18 -0
- package/.aios-core/infrastructure/scripts/modification-risk-assessment.js +970 -0
- package/.aios-core/infrastructure/scripts/modification-validator.js +555 -0
- package/.aios-core/infrastructure/scripts/output-formatter.js +297 -0
- package/.aios-core/infrastructure/scripts/performance-analyzer.js +758 -0
- package/.aios-core/infrastructure/scripts/performance-and-error-resolver.js +258 -0
- package/.aios-core/infrastructure/scripts/performance-optimizer.js +1902 -0
- package/.aios-core/infrastructure/scripts/performance-tracker.js +452 -0
- package/.aios-core/infrastructure/scripts/pm-adapter-factory.js +181 -0
- package/.aios-core/infrastructure/scripts/pm-adapter.js +134 -0
- package/.aios-core/infrastructure/scripts/project-status-loader.js +445 -0
- package/.aios-core/infrastructure/scripts/refactoring-suggester.js +1139 -0
- package/.aios-core/infrastructure/scripts/repository-detector.js +64 -0
- package/.aios-core/infrastructure/scripts/sandbox-tester.js +618 -0
- package/.aios-core/infrastructure/scripts/security-checker.js +359 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/index.js +375 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/manifest-generator.js +410 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/naming-rules.yaml +285 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/placement-rules.yaml +262 -0
- package/.aios-core/infrastructure/scripts/source-tree-guardian/validator.js +468 -0
- package/.aios-core/infrastructure/scripts/spot-check-validator.js +149 -0
- package/.aios-core/infrastructure/scripts/status-mapper.js +115 -0
- package/.aios-core/infrastructure/scripts/template-engine.js +240 -0
- package/.aios-core/infrastructure/scripts/template-validator.js +279 -0
- package/.aios-core/infrastructure/scripts/test-generator.js +844 -0
- package/.aios-core/infrastructure/scripts/test-quality-assessment.js +1081 -0
- package/.aios-core/infrastructure/scripts/test-utilities-fast.js +126 -0
- package/.aios-core/infrastructure/scripts/test-utilities.js +200 -0
- package/.aios-core/infrastructure/scripts/tool-resolver.js +360 -0
- package/.aios-core/infrastructure/scripts/transaction-manager.js +590 -0
- package/.aios-core/infrastructure/scripts/usage-analytics.js +634 -0
- package/.aios-core/infrastructure/scripts/validate-output-pattern.js +213 -0
- package/.aios-core/infrastructure/scripts/visual-impact-generator.js +1056 -0
- package/.aios-core/infrastructure/scripts/yaml-validator.js +397 -0
- package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -0
- package/.aios-core/infrastructure/templates/core-config/core-config-brownfield.tmpl.yaml +182 -0
- package/.aios-core/infrastructure/templates/core-config/core-config-greenfield.tmpl.yaml +127 -0
- package/.aios-core/infrastructure/templates/github-workflows/README.md +109 -0
- package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -0
- package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -0
- package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -0
- package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -0
- package/.aios-core/infrastructure/templates/project-docs/coding-standards-tmpl.md +346 -0
- package/.aios-core/infrastructure/templates/project-docs/source-tree-tmpl.md +177 -0
- package/.aios-core/infrastructure/templates/project-docs/tech-stack-tmpl.md +267 -0
- package/.aios-core/infrastructure/tests/project-status-loader.test.js +394 -0
- package/.aios-core/infrastructure/tests/regression-suite-v2.md +621 -0
- package/.aios-core/infrastructure/tests/utilities-audit-results.json +501 -0
- package/.aios-core/infrastructure/tests/validate-module.js +97 -0
- package/.aios-core/infrastructure/tools/README.md +222 -0
- package/.aios-core/infrastructure/tools/cli/github-cli.yaml +200 -0
- package/.aios-core/infrastructure/tools/cli/llm-routing.yaml +126 -0
- package/.aios-core/infrastructure/tools/cli/railway-cli.yaml +260 -0
- package/.aios-core/infrastructure/tools/cli/supabase-cli.yaml +224 -0
- package/.aios-core/infrastructure/tools/local/ffmpeg.yaml +261 -0
- package/.aios-core/infrastructure/tools/mcp/21st-dev-magic.yaml +127 -0
- package/.aios-core/infrastructure/tools/mcp/browser.yaml +103 -0
- package/.aios-core/infrastructure/tools/mcp/clickup.yaml +534 -0
- package/.aios-core/infrastructure/tools/mcp/context7.yaml +78 -0
- package/.aios-core/infrastructure/tools/mcp/desktop-commander.yaml +180 -0
- package/.aios-core/infrastructure/tools/mcp/exa.yaml +103 -0
- package/.aios-core/infrastructure/tools/mcp/google-workspace.yaml +930 -0
- package/.aios-core/infrastructure/tools/mcp/n8n.yaml +551 -0
- package/.aios-core/infrastructure/tools/mcp/supabase.yaml +808 -0
- package/.aios-core/install-manifest.yaml +347 -0
- package/.aios-core/manifests/agents.csv +1 -0
- package/.aios-core/manifests/schema/manifest-schema.json +190 -0
- package/.aios-core/manifests/tasks.csv +121 -0
- package/.aios-core/manifests/workers.csv +204 -0
- package/.aios-core/package.json +103 -0
- package/.aios-core/product/README.md +56 -0
- package/.aios-core/product/checklists/architect-checklist.md +444 -0
- package/.aios-core/product/checklists/change-checklist.md +183 -0
- package/.aios-core/product/checklists/database-design-checklist.md +119 -0
- package/.aios-core/product/checklists/dba-predeploy-checklist.md +97 -0
- package/.aios-core/product/checklists/dba-rollback-checklist.md +99 -0
- package/.aios-core/product/checklists/pm-checklist.md +376 -0
- package/.aios-core/product/checklists/po-master-checklist.md +442 -0
- package/.aios-core/product/checklists/pre-push-checklist.md +108 -0
- package/.aios-core/product/checklists/release-checklist.md +122 -0
- package/.aios-core/product/checklists/story-dod-checklist.md +102 -0
- package/.aios-core/product/checklists/story-draft-checklist.md +216 -0
- package/.aios-core/product/data/brainstorming-techniques.md +37 -0
- package/.aios-core/product/data/elicitation-methods.md +135 -0
- package/.aios-core/product/data/mode-selection-best-practices.md +471 -0
- package/.aios-core/product/data/test-levels-framework.md +149 -0
- package/.aios-core/product/data/test-priorities-matrix.md +175 -0
- package/.aios-core/product/templates/1mcp-config.yaml +225 -0
- package/.aios-core/product/templates/activation-instructions-inline-greeting.yaml +63 -0
- package/.aios-core/product/templates/activation-instructions-template.md +258 -0
- package/.aios-core/product/templates/adr.hbs +125 -0
- package/.aios-core/product/templates/agent-template.yaml +121 -0
- package/.aios-core/product/templates/architecture-tmpl.yaml +651 -0
- package/.aios-core/product/templates/brainstorming-output-tmpl.yaml +156 -0
- package/.aios-core/product/templates/brownfield-architecture-tmpl.yaml +476 -0
- package/.aios-core/product/templates/brownfield-prd-tmpl.yaml +280 -0
- package/.aios-core/product/templates/changelog-template.md +134 -0
- package/.aios-core/product/templates/command-rationalization-matrix.md +152 -0
- package/.aios-core/product/templates/competitor-analysis-tmpl.yaml +293 -0
- package/.aios-core/product/templates/component-react-tmpl.tsx +98 -0
- package/.aios-core/product/templates/dbdr.hbs +241 -0
- package/.aios-core/product/templates/design-story-tmpl.yaml +587 -0
- package/.aios-core/product/templates/ds-artifact-analysis.md +70 -0
- package/.aios-core/product/templates/engine/elicitation.js +298 -0
- package/.aios-core/product/templates/engine/index.js +308 -0
- package/.aios-core/product/templates/engine/loader.js +231 -0
- package/.aios-core/product/templates/engine/renderer.js +343 -0
- package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -0
- package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -0
- package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -0
- package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -0
- package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -0
- package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -0
- package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -0
- package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -0
- package/.aios-core/product/templates/engine/validator.js +294 -0
- package/.aios-core/product/templates/epic.hbs +212 -0
- package/.aios-core/product/templates/eslintrc-security.json +32 -0
- package/.aios-core/product/templates/front-end-architecture-tmpl.yaml +206 -0
- package/.aios-core/product/templates/front-end-spec-tmpl.yaml +349 -0
- package/.aios-core/product/templates/fullstack-architecture-tmpl.yaml +805 -0
- package/.aios-core/product/templates/github-actions-cd.yml +212 -0
- package/.aios-core/product/templates/github-actions-ci.yml +172 -0
- package/.aios-core/product/templates/github-pr-template.md +67 -0
- package/.aios-core/product/templates/gordon-mcp.yaml +140 -0
- package/.aios-core/product/templates/ide-rules/antigravity-rules.md +115 -0
- package/.aios-core/product/templates/ide-rules/claude-rules.md +221 -0
- package/.aios-core/product/templates/ide-rules/cline-rules.md +84 -0
- package/.aios-core/product/templates/ide-rules/copilot-rules.md +92 -0
- package/.aios-core/product/templates/ide-rules/cursor-rules.md +115 -0
- package/.aios-core/product/templates/ide-rules/gemini-rules.md +85 -0
- package/.aios-core/product/templates/ide-rules/roo-rules.md +86 -0
- package/.aios-core/product/templates/ide-rules/trae-rules.md +104 -0
- package/.aios-core/product/templates/ide-rules/windsurf-rules.md +80 -0
- package/.aios-core/product/templates/index-strategy-tmpl.yaml +53 -0
- package/.aios-core/product/templates/market-research-tmpl.yaml +252 -0
- package/.aios-core/product/templates/mcp-workflow.js +271 -0
- package/.aios-core/product/templates/migration-plan-tmpl.yaml +1022 -0
- package/.aios-core/product/templates/migration-strategy-tmpl.md +524 -0
- package/.aios-core/product/templates/personalized-agent-template.md +258 -0
- package/.aios-core/product/templates/personalized-checklist-template.md +340 -0
- package/.aios-core/product/templates/personalized-task-template-v2.md +905 -0
- package/.aios-core/product/templates/personalized-task-template.md +344 -0
- package/.aios-core/product/templates/personalized-template-file.yaml +322 -0
- package/.aios-core/product/templates/personalized-workflow-template.yaml +460 -0
- package/.aios-core/product/templates/pmdr.hbs +186 -0
- package/.aios-core/product/templates/prd-tmpl.yaml +202 -0
- package/.aios-core/product/templates/prd-v2.0.hbs +216 -0
- package/.aios-core/product/templates/prd.hbs +201 -0
- package/.aios-core/product/templates/project-brief-tmpl.yaml +221 -0
- package/.aios-core/product/templates/qa-gate-tmpl.yaml +240 -0
- package/.aios-core/product/templates/rls-policies-tmpl.yaml +1203 -0
- package/.aios-core/product/templates/schema-design-tmpl.yaml +428 -0
- package/.aios-core/product/templates/shock-report-tmpl.html +502 -0
- package/.aios-core/product/templates/state-persistence-tmpl.yaml +219 -0
- package/.aios-core/product/templates/story-tmpl.yaml +332 -0
- package/.aios-core/product/templates/story.hbs +263 -0
- package/.aios-core/product/templates/task-execution-report.md +495 -0
- package/.aios-core/product/templates/task-template.md +123 -0
- package/.aios-core/product/templates/task.hbs +170 -0
- package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -0
- package/.aios-core/product/templates/tmpl-migration-script.sql +91 -0
- package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -0
- package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -0
- package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -0
- package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -0
- package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -0
- package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -0
- package/.aios-core/product/templates/tmpl-seed-data.sql +140 -0
- package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -0
- package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -0
- package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -0
- package/.aios-core/product/templates/tmpl-trigger.sql +152 -0
- package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -0
- package/.aios-core/product/templates/tmpl-view.sql +177 -0
- package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -0
- package/.aios-core/product/templates/token-exports-tailwind-tmpl.js +395 -0
- package/.aios-core/product/templates/tokens-schema-tmpl.yaml +305 -0
- package/.aios-core/product/templates/workflow-template.yaml +134 -0
- package/.aios-core/quality/metrics-collector.js +572 -0
- package/.aios-core/quality/metrics-hook.js +260 -0
- package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -0
- package/.aios-core/quality/seed-metrics.js +336 -0
- package/.aios-core/scripts/README.md +354 -0
- package/.aios-core/scripts/aios-doc-template.md +325 -0
- package/.aios-core/scripts/batch-migrate-phase1.ps1 +36 -0
- package/.aios-core/scripts/batch-migrate-phase2.ps1 +88 -0
- package/.aios-core/scripts/batch-migrate-phase3.ps1 +45 -0
- package/.aios-core/scripts/command-execution-hook.js +201 -0
- package/.aios-core/scripts/context-detector.js +226 -0
- package/.aios-core/scripts/elicitation-engine.js +385 -0
- package/.aios-core/scripts/elicitation-session-manager.js +300 -0
- package/.aios-core/scripts/migrate-framework-docs.sh +300 -0
- package/.aios-core/scripts/session-context-loader.js +286 -0
- package/.aios-core/scripts/test-template-system.js +941 -0
- package/.aios-core/scripts/validate-phase1.ps1 +35 -0
- package/.aios-core/scripts/workflow-management.md +69 -0
- package/.aios-core/tasks/find-component.md.legacy +391 -0
- package/.aios-core/tasks/generate-commit-message.md.legacy +426 -0
- package/.aios-core/tasks/generate-migration.md.legacy +382 -0
- package/.aios-core/tasks/rollback-modification.md.legacy +307 -0
- package/.aios-core/tasks/update-tests.md.legacy +283 -0
- package/.aios-core/user-guide.md +1413 -0
- package/.aios-core/working-in-the-brownfield.md +361 -0
- package/.claude/CLAUDE.md +221 -0
- package/LICENSE +48 -0
- package/README.md +703 -0
- package/bin/aios-init-old.js +532 -0
- package/bin/aios-init-v4.js +390 -0
- package/bin/aios-init.backup-v1.1.4.js +352 -0
- package/bin/aios-init.js +736 -0
- package/bin/aios-minimal.js +26 -0
- package/bin/aios.js +279 -0
- package/bin/migrate-pm-config.js +219 -0
- package/bin/modules/env-config.js +436 -0
- package/bin/modules/mcp-installer.js +383 -0
- package/bin/utils/install-errors.js +339 -0
- package/bin/utils/install-transaction.js +445 -0
- package/index.d.ts +19 -0
- package/index.esm.js +21 -0
- package/index.js +94 -0
- package/package.json +161 -0
- package/packages/installer/package.json +39 -0
- package/packages/installer/src/config/configure-environment.js +312 -0
- package/packages/installer/src/config/templates/core-config-template.js +183 -0
- package/packages/installer/src/config/templates/env-template.js +127 -0
- package/packages/installer/src/config/validation/config-validator.js +243 -0
- package/packages/installer/src/detection/detect-project-type.js +81 -0
- package/packages/installer/src/wizard/wizard.js +244 -0
- package/packages/installer/tests/integration/environment-configuration.test.js +328 -0
- package/packages/installer/tests/integration/wizard-detection.test.js +349 -0
- package/packages/installer/tests/unit/config-validator.test.js +315 -0
- package/packages/installer/tests/unit/detection/detect-project-type.test.js +401 -0
- package/packages/installer/tests/unit/env-template.test.js +185 -0
- package/src/config/ide-configs.js +189 -0
- package/src/installer/aios-core-installer.js +319 -0
- package/src/installer/dependency-installer.js +335 -0
- package/src/utils/aios-colors.js +234 -0
- package/src/wizard/feedback.js +218 -0
- package/src/wizard/ide-config-generator.js +488 -0
- package/src/wizard/ide-selector.js +84 -0
- package/src/wizard/index.js +589 -0
- package/src/wizard/questions.js +249 -0
- package/src/wizard/validation/index.js +120 -0
- package/src/wizard/validation/report-generator.js +269 -0
- package/src/wizard/validation/troubleshooting-system.js +346 -0
- package/src/wizard/validation/validators/config-validator.js +362 -0
- package/src/wizard/validation/validators/dependency-validator.js +333 -0
- package/src/wizard/validation/validators/file-structure-validator.js +181 -0
- package/src/wizard/validation/validators/mcp-health-checker.js +310 -0
- package/src/wizard/validators.js +274 -0
- package/templates/squad/LICENSE +21 -0
- package/templates/squad/README.md +37 -0
- package/templates/squad/agents/example-agent.yaml +36 -0
- package/templates/squad/package.json +19 -0
- package/templates/squad/squad.yaml +25 -0
- package/templates/squad/tasks/example-task.yaml +46 -0
- package/templates/squad/templates/example-template.md +24 -0
- package/templates/squad/tests/example-agent.test.js +53 -0
- package/templates/squad/workflows/example-workflow.yaml +54 -0
- package/tools/package-builder.js +35 -0
|
@@ -0,0 +1,1081 @@
|
|
|
1
|
+
const fs = require('fs').promises;
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Test quality assessment for AIOS-FULLSTACK test generation
|
|
7
|
+
* Evaluates generated test quality and provides improvement recommendations
|
|
8
|
+
*/
|
|
9
|
+
class TestQualityAssessment {
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
this.rootPath = options.rootPath || process.cwd();
|
|
12
|
+
this.qualityReportsDir = path.join(this.rootPath, '.aios', 'quality-reports');
|
|
13
|
+
this.qualityStandards = this.initializeQualityStandards();
|
|
14
|
+
this.assessmentCache = new Map();
|
|
15
|
+
this.qualityHistory = [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Initialize test quality assessment
|
|
20
|
+
*/
|
|
21
|
+
async initialize() {
|
|
22
|
+
try {
|
|
23
|
+
// Create quality reports directory
|
|
24
|
+
await fs.mkdir(this.qualityReportsDir, { recursive: true });
|
|
25
|
+
|
|
26
|
+
// Load existing quality history
|
|
27
|
+
await this.loadQualityHistory();
|
|
28
|
+
|
|
29
|
+
console.log(chalk.green('✅ Test quality assessment initialized'));
|
|
30
|
+
return true;
|
|
31
|
+
|
|
32
|
+
} catch (_error) {
|
|
33
|
+
console.error(chalk.red(`Failed to initialize test quality assessment: ${error.message}`));
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Assess quality of a single test file
|
|
40
|
+
*/
|
|
41
|
+
async analyzeSingleTestFile(testFilePath) {
|
|
42
|
+
console.log(chalk.blue(`🔍 Assessing test quality: ${path.basename(testFilePath)}`));
|
|
43
|
+
|
|
44
|
+
const assessment = {
|
|
45
|
+
file_path: testFilePath,
|
|
46
|
+
analyzed_at: new Date().toISOString(),
|
|
47
|
+
overall_score: 0,
|
|
48
|
+
quality_rating: 'unknown',
|
|
49
|
+
metrics: {},
|
|
50
|
+
issues: [],
|
|
51
|
+
recommendations: [],
|
|
52
|
+
estimatedCoverage: 0,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
// Read test file content
|
|
57
|
+
const content = await fs.readFile(testFilePath, 'utf-8');
|
|
58
|
+
|
|
59
|
+
// Analyze various quality metrics
|
|
60
|
+
assessment.metrics = await this.analyzeQualityMetrics(_content);
|
|
61
|
+
|
|
62
|
+
// Calculate overall quality score
|
|
63
|
+
assessment.overall_score = this.calculateOverallScore(assessment.metrics);
|
|
64
|
+
|
|
65
|
+
// Determine quality rating
|
|
66
|
+
assessment.quality_rating = this.determineQualityRating(assessment.overall_score);
|
|
67
|
+
|
|
68
|
+
// Identify quality issues
|
|
69
|
+
assessment.issues = this.identifyQualityIssues(assessment.metrics, content);
|
|
70
|
+
|
|
71
|
+
// Generate improvement recommendations
|
|
72
|
+
assessment.recommendations = this.generateRecommendations(assessment.metrics, assessment.issues);
|
|
73
|
+
|
|
74
|
+
// Estimate coverage contribution
|
|
75
|
+
assessment.estimatedCoverage = this.estimateCoverageContribution(assessment.metrics);
|
|
76
|
+
|
|
77
|
+
// Cache assessment
|
|
78
|
+
this.assessmentCache.set(testFilePath, assessment);
|
|
79
|
+
|
|
80
|
+
console.log(chalk.green(`✅ Test quality assessed: ${assessment.quality_rating} (${assessment.overall_score.toFixed(1)}/10)`));
|
|
81
|
+
|
|
82
|
+
return assessment;
|
|
83
|
+
|
|
84
|
+
} catch (_error) {
|
|
85
|
+
console.error(chalk.red(`Failed to assess test quality for ${testFilePath}: ${error.message}`));
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Assess quality of multiple test files
|
|
92
|
+
*/
|
|
93
|
+
async assessTestSuite(testFiles, options = {}) {
|
|
94
|
+
const suiteAssessment = {
|
|
95
|
+
assessed_at: new Date().toISOString(),
|
|
96
|
+
test_files: testFiles.length,
|
|
97
|
+
overall_suite_score: 0,
|
|
98
|
+
quality_distribution: {},
|
|
99
|
+
common_issues: [],
|
|
100
|
+
suite_recommendations: [],
|
|
101
|
+
file_assessments: {},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
console.log(chalk.blue(`📋 Assessing test suite quality (${testFiles.length} files)`));
|
|
105
|
+
|
|
106
|
+
const scores = [];
|
|
107
|
+
const allIssues = [];
|
|
108
|
+
const qualityRatings = { excellent: 0, good: 0, fair: 0, poor: 0, very_poor: 0 };
|
|
109
|
+
|
|
110
|
+
// Assess each test file
|
|
111
|
+
for (const testFile of testFiles) {
|
|
112
|
+
try {
|
|
113
|
+
const assessment = await this.analyzeSingleTestFile(testFile);
|
|
114
|
+
|
|
115
|
+
suiteAssessment.file_assessments[testFile] = assessment;
|
|
116
|
+
scores.push(assessment.overall_score);
|
|
117
|
+
allIssues.push(...assessment.issues);
|
|
118
|
+
qualityRatings[assessment.quality_rating]++;
|
|
119
|
+
|
|
120
|
+
} catch (_error) {
|
|
121
|
+
console.warn(chalk.yellow(`Failed to assess ${testFile}: ${error.message}`));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Calculate suite-level metrics
|
|
126
|
+
suiteAssessment.overall_suite_score = scores.length > 0
|
|
127
|
+
? scores.reduce((sum, score) => sum + score, 0) / scores.length
|
|
128
|
+
: 0;
|
|
129
|
+
|
|
130
|
+
suiteAssessment.quality_distribution = qualityRatings;
|
|
131
|
+
suiteAssessment.common_issues = this.identifyCommonIssues(allIssues);
|
|
132
|
+
suiteAssessment.suite_recommendations = this.generateSuiteRecommendations(suiteAssessment);
|
|
133
|
+
|
|
134
|
+
// Save suite assessment
|
|
135
|
+
await this.saveSuiteAssessment(suiteAssessment);
|
|
136
|
+
|
|
137
|
+
console.log(chalk.green('✅ Test suite assessment completed'));
|
|
138
|
+
console.log(chalk.gray(` Overall score: ${suiteAssessment.overall_suite_score.toFixed(1)}/10`));
|
|
139
|
+
console.log(chalk.gray(` Files assessed: ${testFiles.length}`));
|
|
140
|
+
console.log(chalk.gray(` Common issues: ${suiteAssessment.common_issues.length}`));
|
|
141
|
+
|
|
142
|
+
return suiteAssessment;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Analyze quality metrics for test content
|
|
147
|
+
*/
|
|
148
|
+
async analyzeQualityMetrics(_content) {
|
|
149
|
+
const metrics = {
|
|
150
|
+
// Structure metrics
|
|
151
|
+
test_organization: this.analyzeTestOrganization(_content),
|
|
152
|
+
naming_quality: this.analyzeNamingQuality(_content),
|
|
153
|
+
|
|
154
|
+
// Content metrics
|
|
155
|
+
assertion_quality: this.analyzeAssertionQuality(_content),
|
|
156
|
+
test_coverage_breadth: this.analyzeTestCoverageBreadth(_content),
|
|
157
|
+
edge_case_coverage: this.analyzeEdgeCaseCoverage(_content),
|
|
158
|
+
|
|
159
|
+
// Code quality metrics
|
|
160
|
+
code_clarity: this.analyzeCodeClarity(_content),
|
|
161
|
+
maintainability: this.analyzeMaintainability(_content),
|
|
162
|
+
|
|
163
|
+
// Testing best practices
|
|
164
|
+
isolation: this.analyzeTestIsolation(_content),
|
|
165
|
+
reliability: this.analyzeTestReliability(_content),
|
|
166
|
+
performance: this.analyzeTestPerformance(_content),
|
|
167
|
+
|
|
168
|
+
// Framework usage
|
|
169
|
+
framework_usage: this.analyzeFrameworkUsage(_content),
|
|
170
|
+
mock_quality: this.analyzeMockQuality(_content),
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
return metrics;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Analyze test organization and structure
|
|
178
|
+
*/
|
|
179
|
+
analyzeTestOrganization(_content) {
|
|
180
|
+
const score = { value: 0, max: 10, details: {} };
|
|
181
|
+
|
|
182
|
+
// Check for describe blocks
|
|
183
|
+
const describeBlocks = content.match(/describe\s*\([^{]+\{/g) || [];
|
|
184
|
+
score.details.has_describe_blocks = describeBlocks.length > 0;
|
|
185
|
+
if (score.details.has_describe_blocks) score.value += 2;
|
|
186
|
+
|
|
187
|
+
// Check for nested organization
|
|
188
|
+
const nestedDescribe = content.match(/describe\s*\([^{]*\{\s*[\s\S]*?describe\s*\(/g) || [];
|
|
189
|
+
score.details.has_nested_structure = nestedDescribe.length > 0;
|
|
190
|
+
if (score.details.has_nested_structure) score.value += 1;
|
|
191
|
+
|
|
192
|
+
// Check for setup/teardown
|
|
193
|
+
const setupMethods = content.match(/\b(?:beforeEach|beforeAll|afterEach|afterAll)\s*\(/g) || [];
|
|
194
|
+
score.details.has_setup_teardown = setupMethods.length > 0;
|
|
195
|
+
if (score.details.has_setup_teardown) score.value += 2;
|
|
196
|
+
|
|
197
|
+
// Check for logical grouping
|
|
198
|
+
const testBlocks = content.match(/\b(?:it|test)\s*\(/g) || [];
|
|
199
|
+
score.details.test_count = testBlocks.length;
|
|
200
|
+
score.details.tests_per_describe = describeBlocks.length > 0
|
|
201
|
+
? testBlocks.length / describeBlocks.length
|
|
202
|
+
: testBlocks.length;
|
|
203
|
+
|
|
204
|
+
// Good ratio of tests per describe block
|
|
205
|
+
if (score.details.tests_per_describe >= 2 && score.details.tests_per_describe <= 8) {
|
|
206
|
+
score.value += 2;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Check for comments and documentation
|
|
210
|
+
const comments = content.match(/\/\*[\s\S]*?\*\/|\/\/.*$/gm) || [];
|
|
211
|
+
score.details.has_documentation = comments.length > 0;
|
|
212
|
+
if (score.details.has_documentation) score.value += 1;
|
|
213
|
+
|
|
214
|
+
// Consistent indentation
|
|
215
|
+
const lines = content.split('\n');
|
|
216
|
+
const indentationConsistent = this.checkIndentationConsistency(lines);
|
|
217
|
+
score.details.consistent_indentation = indentationConsistent;
|
|
218
|
+
if (indentationConsistent) score.value += 2;
|
|
219
|
+
|
|
220
|
+
return score;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Analyze naming quality of tests
|
|
225
|
+
*/
|
|
226
|
+
analyzeNamingQuality(_content) {
|
|
227
|
+
const score = { value: 0, max: 10, details: {} };
|
|
228
|
+
|
|
229
|
+
// Extract test names
|
|
230
|
+
const testNames = this.extractTestNames(_content);
|
|
231
|
+
score.details.total_tests = testNames.length;
|
|
232
|
+
|
|
233
|
+
if (testNames.length === 0) return score;
|
|
234
|
+
|
|
235
|
+
// Check naming patterns
|
|
236
|
+
let descriptiveNames = 0;
|
|
237
|
+
let consistentPatterns = 0;
|
|
238
|
+
let appropriateLength = 0;
|
|
239
|
+
|
|
240
|
+
const patterns = {
|
|
241
|
+
should_pattern: /should\s+/i,
|
|
242
|
+
can_pattern: /can\s+/i,
|
|
243
|
+
when_pattern: /when\s+/i,
|
|
244
|
+
given_pattern: /given\s+/i,
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
for (const name of testNames) {
|
|
248
|
+
// Descriptive (contains action verbs or clear intent)
|
|
249
|
+
if (name.length > 20 && (name.includes('should') || name.includes('when') || name.includes('given'))) {
|
|
250
|
+
descriptiveNames++;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Appropriate length (not too short, not too long)
|
|
254
|
+
if (name.length >= 15 && name.length <= 80) {
|
|
255
|
+
appropriateLength++;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Consistent patterns
|
|
259
|
+
for (const pattern of Object.values(patterns)) {
|
|
260
|
+
if (pattern.test(name)) {
|
|
261
|
+
consistentPatterns++;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
score.details.descriptive_ratio = descriptiveNames / testNames.length;
|
|
268
|
+
score.details.length_appropriate_ratio = appropriateLength / testNames.length;
|
|
269
|
+
score.details.pattern_consistent_ratio = consistentPatterns / testNames.length;
|
|
270
|
+
|
|
271
|
+
// Scoring
|
|
272
|
+
score.value += score.details.descriptive_ratio * 4;
|
|
273
|
+
score.value += score.details.length_appropriate_ratio * 3;
|
|
274
|
+
score.value += score.details.pattern_consistent_ratio * 3;
|
|
275
|
+
|
|
276
|
+
return score;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Analyze assertion quality
|
|
281
|
+
*/
|
|
282
|
+
analyzeAssertionQuality(_content) {
|
|
283
|
+
const score = { value: 0, max: 10, details: {} };
|
|
284
|
+
|
|
285
|
+
// Count different types of assertions
|
|
286
|
+
const assertions = {
|
|
287
|
+
specific: content.match(/\.toBe\(|\.toEqual\(|\.toStrictEqual\(/g) || [],
|
|
288
|
+
existence: content.match(/\.toBeDefined\(|\.toBeNull\(|\.toBeUndefined\(/g) || [],
|
|
289
|
+
boolean: content.match(/\.toBeTruthy\(|\.toBeFalsy\(|\.toBeTrue\(|\.toBeFalse\(/g) || [],
|
|
290
|
+
numeric: content.match(/\.toBeGreaterThan\(|\.toBeLessThan\(|\.toBeCloseTo\(/g) || [],
|
|
291
|
+
array: content.match(/\.toHaveLength\(|\.toContain\(|\.toContainEqual\(/g) || [],
|
|
292
|
+
object: content.match(/\.toHaveProperty\(|\.toMatchObject\(/g) || [],
|
|
293
|
+
error: content.match(/\.toThrow\(|\.rejects\.|\.resolves\./g) || [],
|
|
294
|
+
custom: content.match(/\.toMatch\(|\.toMatchSnapshot\(/g) || [],
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const totalAssertions = Object.values(assertions).reduce((sum, arr) => sum + arr.length, 0);
|
|
298
|
+
score.details.total_assertions = totalAssertions;
|
|
299
|
+
|
|
300
|
+
if (totalAssertions === 0) return score;
|
|
301
|
+
|
|
302
|
+
// Diversity of assertion types
|
|
303
|
+
const assertionTypes = Object.entries(assertions).filter(([_, arr]) => arr.length > 0).length;
|
|
304
|
+
score.details.assertion_type_diversity = assertionTypes / Object.keys(assertions).length;
|
|
305
|
+
score.value += score.details.assertion_type_diversity * 3;
|
|
306
|
+
|
|
307
|
+
// Specific vs generic assertions ratio
|
|
308
|
+
const specificAssertions = assertions.specific.length + assertions.numeric.length + assertions.object.length;
|
|
309
|
+
const genericAssertions = assertions.existence.length + assertions.boolean.length;
|
|
310
|
+
score.details.specific_ratio = specificAssertions / (specificAssertions + genericAssertions + 1);
|
|
311
|
+
score.value += score.details.specific_ratio * 4;
|
|
312
|
+
|
|
313
|
+
// Error handling coverage
|
|
314
|
+
score.details.error_handling_ratio = assertions.error.length / totalAssertions;
|
|
315
|
+
score.value += Math.min(score.details.error_handling_ratio * 10, 3);
|
|
316
|
+
|
|
317
|
+
return score;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Analyze test coverage breadth
|
|
322
|
+
*/
|
|
323
|
+
analyzeTestCoverageBreadth(_content) {
|
|
324
|
+
const score = { value: 0, max: 10, details: {} };
|
|
325
|
+
|
|
326
|
+
// Identify different test scenarios
|
|
327
|
+
const scenarios = {
|
|
328
|
+
happy_path: content.match(/should\s+.*(?:work|succeed|return|complete)/gi) || [],
|
|
329
|
+
error_cases: content.match(/should\s+.*(?:throw|fail|error|reject)/gi) || [],
|
|
330
|
+
edge_cases: content.match(/should\s+.*(?:empty|null|undefined|zero|negative|boundary|limit)/gi) || [],
|
|
331
|
+
async_cases: content.match(/async\s*\(|await\s+/g) || [],
|
|
332
|
+
integration: content.match(/integration|end.to.end|e2e/gi) || [],
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// Count covered scenario types
|
|
336
|
+
const scenariosCovered = Object.entries(scenarios).filter(([_, matches]) => matches.length > 0).length;
|
|
337
|
+
score.details.scenario_coverage = scenariosCovered / Object.keys(scenarios).length;
|
|
338
|
+
score.value += score.details.scenario_coverage * 5;
|
|
339
|
+
|
|
340
|
+
// Test comprehensiveness
|
|
341
|
+
const testCount = (content.match(/\b(?:it|test)\s*\(/g) || []).length;
|
|
342
|
+
score.details.test_count = testCount;
|
|
343
|
+
|
|
344
|
+
if (testCount >= 10) score.value += 2;
|
|
345
|
+
else if (testCount >= 5) score.value += 1;
|
|
346
|
+
|
|
347
|
+
// Mock usage indicating interaction testing
|
|
348
|
+
const mockUsage = content.match(/\b(?:mock|spy|stub|fake)\b/gi) || [];
|
|
349
|
+
score.details.interaction_testing = mockUsage.length > 0;
|
|
350
|
+
if (score.details.interaction_testing) score.value += 3;
|
|
351
|
+
|
|
352
|
+
return score;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Analyze edge case coverage
|
|
357
|
+
*/
|
|
358
|
+
analyzeEdgeCaseCoverage(_content) {
|
|
359
|
+
const score = { value: 0, max: 10, details: {} };
|
|
360
|
+
|
|
361
|
+
const edgeCasePatterns = {
|
|
362
|
+
null_undefined: /\b(?:null|undefined)\b/gi,
|
|
363
|
+
empty_values: /\b(?:empty|blank|zero|''|""|\[\]|\{\})\b/gi,
|
|
364
|
+
boundary_values: /\b(?:min|max|first|last|boundary|limit)\b/gi,
|
|
365
|
+
negative_cases: /\b(?:negative|invalid|malformed|corrupt)\b/gi,
|
|
366
|
+
large_values: /\b(?:large|huge|maximum|overflow)\b/gi,
|
|
367
|
+
concurrent: /\b(?:concurrent|parallel|race|async)\b/gi,
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
let edgeCasesFound = 0;
|
|
371
|
+
const edgeCaseDetails = {};
|
|
372
|
+
|
|
373
|
+
for (const [category, pattern] of Object.entries(edgeCasePatterns)) {
|
|
374
|
+
const matches = content.match(pattern) || [];
|
|
375
|
+
edgeCaseDetails[category] = matches.length;
|
|
376
|
+
if (matches.length > 0) edgeCasesFound++;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
score.details.edge_case_categories = edgeCasesFound;
|
|
380
|
+
score.details.edge_case_details = edgeCaseDetails;
|
|
381
|
+
score.details.edge_case_ratio = edgeCasesFound / Object.keys(edgeCasePatterns).length;
|
|
382
|
+
|
|
383
|
+
score.value = score.details.edge_case_ratio * 10;
|
|
384
|
+
|
|
385
|
+
return score;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Analyze code clarity and readability
|
|
390
|
+
*/
|
|
391
|
+
analyzeCodeClarity(_content) {
|
|
392
|
+
const score = { value: 0, max: 10, details: {} };
|
|
393
|
+
|
|
394
|
+
const lines = content.split('\n');
|
|
395
|
+
let clearLines = 0;
|
|
396
|
+
let complexLines = 0;
|
|
397
|
+
|
|
398
|
+
for (const line of lines) {
|
|
399
|
+
const trimmed = line.trim();
|
|
400
|
+
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*')) continue;
|
|
401
|
+
|
|
402
|
+
// Check line complexity
|
|
403
|
+
const complexity = this.calculateLineComplexity(trimmed);
|
|
404
|
+
if (complexity < 3) clearLines++;
|
|
405
|
+
else if (complexity > 5) complexLines++;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const totalCodeLines = lines.filter(line => {
|
|
409
|
+
const trimmed = line.trim();
|
|
410
|
+
return trimmed && !trimmed.startsWith('//') && !trimmed.startsWith('/*');
|
|
411
|
+
}).length;
|
|
412
|
+
|
|
413
|
+
score.details.clear_lines_ratio = totalCodeLines > 0 ? clearLines / totalCodeLines : 0;
|
|
414
|
+
score.details.complex_lines_ratio = totalCodeLines > 0 ? complexLines / totalCodeLines : 0;
|
|
415
|
+
|
|
416
|
+
// Variable naming clarity
|
|
417
|
+
const variables = content.match(/(?:let|const|var)\s+(\w+)/g) || [];
|
|
418
|
+
let descriptiveVariables = 0;
|
|
419
|
+
|
|
420
|
+
for (const variable of variables) {
|
|
421
|
+
const name = variable.match(/(?:let|const|var)\s+(\w+)/)[1];
|
|
422
|
+
if (name.length > 3 && !name.match(/^[a-z]$/)) {
|
|
423
|
+
descriptiveVariables++;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
score.details.descriptive_variables_ratio = variables.length > 0
|
|
428
|
+
? descriptiveVariables / variables.length
|
|
429
|
+
: 1;
|
|
430
|
+
|
|
431
|
+
// Scoring
|
|
432
|
+
score.value += score.details.clear_lines_ratio * 4;
|
|
433
|
+
score.value += (1 - score.details.complex_lines_ratio) * 3;
|
|
434
|
+
score.value += score.details.descriptive_variables_ratio * 3;
|
|
435
|
+
|
|
436
|
+
return score;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Analyze maintainability factors
|
|
441
|
+
*/
|
|
442
|
+
analyzeMaintainability(_content) {
|
|
443
|
+
const score = { value: 0, max: 10, details: {} };
|
|
444
|
+
|
|
445
|
+
// DRY principle - look for repeated code patterns
|
|
446
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
447
|
+
const uniqueLines = new Set(lines.map(line => line.trim()));
|
|
448
|
+
score.details.code_duplication_ratio = 1 - (uniqueLines.size / lines.length);
|
|
449
|
+
|
|
450
|
+
// Helper function usage
|
|
451
|
+
const helperFunctions = content.match(/function\s+\w+Helper|const\s+\w+Helper/g) || [];
|
|
452
|
+
score.details.uses_helpers = helperFunctions.length > 0;
|
|
453
|
+
|
|
454
|
+
// Test data management
|
|
455
|
+
const testData = content.match(/const\s+(?:test|mock|fixture|sample)Data/gi) || [];
|
|
456
|
+
score.details.organized_test_data = testData.length > 0;
|
|
457
|
+
|
|
458
|
+
// Magic numbers/strings
|
|
459
|
+
const magicNumbers = content.match(/\b(?!0|1|2|10|100|1000)\d{3,}\b/g) || [];
|
|
460
|
+
const magicStrings = content.match(/'[^']{20,}'|"[^"]{20,}"/g) || [];
|
|
461
|
+
score.details.magic_values_count = magicNumbers.length + magicStrings.length;
|
|
462
|
+
|
|
463
|
+
// Scoring
|
|
464
|
+
score.value += (1 - Math.min(score.details.code_duplication_ratio, 0.5)) * 4;
|
|
465
|
+
score.value += score.details.uses_helpers ? 2 : 0;
|
|
466
|
+
score.value += score.details.organized_test_data ? 2 : 0;
|
|
467
|
+
score.value += Math.max(0, 2 - (score.details.magic_values_count * 0.5));
|
|
468
|
+
|
|
469
|
+
return score;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Analyze test isolation
|
|
474
|
+
*/
|
|
475
|
+
analyzeTestIsolation(_content) {
|
|
476
|
+
const score = { value: 0, max: 10, details: {} };
|
|
477
|
+
|
|
478
|
+
// Check for proper setup/teardown
|
|
479
|
+
const setupTeardown = content.match(/\b(?:beforeEach|afterEach)\s*\(/g) || [];
|
|
480
|
+
score.details.has_isolation_setup = setupTeardown.length > 0;
|
|
481
|
+
if (score.details.has_isolation_setup) score.value += 3;
|
|
482
|
+
|
|
483
|
+
// Check for shared state usage
|
|
484
|
+
const _sharedVariables = content.match(/\b(?:let|var)\s+\w+(?=\s*;|\s*=.*;\s*$)/gm) || [];
|
|
485
|
+
const sharedInDescribe = content.match(/describe[^{]*\{[^}]*(?:let|var)\s+\w+/g) || [];
|
|
486
|
+
score.details.shared_state_usage = sharedInDescribe.length;
|
|
487
|
+
|
|
488
|
+
// Penalty for excessive shared state
|
|
489
|
+
if (score.details.shared_state_usage > 3) score.value -= 2;
|
|
490
|
+
else if (score.details.shared_state_usage === 0) score.value += 2;
|
|
491
|
+
|
|
492
|
+
// Check for test dependencies (tests that depend on order)
|
|
493
|
+
const testOrder = content.includes('beforeAll') && !content.includes('afterAll');
|
|
494
|
+
score.details.potential_order_dependency = testOrder;
|
|
495
|
+
if (!testOrder) score.value += 2;
|
|
496
|
+
|
|
497
|
+
// Mock cleanup
|
|
498
|
+
const mockCleanup = content.match(/\b(?:jest\.clearAllMocks|sinon\.restore|vi\.clearAllMocks)\b/g) || [];
|
|
499
|
+
score.details.mock_cleanup = mockCleanup.length > 0;
|
|
500
|
+
if (score.details.mock_cleanup) score.value += 3;
|
|
501
|
+
|
|
502
|
+
return score;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Analyze test reliability
|
|
507
|
+
*/
|
|
508
|
+
analyzeTestReliability(_content) {
|
|
509
|
+
const score = { value: 0, max: 10, details: {} };
|
|
510
|
+
|
|
511
|
+
// Check for flaky patterns
|
|
512
|
+
const flakyPatterns = {
|
|
513
|
+
timeouts: content.match(/setTimeout|setInterval/g) || [],
|
|
514
|
+
dates: content.match(/new Date\(\)|Date\.now\(\)/g) || [],
|
|
515
|
+
random: content.match(/Math\.random\(\)|Math\.floor.*random/g) || [],
|
|
516
|
+
external_deps: content.match(/fetch\(|axios\.|http\./g) || [],
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
const totalFlakyPatterns = Object.values(flakyPatterns).reduce((sum, arr) => sum + arr.length, 0);
|
|
520
|
+
score.details.flaky_pattern_count = totalFlakyPatterns;
|
|
521
|
+
|
|
522
|
+
// Deterministic test data
|
|
523
|
+
const deterministicData = content.match(/const\s+\w+\s*=\s*\{|const\s+\w+\s*=\s*\[/g) || [];
|
|
524
|
+
score.details.uses_deterministic_data = deterministicData.length > 0;
|
|
525
|
+
|
|
526
|
+
// Proper async handling
|
|
527
|
+
const asyncTests = content.match(/async\s*\(|await\s+/g) || [];
|
|
528
|
+
const promiseHandling = content.match(/\.resolves\.|\.rejects\.|return\s+\w+\(/g) || [];
|
|
529
|
+
score.details.proper_async_handling = asyncTests.length > 0 && promiseHandling.length > 0;
|
|
530
|
+
|
|
531
|
+
// Scoring
|
|
532
|
+
score.value += Math.max(0, 4 - totalFlakyPatterns);
|
|
533
|
+
score.value += score.details.uses_deterministic_data ? 3 : 0;
|
|
534
|
+
score.value += score.details.proper_async_handling ? 3 : 0;
|
|
535
|
+
|
|
536
|
+
return score;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Analyze test performance considerations
|
|
541
|
+
*/
|
|
542
|
+
analyzeTestPerformance(_content) {
|
|
543
|
+
const score = { value: 0, max: 10, details: {} };
|
|
544
|
+
|
|
545
|
+
// Count expensive operations
|
|
546
|
+
const expensiveOps = {
|
|
547
|
+
file_io: content.match(/fs\.|readFile|writeFile/g) || [],
|
|
548
|
+
network: content.match(/fetch\(|axios\.|http\./g) || [],
|
|
549
|
+
heavy_computation: content.match(/for\s*\([^)]*1000|while\s*\(/g) || [],
|
|
550
|
+
large_objects: content.match(/Array\(\d{3,}\)|new Array\(\d{3,}\)/g) || [],
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
const totalExpensiveOps = Object.values(expensiveOps).reduce((sum, arr) => sum + arr.length, 0);
|
|
554
|
+
score.details.expensive_operations = totalExpensiveOps;
|
|
555
|
+
|
|
556
|
+
// Mocking of expensive operations
|
|
557
|
+
const mockedOps = content.match(/mock\w*\s*\(\s*['"`](?:fs|http|fetch)/g) || [];
|
|
558
|
+
score.details.mocked_expensive_ops = mockedOps.length;
|
|
559
|
+
|
|
560
|
+
// Timeout configurations
|
|
561
|
+
const timeouts = content.match(/timeout\s*\(\s*\d+/g) || [];
|
|
562
|
+
score.details.has_timeout_config = timeouts.length > 0;
|
|
563
|
+
|
|
564
|
+
// Scoring
|
|
565
|
+
score.value = 10; // Start with perfect score
|
|
566
|
+
score.value -= Math.min(totalExpensiveOps * 2, 6); // Penalty for expensive ops
|
|
567
|
+
score.value += Math.min(mockedOps.length, 3); // Bonus for mocking
|
|
568
|
+
score.value += score.details.has_timeout_config ? 1 : 0;
|
|
569
|
+
|
|
570
|
+
return Math.max(score.value, 0);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Analyze framework usage quality
|
|
575
|
+
*/
|
|
576
|
+
analyzeFrameworkUsage(_content) {
|
|
577
|
+
const score = { value: 0, max: 10, details: {} };
|
|
578
|
+
|
|
579
|
+
// Detect framework
|
|
580
|
+
const framework = this.detectTestFramework(_content);
|
|
581
|
+
score.details.framework = framework;
|
|
582
|
+
|
|
583
|
+
// Framework-specific best practices
|
|
584
|
+
switch (framework) {
|
|
585
|
+
case 'jest':
|
|
586
|
+
score.value += this.analyzeJestUsage(_content);
|
|
587
|
+
break;
|
|
588
|
+
case 'mocha':
|
|
589
|
+
score.value += this.analyzeMochaUsage(_content);
|
|
590
|
+
break;
|
|
591
|
+
case 'vitest':
|
|
592
|
+
score.value += this.analyzeVitestUsage(_content);
|
|
593
|
+
break;
|
|
594
|
+
default:
|
|
595
|
+
score.value += 5; // Neutral score for unknown framework
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return score;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Analyze mock quality
|
|
603
|
+
*/
|
|
604
|
+
analyzeMockQuality(_content) {
|
|
605
|
+
const score = { value: 0, max: 10, details: {} };
|
|
606
|
+
|
|
607
|
+
// Mock usage patterns
|
|
608
|
+
const mocks = {
|
|
609
|
+
jest_mocks: content.match(/jest\.mock\(|jest\.fn\(\)|mockImplementation/g) || [],
|
|
610
|
+
sinon_mocks: content.match(/sinon\.mock\(|sinon\.spy\(|sinon\.stub\(/g) || [],
|
|
611
|
+
vitest_mocks: content.match(/vi\.mock\(|vi\.fn\(\)|mockImplementation/g) || [],
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
const totalMocks = Object.values(mocks).reduce((sum, arr) => sum + arr.length, 0);
|
|
615
|
+
score.details.total_mocks = totalMocks;
|
|
616
|
+
|
|
617
|
+
if (totalMocks === 0) {
|
|
618
|
+
score.value = 7; // Neutral score for no mocks
|
|
619
|
+
return score;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Mock verification
|
|
623
|
+
const mockVerifications = content.match(/toHaveBeenCalled|toHaveBeenCalledWith|calledWith|called/g) || [];
|
|
624
|
+
score.details.mock_verifications = mockVerifications.length;
|
|
625
|
+
score.details.verification_ratio = mockVerifications.length / totalMocks;
|
|
626
|
+
|
|
627
|
+
// Mock cleanup
|
|
628
|
+
const mockCleanup = content.match(/mockRestore|mockClear|restore\(\)|clearAllMocks/g) || [];
|
|
629
|
+
score.details.mock_cleanup = mockCleanup.length > 0;
|
|
630
|
+
|
|
631
|
+
// Scoring
|
|
632
|
+
score.value += Math.min(score.details.verification_ratio * 6, 6);
|
|
633
|
+
score.value += score.details.mock_cleanup ? 2 : 0;
|
|
634
|
+
score.value += Math.min(totalMocks * 0.5, 2); // Bonus for using mocks appropriately
|
|
635
|
+
|
|
636
|
+
return score;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Helper methods for analysis
|
|
640
|
+
|
|
641
|
+
checkIndentationConsistency(lines) {
|
|
642
|
+
const indentations = lines
|
|
643
|
+
.filter(line => line.trim())
|
|
644
|
+
.map(line => line.match(/^\s*/)[0].length)
|
|
645
|
+
.filter(indent => indent > 0);
|
|
646
|
+
|
|
647
|
+
if (indentations.length < 2) return true;
|
|
648
|
+
|
|
649
|
+
// Check if indentation follows a consistent pattern (2 or 4 spaces)
|
|
650
|
+
const commonIndent = indentations.reduce((acc, indent) => {
|
|
651
|
+
const factor = indent % 2 === 0 ? 2 : (indent % 4 === 0 ? 4 : 1);
|
|
652
|
+
acc[factor] = (acc[factor] || 0) + 1;
|
|
653
|
+
return acc;
|
|
654
|
+
}, {});
|
|
655
|
+
|
|
656
|
+
const mostCommon = Object.keys(commonIndent).reduce((a, b) =>
|
|
657
|
+
commonIndent[a] > commonIndent[b] ? a : b,
|
|
658
|
+
);
|
|
659
|
+
|
|
660
|
+
const consistent = indentations.filter(indent => indent % mostCommon === 0).length;
|
|
661
|
+
return consistent / indentations.length > 0.8;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
extractTestNames(_content) {
|
|
665
|
+
const testMatches = content.match(/(?:it|test)\s*\(\s*['"`]([^'"`]+)['"`]/g) || [];
|
|
666
|
+
return testMatches.map(match => {
|
|
667
|
+
const nameMatch = match.match(/['"`]([^'"`]+)['"`]/);
|
|
668
|
+
return nameMatch ? nameMatch[1] : '';
|
|
669
|
+
}).filter(name => name);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
calculateLineComplexity(line) {
|
|
673
|
+
let complexity = 0;
|
|
674
|
+
|
|
675
|
+
// Nesting indicators
|
|
676
|
+
complexity += (line.match(/[\(\)\[\]\{\}]/g) || []).length * 0.5;
|
|
677
|
+
|
|
678
|
+
// Logical operators
|
|
679
|
+
complexity += (line.match(/&&|\|\||!(?!=)/g) || []).length;
|
|
680
|
+
|
|
681
|
+
// Conditional statements
|
|
682
|
+
complexity += (line.match(/\?|\:|if|else|switch|case/g) || []).length;
|
|
683
|
+
|
|
684
|
+
// Function calls
|
|
685
|
+
complexity += (line.match(/\w+\s*\(/g) || []).length * 0.3;
|
|
686
|
+
|
|
687
|
+
return complexity;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
detectTestFramework(_content) {
|
|
691
|
+
if (content.includes('jest') || content.includes('expect(')) return 'jest';
|
|
692
|
+
if (content.includes('mocha') || content.includes('chai')) return 'mocha';
|
|
693
|
+
if (content.includes('vitest') || content.includes('vi.')) return 'vitest';
|
|
694
|
+
return 'unknown';
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
analyzeJestUsage(_content) {
|
|
698
|
+
let score = 0;
|
|
699
|
+
|
|
700
|
+
// Good Jest practices
|
|
701
|
+
if (content.includes('expect.extend')) score += 1;
|
|
702
|
+
if (content.includes('jest.mock')) score += 1;
|
|
703
|
+
if (content.includes('toMatchSnapshot')) score += 1;
|
|
704
|
+
if (content.includes('toHaveBeenCalled')) score += 1;
|
|
705
|
+
if (content.includes('jest.clearAllMocks')) score += 1;
|
|
706
|
+
|
|
707
|
+
return Math.min(score, 5);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
analyzeMochaUsage(_content) {
|
|
711
|
+
let score = 0;
|
|
712
|
+
|
|
713
|
+
// Good Mocha practices
|
|
714
|
+
if (content.includes('this.timeout')) score += 1;
|
|
715
|
+
if (content.includes('done')) score += 1;
|
|
716
|
+
if (content.includes('chai')) score += 1;
|
|
717
|
+
if (content.includes('sinon')) score += 1;
|
|
718
|
+
|
|
719
|
+
return Math.min(score, 4);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
analyzeVitestUsage(_content) {
|
|
723
|
+
let score = 0;
|
|
724
|
+
|
|
725
|
+
// Good Vitest practices
|
|
726
|
+
if (content.includes('vi.mock')) score += 1;
|
|
727
|
+
if (content.includes('vi.spyOn')) score += 1;
|
|
728
|
+
if (content.includes('vi.clearAllMocks')) score += 1;
|
|
729
|
+
|
|
730
|
+
return Math.min(score, 3);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Calculate overall quality score
|
|
735
|
+
*/
|
|
736
|
+
calculateOverallScore(metrics) {
|
|
737
|
+
const weights = {
|
|
738
|
+
test_organization: 0.15,
|
|
739
|
+
naming_quality: 0.12,
|
|
740
|
+
assertion_quality: 0.15,
|
|
741
|
+
test_coverage_breadth: 0.15,
|
|
742
|
+
edge_case_coverage: 0.10,
|
|
743
|
+
code_clarity: 0.08,
|
|
744
|
+
maintainability: 0.08,
|
|
745
|
+
isolation: 0.07,
|
|
746
|
+
reliability: 0.05,
|
|
747
|
+
performance: 0.03,
|
|
748
|
+
framework_usage: 0.01,
|
|
749
|
+
mock_quality: 0.01,
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
let totalScore = 0;
|
|
753
|
+
let totalWeight = 0;
|
|
754
|
+
|
|
755
|
+
for (const [metric, weight] of Object.entries(weights)) {
|
|
756
|
+
if (metrics[metric]) {
|
|
757
|
+
const normalizedScore = (metrics[metric].value || metrics[metric]) / 10;
|
|
758
|
+
totalScore += normalizedScore * weight * 10;
|
|
759
|
+
totalWeight += weight;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
return totalWeight > 0 ? totalScore / totalWeight : 0;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Determine quality rating from score
|
|
768
|
+
*/
|
|
769
|
+
determineQualityRating(score) {
|
|
770
|
+
if (score >= 9) return 'excellent';
|
|
771
|
+
if (score >= 7.5) return 'good';
|
|
772
|
+
if (score >= 6) return 'fair';
|
|
773
|
+
if (score >= 4) return 'poor';
|
|
774
|
+
return 'very_poor';
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Identify quality issues from metrics
|
|
779
|
+
*/
|
|
780
|
+
identifyQualityIssues(metrics, content) {
|
|
781
|
+
const issues = [];
|
|
782
|
+
|
|
783
|
+
// Organization issues
|
|
784
|
+
if (metrics.test_organization.value < 5) {
|
|
785
|
+
issues.push({
|
|
786
|
+
category: 'organization',
|
|
787
|
+
severity: 'medium',
|
|
788
|
+
message: 'Poor test organization - missing describe blocks or setup/teardown',
|
|
789
|
+
suggestion: 'Use describe blocks to group related tests and add beforeEach/afterEach for setup',
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Naming issues
|
|
794
|
+
if (metrics.naming_quality.value < 5) {
|
|
795
|
+
issues.push({
|
|
796
|
+
category: 'naming',
|
|
797
|
+
severity: 'medium',
|
|
798
|
+
message: 'Poor test naming - tests should clearly describe what they verify',
|
|
799
|
+
suggestion: 'Use descriptive test names that explain the expected behavior',
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Assertion issues
|
|
804
|
+
if (metrics.assertion_quality.value < 6) {
|
|
805
|
+
issues.push({
|
|
806
|
+
category: 'assertions',
|
|
807
|
+
severity: 'high',
|
|
808
|
+
message: 'Weak assertions - too many generic or few specific assertions',
|
|
809
|
+
suggestion: 'Use specific assertions like toEqual() instead of toBeTruthy()',
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Coverage issues
|
|
814
|
+
if (metrics.test_coverage_breadth.value < 5) {
|
|
815
|
+
issues.push({
|
|
816
|
+
category: 'coverage',
|
|
817
|
+
severity: 'high',
|
|
818
|
+
message: 'Limited test coverage - missing error cases or edge cases',
|
|
819
|
+
suggestion: 'Add tests for error conditions, edge cases, and different input scenarios',
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Edge case issues
|
|
824
|
+
if (metrics.edge_case_coverage.value < 4) {
|
|
825
|
+
issues.push({
|
|
826
|
+
category: 'edge_cases',
|
|
827
|
+
severity: 'medium',
|
|
828
|
+
message: 'Insufficient edge case coverage',
|
|
829
|
+
suggestion: 'Add tests for null/undefined values, empty inputs, and boundary conditions',
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Reliability issues
|
|
834
|
+
if (metrics.reliability.value < 6) {
|
|
835
|
+
issues.push({
|
|
836
|
+
category: 'reliability',
|
|
837
|
+
severity: 'high',
|
|
838
|
+
message: 'Tests may be flaky due to timing, randomness, or external dependencies',
|
|
839
|
+
suggestion: 'Mock external dependencies and use deterministic test data',
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
return issues;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Generate improvement recommendations
|
|
848
|
+
*/
|
|
849
|
+
generateRecommendations(metrics, issues) {
|
|
850
|
+
const recommendations = [];
|
|
851
|
+
|
|
852
|
+
// Prioritize recommendations based on impact and severity
|
|
853
|
+
const _highImpactIssues = issues.filter(issue => issue.severity === 'high');
|
|
854
|
+
const _mediumImpactIssues = issues.filter(issue => issue.severity === 'medium');
|
|
855
|
+
|
|
856
|
+
// Add specific recommendations based on metrics
|
|
857
|
+
if (metrics.assertion_quality.value < 7) {
|
|
858
|
+
recommendations.push({
|
|
859
|
+
priority: 'high',
|
|
860
|
+
category: 'assertions',
|
|
861
|
+
action: 'Improve assertion specificity',
|
|
862
|
+
details: 'Replace generic assertions with specific ones that verify exact expected values',
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
if (metrics.test_coverage_breadth.value < 6) {
|
|
867
|
+
recommendations.push({
|
|
868
|
+
priority: 'high',
|
|
869
|
+
category: 'coverage',
|
|
870
|
+
action: 'Expand test scenarios',
|
|
871
|
+
details: 'Add tests for error handling, async operations, and integration scenarios',
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (metrics.maintainability.value < 6) {
|
|
876
|
+
recommendations.push({
|
|
877
|
+
priority: 'medium',
|
|
878
|
+
category: 'maintainability',
|
|
879
|
+
action: 'Reduce code duplication',
|
|
880
|
+
details: 'Extract common test setup into helper functions or use test factories',
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if (metrics.isolation.value < 7) {
|
|
885
|
+
recommendations.push({
|
|
886
|
+
priority: 'medium',
|
|
887
|
+
category: 'isolation',
|
|
888
|
+
action: 'Improve test isolation',
|
|
889
|
+
details: 'Ensure tests can run independently by using proper setup/teardown',
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
return recommendations;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Estimate coverage contribution of the test
|
|
898
|
+
*/
|
|
899
|
+
estimateCoverageContribution(metrics) {
|
|
900
|
+
// Base coverage from test breadth
|
|
901
|
+
let coverage = metrics.test_coverage_breadth.value * 5; // 0-50%
|
|
902
|
+
|
|
903
|
+
// Bonus from assertion quality
|
|
904
|
+
coverage += metrics.assertion_quality.value * 2; // 0-20%
|
|
905
|
+
|
|
906
|
+
// Bonus from edge case coverage
|
|
907
|
+
coverage += metrics.edge_case_coverage.value * 2; // 0-20%
|
|
908
|
+
|
|
909
|
+
// Bonus from mock usage (interaction testing)
|
|
910
|
+
if (metrics.mock_quality.total_mocks > 0) {
|
|
911
|
+
coverage += 10; // 10% bonus
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
return Math.min(coverage, 95); // Cap at 95%
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* Identify common issues across multiple test files
|
|
919
|
+
*/
|
|
920
|
+
identifyCommonIssues(allIssues) {
|
|
921
|
+
const issueCounts = {};
|
|
922
|
+
|
|
923
|
+
for (const issue of allIssues) {
|
|
924
|
+
const key = `${issue.category}-${issue.message}`;
|
|
925
|
+
issueCounts[key] = (issueCounts[key] || 0) + 1;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Return issues that appear in multiple files
|
|
929
|
+
return Object.entries(issueCounts)
|
|
930
|
+
.filter(([_, count]) => count > 1)
|
|
931
|
+
.map(([key, count]) => {
|
|
932
|
+
const [category, message] = key.split('-', 2);
|
|
933
|
+
return { category, message, occurrences: count };
|
|
934
|
+
})
|
|
935
|
+
.sort((a, b) => b.occurrences - a.occurrences);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Generate suite-level recommendations
|
|
940
|
+
*/
|
|
941
|
+
generateSuiteRecommendations(suiteAssessment) {
|
|
942
|
+
const recommendations = [];
|
|
943
|
+
|
|
944
|
+
if (suiteAssessment.overall_suite_score < 6) {
|
|
945
|
+
recommendations.push({
|
|
946
|
+
priority: 'high',
|
|
947
|
+
type: 'overall_quality',
|
|
948
|
+
message: 'Test suite quality is below acceptable standards',
|
|
949
|
+
action: 'Focus on improving test organization, assertions, and coverage breadth',
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
const poorQualityFiles = suiteAssessment.quality_distribution.poor +
|
|
954
|
+
suiteAssessment.quality_distribution.very_poor;
|
|
955
|
+
|
|
956
|
+
if (poorQualityFiles > suiteAssessment.test_files * 0.3) {
|
|
957
|
+
recommendations.push({
|
|
958
|
+
priority: 'high',
|
|
959
|
+
type: 'poor_quality_files',
|
|
960
|
+
message: `${poorQualityFiles} files have poor test quality`,
|
|
961
|
+
action: 'Prioritize refactoring tests with quality ratings of "poor" or "very_poor"',
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
if (suiteAssessment.common_issues.length > 3) {
|
|
966
|
+
recommendations.push({
|
|
967
|
+
priority: 'medium',
|
|
968
|
+
type: 'systematic_issues',
|
|
969
|
+
message: 'Multiple files share common quality issues',
|
|
970
|
+
action: 'Address systematic issues across the test suite with consistent patterns',
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
return recommendations;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// Data persistence methods
|
|
978
|
+
|
|
979
|
+
async loadQualityHistory() {
|
|
980
|
+
try {
|
|
981
|
+
const historyFile = path.join(this.qualityReportsDir, 'quality-history.json');
|
|
982
|
+
const exists = await fs.access(historyFile).then(() => true).catch(() => false);
|
|
983
|
+
|
|
984
|
+
if (exists) {
|
|
985
|
+
const data = JSON.parse(await fs.readFile(historyFile, 'utf-8'));
|
|
986
|
+
this.qualityHistory = data.quality_history || [];
|
|
987
|
+
}
|
|
988
|
+
} catch (_error) {
|
|
989
|
+
// No existing data, start fresh
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
async saveSuiteAssessment(suiteAssessment) {
|
|
994
|
+
try {
|
|
995
|
+
// Save individual suite assessment
|
|
996
|
+
const assessmentId = `suite-${Date.now()}`;
|
|
997
|
+
const assessmentFile = path.join(this.qualityReportsDir, `${assessmentId}.json`);
|
|
998
|
+
await fs.writeFile(assessmentFile, JSON.stringify(suiteAssessment, null, 2));
|
|
999
|
+
|
|
1000
|
+
// Update quality history
|
|
1001
|
+
this.qualityHistory.push({
|
|
1002
|
+
assessment_id: assessmentId,
|
|
1003
|
+
timestamp: suiteAssessment.assessed_at,
|
|
1004
|
+
overall_score: suiteAssessment.overall_suite_score,
|
|
1005
|
+
test_files: suiteAssessment.test_files,
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
// Save updated history
|
|
1009
|
+
const historyFile = path.join(this.qualityReportsDir, 'quality-history.json');
|
|
1010
|
+
const historyData = {
|
|
1011
|
+
last_updated: new Date().toISOString(),
|
|
1012
|
+
quality_history: this.qualityHistory.slice(-20), // Keep last 20 assessments
|
|
1013
|
+
};
|
|
1014
|
+
await fs.writeFile(historyFile, JSON.stringify(historyData, null, 2));
|
|
1015
|
+
|
|
1016
|
+
console.log(chalk.gray(`Quality assessment saved: ${assessmentFile}`));
|
|
1017
|
+
|
|
1018
|
+
} catch (_error) {
|
|
1019
|
+
console.warn(chalk.yellow(`Failed to save quality assessment: ${error.message}`));
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* Initialize quality standards configuration
|
|
1025
|
+
*/
|
|
1026
|
+
initializeQualityStandards() {
|
|
1027
|
+
return {
|
|
1028
|
+
minimum_scores: {
|
|
1029
|
+
overall: 6.0,
|
|
1030
|
+
test_organization: 5.0,
|
|
1031
|
+
naming_quality: 5.0,
|
|
1032
|
+
assertion_quality: 6.0,
|
|
1033
|
+
test_coverage_breadth: 5.0,
|
|
1034
|
+
reliability: 6.0,
|
|
1035
|
+
},
|
|
1036
|
+
target_scores: {
|
|
1037
|
+
overall: 8.5,
|
|
1038
|
+
test_organization: 8.0,
|
|
1039
|
+
naming_quality: 7.5,
|
|
1040
|
+
assertion_quality: 8.5,
|
|
1041
|
+
test_coverage_breadth: 8.0,
|
|
1042
|
+
reliability: 8.5,
|
|
1043
|
+
},
|
|
1044
|
+
quality_thresholds: {
|
|
1045
|
+
excellent: 9.0,
|
|
1046
|
+
good: 7.5,
|
|
1047
|
+
fair: 6.0,
|
|
1048
|
+
poor: 4.0,
|
|
1049
|
+
},
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Get quality trends over time
|
|
1055
|
+
*/
|
|
1056
|
+
getQualityTrends() {
|
|
1057
|
+
if (this.qualityHistory.length < 2) {
|
|
1058
|
+
return { trend: 'insufficient_data', message: 'Need at least 2 assessments for trend calculation' };
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
const recent = this.qualityHistory.slice(-5); // Last 5 assessments
|
|
1062
|
+
const scores = recent.map(h => h.overall_score);
|
|
1063
|
+
|
|
1064
|
+
const firstScore = scores[0];
|
|
1065
|
+
const lastScore = scores[scores.length - 1];
|
|
1066
|
+
const difference = lastScore - firstScore;
|
|
1067
|
+
|
|
1068
|
+
let trend = 'stable';
|
|
1069
|
+
if (difference > 0.5) trend = 'improving';
|
|
1070
|
+
else if (difference < -0.5) trend = 'declining';
|
|
1071
|
+
|
|
1072
|
+
return {
|
|
1073
|
+
trend,
|
|
1074
|
+
difference: difference.toFixed(1),
|
|
1075
|
+
current_score: lastScore,
|
|
1076
|
+
assessment_count: recent.length,
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
module.exports = TestQualityAssessment;
|