maintainability-agent 2.4.1__tar.gz → 2.5.0__tar.gz
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.
- {maintainability_agent-2.4.1/src/maintainability_agent.egg-info → maintainability_agent-2.5.0}/PKG-INFO +2 -2
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/README.md +1 -1
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/pyproject.toml +1 -1
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_agent.egg-info/SOURCES.txt +2 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/__init__.py +1 -1
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_first_run.py +54 -2
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_mcp_setup.py +18 -4
- maintainability_agent-2.5.0/src/maintainability_audit/_test_commands.py +251 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/config.py +1 -1
- maintainability_agent-2.5.0/tests/test_test_commands.py +348 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/LICENSE +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/setup.cfg +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/__main__.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_adapters.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_analysis.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_aspects.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_assets/standard.md +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_attestation.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_backfill.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_bands.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_built_ins.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_calibration.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_catalog.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_charts.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_cognitive.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_config_defaults.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_conformance.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_corroborate.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_coverage_notes.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_derive.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_discovery.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_documents.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_economics.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_economics_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_environment.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_evidence_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_finding_match.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_formula.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_gates.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_generic.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_grant_ledger.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_history_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_hotspots.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_html_report_sections.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_html_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_identity.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_markdown_sections.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_masking.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_mcp_audit.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_mcp_gate.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_mcp_grants.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_mcp_resources.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_metric_adapters.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_metrics_types.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_pillars.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_practice.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_pressures.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_c.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_core.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_fortran.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_java.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_js.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ranges_swift.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_ratchet.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_recurrence.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_runner.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_safe_write.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_scan_history.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_scan_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_second_source.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_selection.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_semantic.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_semantic_policy.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_semantic_ts.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_semantic_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_setup_errors.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_setup_persist.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_skill_install.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_stored_grants.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_tdd_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_test_execution.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_test_pairing.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_tokens.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_tool_adapters.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_trends.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_user_config.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_verdict_adapters.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_verification.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_work_order.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_work_order_view.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_work_order_weights.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_xml.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/baseline.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/cli.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/deadcode.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/duplication.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/evidence.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/git_tools.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/history.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/idioms.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/instructions.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/mcp_server.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/metrics.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/prompts.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/renderers.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/report.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/sarif.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/scoring.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/similarity.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/source.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_acquisition_trust.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_adapter_docs.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_adapter_recordings.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_adapters.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_added_lines.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analysis_coverage.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analysis_execution.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_bridge.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_config_isolation.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_estimate_claims.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_pinning.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_primary_estimate.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_provenance.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_scoring_path.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_spread_range.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_analyzer_xml_bounds.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_annotations_match_behaviour.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_anticipated_refusals.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_architecture.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_artifact_write_route_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_aspect_coverage.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_asset_snapshot_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_attestation.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_audit_components.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_authorization_freshness.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_authorship_gates.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_backfill.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_band_concealment_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_band_concealment_p3.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_band_pressures.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_bands.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_body_or_signature_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_c_declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_calibration_corpus.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_calibration_drift.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_calibration_tooling.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_catalog_selection.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_catalog_tier_promise.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_chat_primary_docs.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_checkstyle_adapter.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_checkstyle_catalog.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_ci_history_recipe.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_claimed_languages.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_cli.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_clone_group_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_cognitive_complexity.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_cohort_statistics.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_concealment_properties.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_config_shape.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_consent_and_grant.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_consumer_migration.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_contract_claims.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_corroborate.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_coverage_by_language.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_cpp_declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_csharp_declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_d15_composition.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_d15_goal_directed.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_dead_code.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_declaration_edge_cases.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_declaration_grading.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_declaration_ranges.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_declaration_source.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_declared_authorship.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_declared_imports.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_derivation_mix.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_determinism.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_dimension_ratchet.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_direct_runner_availability_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_discovery.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_doc_claims.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_docs_links.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_economic_context.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_empty_output_not_clean.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_environment_work_order.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_evidence_invariants.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_evidence_normalization.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_evidence_properties.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_exclusion_dialects.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_falsifier_standard.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_file_list_cap_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_finding_identity.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_first_run_elicitation.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_first_run_prompt.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_first_run_reelicitation.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_fix_breadth_window.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_fixed_form_fortran.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_format_ask.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_fortran_declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_fortran_metrics.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_fortran_practice.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_git_argv.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_git_read_only.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_git_readonly_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_grant_only_user_tier.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_history.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_history_boundary.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_history_manifest.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_history_schema2.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_history_window.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_hostile_prompt.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_html_executive.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_html_section_parity_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_identity_docs.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_identity_resolution.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_idiom_divergence.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_installed_wheel_runtime.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_instruction_targets.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_java_range_guard.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_java_ranges.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_java_scored.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_java_wiring.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_js_complexity_operators.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_js_declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_language_coverage.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_mcp_baseline_payload.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_mcp_history.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_mcp_server.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_migration_1_0.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_near_duplicates.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_network_disclosure.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_pattern_budget.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_phase6_claims.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_pillars_and_practice.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_platform_claim.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_pmd_adapter.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_pmd_audit_closures.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_pool_runs_by_config.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_population_floors.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_practice_nested_gates_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_presentation_refusals.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_promises.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_prompt_escalation_once.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_prompt_honesty.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_prompt_location_escalation_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_prove_falsifiers.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_python_declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_read_boundary.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_readme_claims.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_recurrence.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_release_plan.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_release_plan_status.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_report_remedy_copy.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_roles_recorded.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_root_grants.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_runner.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_sarif.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_scan_history.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_scan_scope.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_scanning.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_schema_fidelity.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_scope_conformance.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_scoring_calibration.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_semantic_policy.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_setup_gate_completeness.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_setup_gate_independent_contract.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_setup_precondition.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_skill_install.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_source_index.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_spotbugs_adapter.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_spotbugs_catalog.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_stage8_contract.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_suite_isolation.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_swift_declarations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_tdd_structure.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_test_execution_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_three_presentations.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_trends.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_type_fields_not_functions_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_uat_falsifiers.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_unread_code.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_user_config_tier.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_verification_audit_closures.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_verified_grade.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_version_claim.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_wheel_contents.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_work_order.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_work_order_items.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_work_order_selection.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_workflow_supply_chain.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_write_boundary.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_write_route_class.py +0 -0
- {maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/tests/test_written_record.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -44,7 +44,7 @@ Dynamic: license-file
|
|
|
44
44
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
45
45
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
46
46
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
47
|
-
Version **2.
|
|
47
|
+
Version **2.5.0**.
|
|
48
48
|
|
|
49
49
|
**Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
|
|
50
50
|
*and* fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
6
6
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
7
7
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
8
|
-
Version **2.
|
|
8
|
+
Version **2.5.0**.
|
|
9
9
|
|
|
10
10
|
**Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
|
|
11
11
|
*and* fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "maintainability-agent"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.5.0"
|
|
8
8
|
description = "Maintainability gate and AI remediation prompt generator for CI."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# 3.11, not 3.10. `_discovery`, `_pillars` and `_runner` all import
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maintainability-agent
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: Maintainability gate and AI remediation prompt generator for CI.
|
|
5
5
|
Author: Marshall Guillory
|
|
6
6
|
License: MIT
|
|
@@ -44,7 +44,7 @@ Dynamic: license-file
|
|
|
44
44
|
**A deterministic, offline maintainability audit whose output is a _bounded
|
|
45
45
|
work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
|
|
46
46
|
says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
|
|
47
|
-
Version **2.
|
|
47
|
+
Version **2.5.0**.
|
|
48
48
|
|
|
49
49
|
**Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
|
|
50
50
|
*and* fixed-form), and the JS/TS family — each by a scanner written for it, and
|
|
@@ -82,6 +82,7 @@ src/maintainability_audit/_setup_persist.py
|
|
|
82
82
|
src/maintainability_audit/_skill_install.py
|
|
83
83
|
src/maintainability_audit/_stored_grants.py
|
|
84
84
|
src/maintainability_audit/_tdd_view.py
|
|
85
|
+
src/maintainability_audit/_test_commands.py
|
|
85
86
|
src/maintainability_audit/_test_execution.py
|
|
86
87
|
src/maintainability_audit/_test_pairing.py
|
|
87
88
|
src/maintainability_audit/_tokens.py
|
|
@@ -293,6 +294,7 @@ tests/test_stage8_contract.py
|
|
|
293
294
|
tests/test_suite_isolation.py
|
|
294
295
|
tests/test_swift_declarations.py
|
|
295
296
|
tests/test_tdd_structure.py
|
|
297
|
+
tests/test_test_commands.py
|
|
296
298
|
tests/test_test_execution_class.py
|
|
297
299
|
tests/test_three_presentations.py
|
|
298
300
|
tests/test_trends.py
|
{maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_first_run.py
RENAMED
|
@@ -22,6 +22,7 @@ sat in ``DEFAULTS``, documented as reserved, read by nothing, from
|
|
|
22
22
|
"""
|
|
23
23
|
from __future__ import annotations
|
|
24
24
|
|
|
25
|
+
import contextlib
|
|
25
26
|
import json
|
|
26
27
|
import sys
|
|
27
28
|
from pathlib import Path
|
|
@@ -190,11 +191,53 @@ def maybe_prompt_economics(root: Path, config: dict) -> None:
|
|
|
190
191
|
print(f"Wrote {written}")
|
|
191
192
|
|
|
192
193
|
|
|
194
|
+
def _input_with_default(prompt: str, default: str) -> str:
|
|
195
|
+
"""`input()` with the line pre-filled, where the terminal allows it.
|
|
196
|
+
|
|
197
|
+
`readline` is what makes the default *editable* rather than merely
|
|
198
|
+
described: the text is inserted into the line buffer, so Enter submits
|
|
199
|
+
it, backspace edits it, and clearing it returns the empty string that
|
|
200
|
+
has always meant "cancel". Without that, a pre-filled default and a
|
|
201
|
+
blank-means-cancel rule cannot both be true on one keystroke.
|
|
202
|
+
|
|
203
|
+
Absent or unusable `readline` — Windows without pyreadline, a terminal
|
|
204
|
+
that refuses the hook — falls back to a plain `input()`. The default is
|
|
205
|
+
still named in the prompt text, so the operator loses the keystroke and
|
|
206
|
+
not the information. Never let this be the thing that fails a setup.
|
|
207
|
+
"""
|
|
208
|
+
if not default:
|
|
209
|
+
return input(prompt)
|
|
210
|
+
try:
|
|
211
|
+
import readline
|
|
212
|
+
except ImportError:
|
|
213
|
+
return input(prompt)
|
|
214
|
+
|
|
215
|
+
def _prefill() -> None:
|
|
216
|
+
readline.insert_text(default)
|
|
217
|
+
readline.redisplay()
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
readline.set_startup_hook(_prefill)
|
|
221
|
+
return input(prompt)
|
|
222
|
+
except Exception: # noqa: BLE001 - a cosmetic hook must not fail setup
|
|
223
|
+
return input(prompt)
|
|
224
|
+
finally:
|
|
225
|
+
# Global state: a hook left installed would pre-type this command
|
|
226
|
+
# into whatever the session asks next.
|
|
227
|
+
with contextlib.suppress(Exception):
|
|
228
|
+
readline.set_startup_hook()
|
|
229
|
+
|
|
230
|
+
|
|
193
231
|
def maybe_prompt_test_command(root: Path, config: dict) -> None:
|
|
194
232
|
"""Ask the opted-in operator for the test command, once -- the CLI half
|
|
195
233
|
of the Class 5 second stage, mirroring the labor-rate ask. Fires only at
|
|
196
234
|
a TTY, only when the suite was opted into and no command is stored, and
|
|
197
235
|
a blank answer cancels the opt-in. Nothing runs until a command exists.
|
|
236
|
+
|
|
237
|
+
Where the tree's manifests name a runner, the line is **pre-filled**
|
|
238
|
+
with that command rather than merely mentioning it, so this surface and
|
|
239
|
+
the MCP one carry the same default in the same field: Enter accepts,
|
|
240
|
+
editing replaces, and clearing the line cancels exactly as before.
|
|
198
241
|
"""
|
|
199
242
|
import shlex
|
|
200
243
|
|
|
@@ -209,10 +252,19 @@ def maybe_prompt_test_command(root: Path, config: dict) -> None:
|
|
|
209
252
|
if (config.get("expected_commands") or {}).get("test"):
|
|
210
253
|
return
|
|
211
254
|
|
|
212
|
-
|
|
255
|
+
from ._test_commands import suggested_test_command
|
|
256
|
+
|
|
257
|
+
suggested = suggested_test_command(root)
|
|
258
|
+
detected = " ".join(suggested.command) if suggested is not None else ""
|
|
259
|
+
prompt = (
|
|
260
|
+
f"Detected `{detected}` from {suggested.evidence}. The command that "
|
|
261
|
+
"runs this repository's test suite (Enter to accept, clear the line "
|
|
262
|
+
"to cancel running it): "
|
|
263
|
+
if suggested is not None else
|
|
213
264
|
"The command that runs this repository's test suite, e.g. `pytest` "
|
|
214
265
|
"(Enter to cancel running it): "
|
|
215
|
-
)
|
|
266
|
+
)
|
|
267
|
+
answer = _input_with_default(prompt, detected).strip()
|
|
216
268
|
|
|
217
269
|
from ._safe_write import write_bounded
|
|
218
270
|
|
{maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/_mcp_setup.py
RENAMED
|
@@ -226,21 +226,35 @@ def run_tests_pending(root: Path) -> bool:
|
|
|
226
226
|
and "test_execution" not in stored)
|
|
227
227
|
|
|
228
228
|
|
|
229
|
-
def test_command_questions() -> list[dict[str, Any]]:
|
|
229
|
+
def test_command_questions(root: Path | None = None) -> list[dict[str, Any]]:
|
|
230
230
|
"""The one command, asked only of someone who opted into running it.
|
|
231
231
|
|
|
232
232
|
A free-text answer (empty options), the second stage of the opt-in the
|
|
233
233
|
way the labor rates are the second stage of the economic scenario.
|
|
234
|
+
|
|
235
|
+
When the tree's manifests name a runner, that command is the question's
|
|
236
|
+
`default` and the prompt says which file proposed it. It is a default,
|
|
237
|
+
not a decision: the operator's answer is what gets stored, and blank
|
|
238
|
+
still cancels the opt-in — a pre-filled field the operator clears is
|
|
239
|
+
the same cancellation it always was.
|
|
234
240
|
"""
|
|
241
|
+
from ._test_commands import suggested_test_command
|
|
242
|
+
|
|
243
|
+
suggested = suggested_test_command(root) if root is not None else None
|
|
244
|
+
detected = " ".join(suggested.command) if suggested is not None else ""
|
|
245
|
+
because = (
|
|
246
|
+
f"Detected `{detected}` from {suggested.evidence}. "
|
|
247
|
+
if suggested is not None else ""
|
|
248
|
+
)
|
|
235
249
|
return [{
|
|
236
250
|
"name": "test_command",
|
|
237
251
|
"prompt": (
|
|
238
|
-
"The command that runs this repository's test suite "
|
|
252
|
+
f"{because}The command that runs this repository's test suite "
|
|
239
253
|
"(e.g. `pytest`, `npm test`). It runs in the repository root, "
|
|
240
254
|
"and leaving it blank cancels the opt-in."
|
|
241
255
|
),
|
|
242
256
|
"options": [],
|
|
243
|
-
"default":
|
|
257
|
+
"default": detected,
|
|
244
258
|
}]
|
|
245
259
|
|
|
246
260
|
|
|
@@ -334,7 +348,7 @@ def setup_schema(root: Path | None = None):
|
|
|
334
348
|
if root is not None and economics_bounds_pending(root):
|
|
335
349
|
return _schema_for(economics_bound_questions())
|
|
336
350
|
if root is not None and test_command_pending(root):
|
|
337
|
-
return _schema_for(test_command_questions())
|
|
351
|
+
return _schema_for(test_command_questions(root))
|
|
338
352
|
return _schema_for(setup_questions(load_config(None)))
|
|
339
353
|
|
|
340
354
|
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"""The command that runs a repository's tests, read from its build files.
|
|
2
|
+
|
|
3
|
+
`expected_commands.test` has always been hand-typed. The prompt's example
|
|
4
|
+
was `pytest`, so on every non-Python tree the operator was asked a question
|
|
5
|
+
the repository could already answer: a `Package.swift` beside a `Tests/`
|
|
6
|
+
directory says `swift test` as plainly as a manifest says anything.
|
|
7
|
+
|
|
8
|
+
**This suggests; it never decides.** The `require_test_command` hard gate
|
|
9
|
+
reads "a *documented* test command", and a command this module wrote into
|
|
10
|
+
the config unasked would satisfy that gate while nobody had documented
|
|
11
|
+
anything — a gate passing on evidence it invented. So detection reaches
|
|
12
|
+
exactly one place: the default offered in the setup question, on every
|
|
13
|
+
surface. A human still answers it, and their answer is what gets stored.
|
|
14
|
+
|
|
15
|
+
**Every rule is anchored to a manifest**, never to a directory name alone
|
|
16
|
+
or a file extension. `go.mod` means the tree is a Go module; a stray
|
|
17
|
+
`.go` file means someone vendored something. The manifest is recorded as
|
|
18
|
+
`evidence` and travels with the suggestion, so the question can say *why*
|
|
19
|
+
it is proposing this and the operator can disagree with a reason.
|
|
20
|
+
|
|
21
|
+
**What it refuses to guess**, because a command that cannot run is worse
|
|
22
|
+
than no suggestion:
|
|
23
|
+
|
|
24
|
+
- **An Xcode project with no `Package.swift`.** `xcodebuild test` needs
|
|
25
|
+
`-scheme`, and usually `-destination` as well; neither is derivable from
|
|
26
|
+
the tree with any confidence. The roadmap named `xcodebuild test` as a
|
|
27
|
+
target and it is deliberately not shipped: bare `xcodebuild test` fails
|
|
28
|
+
on every project it would be offered for, and a suggestion that always
|
|
29
|
+
fails teaches the operator to ignore suggestions.
|
|
30
|
+
- **`npm test` where `scripts.test` is the placeholder** npm generates
|
|
31
|
+
(`echo "Error: no test specified" && exit 1`). It is a script that
|
|
32
|
+
exists in order not to be a test command.
|
|
33
|
+
- **A package with no tests.** `swift test` on a package with no test
|
|
34
|
+
target is an error, so `Tests/` or a `.testTarget` in the manifest is
|
|
35
|
+
required, not just `Package.swift`.
|
|
36
|
+
|
|
37
|
+
Nothing here runs anything. Detection is file reading, and whether the
|
|
38
|
+
suite may be *executed* remains the Class 5 opt-in, default off.
|
|
39
|
+
"""
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
import json
|
|
43
|
+
import re
|
|
44
|
+
from dataclasses import dataclass
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
|
|
47
|
+
#: Bounded like `_practice._read`: a manifest is small, and a multi-megabyte
|
|
48
|
+
#: `package.json` is not a reason to read a multi-megabyte file.
|
|
49
|
+
_READ_LIMIT = 200_000
|
|
50
|
+
|
|
51
|
+
#: The npm placeholder, written by `npm init` so that `scripts.test` exists.
|
|
52
|
+
#: Matching it loosely on purpose — the wording has changed across npm
|
|
53
|
+
#: versions and the shape has not.
|
|
54
|
+
_NPM_PLACEHOLDER = re.compile(r"no test specified", re.IGNORECASE)
|
|
55
|
+
|
|
56
|
+
_CMAKE_TESTS = re.compile(r"^\s*(?:enable_testing\s*\(|add_test\s*\()", re.MULTILINE)
|
|
57
|
+
_SWIFT_TEST_TARGET = re.compile(r"\.testTarget\s*\(")
|
|
58
|
+
_PYTEST_DECLARED = re.compile(
|
|
59
|
+
r"^\s*\[(?:tool\.pytest[.\]]|pytest\]|tool:pytest\])", re.MULTILINE
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True)
|
|
64
|
+
class TestCommand:
|
|
65
|
+
"""A suggested command and the file that suggested it."""
|
|
66
|
+
|
|
67
|
+
command: list[str]
|
|
68
|
+
evidence: str
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _read(path: Path) -> str:
|
|
72
|
+
try:
|
|
73
|
+
with path.open("r", encoding="utf-8", errors="replace") as handle:
|
|
74
|
+
return handle.read(_READ_LIMIT)
|
|
75
|
+
except OSError:
|
|
76
|
+
return ""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _swift(root: Path) -> TestCommand | None:
|
|
80
|
+
"""SwiftPM, and only where a test target exists to run.
|
|
81
|
+
|
|
82
|
+
`swift test` on a package without one exits non-zero, so `Package.swift`
|
|
83
|
+
alone is not enough. Either spelling of "there are tests here" counts:
|
|
84
|
+
the conventional `Tests/` directory, or a `.testTarget` the manifest
|
|
85
|
+
declares somewhere else.
|
|
86
|
+
"""
|
|
87
|
+
manifest = root / "Package.swift"
|
|
88
|
+
if not manifest.is_file():
|
|
89
|
+
return None
|
|
90
|
+
has_tests = (root / "Tests").is_dir() or bool(
|
|
91
|
+
_SWIFT_TEST_TARGET.search(_read(manifest))
|
|
92
|
+
)
|
|
93
|
+
return TestCommand(["swift", "test"], "Package.swift") if has_tests else None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _fortran(root: Path) -> TestCommand | None:
|
|
97
|
+
"""`fpm.toml` is the Fortran Package Manager's manifest.
|
|
98
|
+
|
|
99
|
+
`_practice` already reads this file for fortitude's lint settings, so
|
|
100
|
+
the tree shape is one this tool understood before it could name the
|
|
101
|
+
command that tests it.
|
|
102
|
+
"""
|
|
103
|
+
return (
|
|
104
|
+
TestCommand(["fpm", "test"], "fpm.toml")
|
|
105
|
+
if (root / "fpm.toml").is_file()
|
|
106
|
+
else None
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _rust(root: Path) -> TestCommand | None:
|
|
111
|
+
return (
|
|
112
|
+
TestCommand(["cargo", "test"], "Cargo.toml")
|
|
113
|
+
if (root / "Cargo.toml").is_file()
|
|
114
|
+
else None
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _go(root: Path) -> TestCommand | None:
|
|
119
|
+
"""`./...` because a bare `go test` tests only the root package.
|
|
120
|
+
|
|
121
|
+
The difference matters in a module with any structure at all: the bare
|
|
122
|
+
form silently tests almost nothing and exits zero, which is the worst
|
|
123
|
+
available outcome for a command whose job is to fail.
|
|
124
|
+
"""
|
|
125
|
+
return (
|
|
126
|
+
TestCommand(["go", "test", "./..."], "go.mod")
|
|
127
|
+
if (root / "go.mod").is_file()
|
|
128
|
+
else None
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _cmake(root: Path) -> TestCommand | None:
|
|
133
|
+
"""`ctest`, but only where the project actually registered tests.
|
|
134
|
+
|
|
135
|
+
A `CMakeLists.txt` without `enable_testing()` or `add_test()` builds
|
|
136
|
+
something that has no tests to run, and `ctest` there reports "No tests
|
|
137
|
+
were found" and exits non-zero.
|
|
138
|
+
"""
|
|
139
|
+
manifest = root / "CMakeLists.txt"
|
|
140
|
+
if not manifest.is_file() or not _CMAKE_TESTS.search(_read(manifest)):
|
|
141
|
+
return None
|
|
142
|
+
return TestCommand(["ctest"], "CMakeLists.txt")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _node(root: Path) -> TestCommand | None:
|
|
146
|
+
"""`npm test`, unless the script is npm's own placeholder."""
|
|
147
|
+
manifest = root / "package.json"
|
|
148
|
+
if not manifest.is_file():
|
|
149
|
+
return None
|
|
150
|
+
try:
|
|
151
|
+
parsed = json.loads(_read(manifest))
|
|
152
|
+
except (json.JSONDecodeError, ValueError):
|
|
153
|
+
return None
|
|
154
|
+
if not isinstance(parsed, dict):
|
|
155
|
+
return None
|
|
156
|
+
script = (parsed.get("scripts") or {}).get("test")
|
|
157
|
+
if not isinstance(script, str) or not script.strip():
|
|
158
|
+
return None
|
|
159
|
+
if _NPM_PLACEHOLDER.search(script):
|
|
160
|
+
return None
|
|
161
|
+
return TestCommand(["npm", "test"], "package.json")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _python(root: Path) -> TestCommand | None:
|
|
165
|
+
"""pytest where a file declares it, not where a `tests/` folder exists.
|
|
166
|
+
|
|
167
|
+
A directory named `tests` says nothing about the runner. A
|
|
168
|
+
`[tool.pytest.ini_options]`, `[pytest]` or `[tool:pytest]` section is a
|
|
169
|
+
repository stating which runner it uses, which is the only thing worth
|
|
170
|
+
reading it for.
|
|
171
|
+
"""
|
|
172
|
+
if (root / "pytest.ini").is_file():
|
|
173
|
+
return TestCommand(["pytest"], "pytest.ini")
|
|
174
|
+
for name in ("pyproject.toml", "tox.ini", "setup.cfg"):
|
|
175
|
+
manifest = root / name
|
|
176
|
+
if manifest.is_file() and _PYTEST_DECLARED.search(_read(manifest)):
|
|
177
|
+
return TestCommand(["pytest"], name)
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _maven(root: Path) -> TestCommand | None:
|
|
182
|
+
return (
|
|
183
|
+
TestCommand(["mvn", "test"], "pom.xml")
|
|
184
|
+
if (root / "pom.xml").is_file()
|
|
185
|
+
else None
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _gradle(root: Path) -> TestCommand | None:
|
|
190
|
+
"""The wrapper when the repository ships one, because that is the point.
|
|
191
|
+
|
|
192
|
+
A checked-in `gradlew` pins the Gradle version the build expects;
|
|
193
|
+
calling bare `gradle` uses whatever the machine happens to have, which
|
|
194
|
+
is the thing the wrapper exists to prevent.
|
|
195
|
+
"""
|
|
196
|
+
for name in ("build.gradle", "build.gradle.kts"):
|
|
197
|
+
if (root / name).is_file():
|
|
198
|
+
wrapper = (root / "gradlew").is_file()
|
|
199
|
+
return TestCommand(["./gradlew" if wrapper else "gradle", "test"], name)
|
|
200
|
+
return None
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _dotnet(root: Path) -> TestCommand | None:
|
|
204
|
+
for pattern in ("*.sln", "*.slnx"):
|
|
205
|
+
found = sorted(root.glob(pattern))
|
|
206
|
+
if found:
|
|
207
|
+
return TestCommand(["dotnet", "test"], found[0].name)
|
|
208
|
+
projects = sorted(root.glob("*.csproj"))
|
|
209
|
+
return TestCommand(["dotnet", "test"], projects[0].name) if projects else None
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
#: Order is the tie-break and is therefore part of the contract: a tree with
|
|
213
|
+
#: both a `Package.swift` and a `package.json` gets one answer, the same one
|
|
214
|
+
#: every time (P1). Ecosystems whose manifest is unambiguous come first;
|
|
215
|
+
#: `package.json` is late because it is the file most often present in a
|
|
216
|
+
#: repository whose real subject is something else.
|
|
217
|
+
_DETECTORS = (
|
|
218
|
+
_swift,
|
|
219
|
+
_fortran,
|
|
220
|
+
_rust,
|
|
221
|
+
_go,
|
|
222
|
+
_cmake,
|
|
223
|
+
_maven,
|
|
224
|
+
_gradle,
|
|
225
|
+
_dotnet,
|
|
226
|
+
_python,
|
|
227
|
+
_node,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def detect_test_commands(root: Path) -> list[TestCommand]:
|
|
232
|
+
"""Every command this tree's manifests support, in a fixed order.
|
|
233
|
+
|
|
234
|
+
Plural because a repository may honestly have more than one — a Swift
|
|
235
|
+
package with a Node-based docs site is not a malformed tree — and
|
|
236
|
+
reporting only the first would hide that from anyone deciding.
|
|
237
|
+
"""
|
|
238
|
+
root = Path(root)
|
|
239
|
+
found = [detector(root) for detector in _DETECTORS]
|
|
240
|
+
return [item for item in found if item is not None]
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def suggested_test_command(root: Path) -> TestCommand | None:
|
|
244
|
+
"""The one command to offer as the setup question's default, or `None`.
|
|
245
|
+
|
|
246
|
+
`None` is a real answer and the common one: most trees this tool audits
|
|
247
|
+
will not carry a manifest it recognises, and the question is then asked
|
|
248
|
+
exactly as it always was.
|
|
249
|
+
"""
|
|
250
|
+
found = detect_test_commands(root)
|
|
251
|
+
return found[0] if found else None
|
{maintainability_agent-2.4.1 → maintainability_agent-2.5.0}/src/maintainability_audit/config.py
RENAMED
|
@@ -11,7 +11,7 @@ from ._config_defaults import DEFAULT_CONFIG, DEFAULT_IDIOM_GROUPS
|
|
|
11
11
|
# still the door every caller comes through.
|
|
12
12
|
__all__ = ["DEFAULT_CONFIG", "DEFAULT_IDIOM_GROUPS", "PROJECT_URL", "VERSION"]
|
|
13
13
|
|
|
14
|
-
VERSION = "2.
|
|
14
|
+
VERSION = "2.5.0"
|
|
15
15
|
|
|
16
16
|
PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
|
|
17
17
|
|