roam-code 12.31__tar.gz → 12.33__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.
- {roam_code-12.31 → roam_code-12.33}/PKG-INFO +1 -1
- {roam_code-12.31 → roam_code-12.33}/pyproject.toml +1 -1
- {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/detectors.py +198 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/tasks.py +69 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_debt.py +8 -1
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_describe.py +0 -1
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_math.py +38 -1
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_n1.py +1 -5
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_orphan_routes.py +10 -7
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_comment_render.py +11 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/finding_suppress.py +52 -2
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/resolve.py +7 -5
- {roam_code-12.31 → roam_code-12.33}/src/roam/competitor_site_data.py +2 -2
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/clone_detect.py +3 -13
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/complexity.py +0 -7
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/foxpro_lang.py +0 -2
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/hcl_lang.py +6 -4
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp-server-card.json +1 -1
- {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/seeds.py +0 -2
- {roam_code-12.31 → roam_code-12.33}/src/roam/search/tfidf.py +0 -1
- {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/PKG-INFO +1 -1
- {roam_code-12.31 → roam_code-12.33}/tests/test_math.py +79 -2
- {roam_code-12.31 → roam_code-12.33}/tests/test_mcp_server.py +16 -5
- {roam_code-12.31 → roam_code-12.33}/LICENSE +0 -0
- {roam_code-12.31 → roam_code-12.33}/README.md +0 -0
- {roam_code-12.31 → roam_code-12.33}/setup.cfg +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/__main__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/analysis/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/analysis/effects.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/analysis/taint.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/api.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/ask/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/ask/classifier.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/ask/recipes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/ask/runner.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/ask/workflow.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/attest/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/attest/cga.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/base.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_config.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_django.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_protobuf.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_rest_api.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_salesforce.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/bridge_template.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/bridges/registry.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/fixes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/python_idioms.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/catalog/smells.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/cli.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/audit_trail_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/changed_files.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_adrs.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_adversarial.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_affected.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_affected_tests.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_agent_context.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_agent_export.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_agent_plan.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ai_ratio.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ai_readiness.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_alerts.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_annotate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_api.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_api_changes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_api_drift.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ask.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_attest.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit_trail_conformance.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit_trail_export.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_audit_trail_verify.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_auth_gaps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_bisect.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_breaking.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_budget.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_bus_factor.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_capsule.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_cga.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_changelog.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_check_rules.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ci_setup.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_clean.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_clones.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_closure.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_clusters.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_codeowners.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_complexity.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_config.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_congestion.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_context.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_conventions.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_coupling.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_coverage_gaps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_critique.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_cut.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dark_matter.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dashboard.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dead.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_deps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dev_profile.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_diagnose.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_diff.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_disambiguate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_doc_staleness.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_docs_coverage.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_doctor.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_dogfood.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_drift.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_duplicates.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_effects.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_endpoints.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_entry_points.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_eval_retrieve.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_exit_codes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fan.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_file.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fingerprint.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fitness.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_flag_dead.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fleet.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_fn_coupling.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_forecast.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_graph_export.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_graph_stats.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_grep.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_guard.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_health.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_help_search.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_hooks.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_hotspots.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_hover.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_impact.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_index.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_index_bundle.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_index_stats.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ingest_trace.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_init.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_intent.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_invariants.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_layers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_map.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_mcp_setup.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_mcp_status.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_metrics.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_metrics_push.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_migration_safety.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_minimap.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_missing_index.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_module.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_mutate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_oracle.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_orchestrate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_orphan_imports.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_over_fetch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_owner.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_partition.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_path_coverage.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_patterns.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_plan.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_plan_refactor.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_plugins.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_analyze.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_diff.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_prep.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pr_risk.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pre_commit.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_preflight.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_py_modern.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_py_types.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_pytest_fixtures.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_recipes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_recommend.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_relate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_report.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_reset.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_retrieve.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_risk.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_rules.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_rules_validate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_safe_delete.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_safe_zones.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_sbom.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_schema.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_search.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_search_semantic.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_secrets.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_semantic_diff.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_simulate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_simulate_departure.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_sketch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_smells.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_spectral.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_split.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_stats.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_supply_chain.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_suppress.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_symbol.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_syntax_check.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_taint.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_telemetry.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_gaps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_impact.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_pyramid.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_test_scaffold.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_testmap.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_timeline.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_tour.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_trace.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_trends.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_triage.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_understand.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_uses.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_verify.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_verify_imports.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_version.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vibe_check.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_visualize.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vuln_map.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vuln_reach.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_vulns.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_watch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_weather.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_why.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_why_fail.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_workflow.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_ws.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/cmd_xlang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/codeowners_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/context_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/gate_presets.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/git_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/graph_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/metrics_history.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/next_steps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/audit_trail.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/cache.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/pr_analyze/rules.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/commands/suppression.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/config.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/coverage_reports.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/critique/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/critique/aggregator.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/critique/checks.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/db/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/db/connection.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/db/queries.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/db/schema.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/eval/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/eval/harness.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/exit_codes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/fleet/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/fleet/adapters.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/fleet/manifest.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/git_utils.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/anomaly.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/builder.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/clusters.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/cycles.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/dark_matter.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/diff.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/fingerprint.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/layers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/pagerank.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/partition.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/pathfinding.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/propagation.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/simulate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/spectral.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/graph/stats.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/discovery.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/django_post.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/file_roles.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/git_stats.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/gitignore.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/incremental.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/indexer.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/parser.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/pytest_fixtures.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/registry_dispatch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/relations.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/symbols.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/index/test_conventions.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/apex_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/aura_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/base.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/c_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/csharp_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/extractor_schema.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/extractors/kotlin.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/generic_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/go_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/java_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/javascript_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/kotlin_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/php_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/python_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/query_engine.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/registry.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/ruby_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/rust_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/scala_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/sfxml_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/sql_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/swift_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/typescript_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/visualforce_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/languages/yaml_lang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/completions.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/concurrency.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/progress.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/sampling.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/session.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_extras/watcher.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/mcp_server.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/observability.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/confidence.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/errors.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/file_role_hints.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/formatter.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/framework_filter.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/mermaid.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/project_shape.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/sarif.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/output/schema_registry.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/plugins.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/refactor/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/refactor/codegen.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/refactor/transforms.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/learned_ranker.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/pipeline.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/rerank.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/retrieve/semantic.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/rules/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/rules/ast_match.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/rules/builtin.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/rules/dataflow.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/rules/engine.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/daemon.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/graph_backend.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/hotspots.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/lock_modes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/lockmgr.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/runtime/trace_ingest.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/search/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/search/framework_packs.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/search/index_embeddings.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/search/onnx_embeddings.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/aibom_extension.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_classifier.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_engine.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/api_error_leak.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/java_fileupload_path_traversal.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_insecure_jwt_decode.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_localstorage_secrets.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_prototype_pollution.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_ssrf.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/js_xss.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_basic.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_deserialization.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_path_traversal.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_socketio_remote_source.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_sqli.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/python_urllib_open_redirect.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/taint_rules/vue_v_html.yaml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/vuln_reach.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/security/vuln_store.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/surface_counts.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/telemetry.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/templates/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/Jenkinsfile +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/agent-review.yml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/azure-pipelines.yml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/bitbucket-pipelines.yml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/templates/ci/gitlab-ci.yml +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/__init__.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/aggregator.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/api_scanner.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/config.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam/workspace/db.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/SOURCES.txt +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/dependency_links.txt +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/entry_points.txt +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/requires.txt +0 -0
- {roam_code-12.31 → roam_code-12.33}/src/roam_code.egg-info/top_level.txt +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_adrs.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_adversarial.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_affected.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_agent_export.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_agent_mode.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_agent_plan_context.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ai_ratio.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ai_readiness.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_alerts_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_annotations.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_anomaly.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_api_changes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_api_drift.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ask.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_attest.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_aggregate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_conformance.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_sequence.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_audit_trail_verify.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_auth_gaps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_backend_fixes_round2.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_backend_fixes_round3.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_basic.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_batch_mcp.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_bisect.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_bridge_django.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_bridges.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_bridges_extended.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_budget.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_budget_flag.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_budget_phase2.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_bus_factor.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_capsule.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_cga.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_check_rules.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ci_gate_eval.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ci_sarif_guard.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ci_setup.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_clones.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_closure.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_codeowners.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_commands_architecture.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_commands_exploration.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_commands_health.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_commands_refactoring.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_commands_workflow.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_competitor_site_data.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_comprehensive.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_config.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_congestion.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_context_propagation.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_conventions_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_coverage_gaps_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_coverage_ingestion.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_critique.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_cut.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_dark_matter.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_dark_matter_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_dashboard.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_dataflow_dead.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_dead_aging.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_defer_loading.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_demo_gif_asset.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_describe.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_detail_flag_hints.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_detector_precision.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_deterministic_output.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_dev_profile.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_difficulty_scoring.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_doc_consistency.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_doc_staleness.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_docker_assets.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_docs_coverage.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_docs_site_quality.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_doctor.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_dogfood.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_drift.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_drift_by_team.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_duplicates.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_effects.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_effects_propagation.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_endpoints.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_entry_points_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_eval_retrieve.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_except_pass_narrow.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_exclude_patterns.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_exit_codes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_extractor_grammar_drift.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_fallback_contracts.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_file_roles.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_finding_suppress.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_fingerprint.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_fixes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_flag_dead.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_fleet.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_fn_coupling.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_forecast.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_formatters.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_foxpro.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_framework_detection.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_gate_presets.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_git_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_git_utils.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_guard.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_health_gate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_hooks.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_hotspots.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_hover.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_index.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_index_bundle.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_init_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_install_check.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_intent.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_invariants.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_json_contracts.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_json_error_envelope.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_kotlin_swift_extractors.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_language_corpus.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_languages.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_laravel_fp_fixes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_library_api.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_math_fp_fixes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_math_tips.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_mcp_extras.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_mcp_setup.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_mermaid.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_metrics_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_metrics_push.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_migration_safety.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_minimap.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_missing_index.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_mutate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_n1.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_next_steps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_onboard.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_oracle.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_orchestrate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_orphan_routes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_oss_bench_harness.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_over_fetch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pagerank_truncation.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_partition.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_path_coverage.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_patterns_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_performance.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_personalized_pagerank.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_plan.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_plugin_discovery.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_cache.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_edge_cases.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_helpers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_analyze_v2_signals.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_comment_render.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_comment_script.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_diff.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pr_risk_author.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_progress.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_progressive_disclosure.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_properties.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_pytest_fixtures.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_python_extractor_v2.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_python_idioms_e2e.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_python_pivot.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_readme_surface_consistency.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_realworld_feedback.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_refactoring_intelligence.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_registry_dispatch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_regression_fp_corpus.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_relate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_report.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_reset_clean.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_resolve.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_retrieve.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_retrieve_cross_repo.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_retrieve_seeds.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_risk.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ruby.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_rule_profiles.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_rules.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_rules_ast_match.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_rules_community_pack.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_rules_dataflow.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_rules_symbol_requirements.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_rules_validate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_runtime.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_runtime_score.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_salesforce.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_sarif_flag.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_sbom.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_scala.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_schema_versioning.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_search_explain.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_secrets.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_secrets_v2.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_semantic_diff.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_semantic_onnx.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_semantic_search.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_simulate.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_simulate_departure.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_sketch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_smells.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_smoke.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_sna_metrics.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_spectral.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_split_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_sql.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_suggest_reviewers.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_supply_chain.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_surface_counts.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_syntax_check.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_taint.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_taint_analysis.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_taint_classifier.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_taint_intraprocedural.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_test_conventions.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_test_gaps.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_test_scaffold.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_testmap.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_top_flag_consistency.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_tour_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_trends.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_trends_cohort.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_triage.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_uses_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1215_passes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1216_passes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1216_passes_41_50.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1216_passes_51_60.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1217_passes_61_80.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1218_passes_81_90.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1219_passes_91_100.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1220_passes_101_110.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1221_query_timeout.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v1221_untested_commands.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v12_2.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v2_edge_cases.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v2_integration.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v6_features.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v71_features.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v7_features.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_v82_features.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_verify.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_verify_imports.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_vibe_check.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_visualize.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_vuln.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_vulns_cmd.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_watch.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_why.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_workspace.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_ws_resolve_fixes.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_xlang.py +0 -0
- {roam_code-12.31 → roam_code-12.33}/tests/test_yaml_hcl.py +0 -0
|
@@ -1723,6 +1723,10 @@ def autodetect_framework_profile() -> str | None:
|
|
|
1723
1723
|
tanstack = "@tanstack/vue-query" in deps or "@tanstack/query-core" in deps
|
|
1724
1724
|
if tanstack and (vue_ver.startswith("^3") or vue_ver.startswith("3") or vue_ver.startswith("~3")):
|
|
1725
1725
|
return "vue3-tanstack"
|
|
1726
|
+
# Z6 (2026-05-06) — Express/Koa/Fastify don't have framework
|
|
1727
|
+
# profiles yet (they're light frameworks; the I/O patterns are
|
|
1728
|
+
# generic Node fs / http). Return None for now but flag in meta
|
|
1729
|
+
# so future versions can add a profile when one becomes useful.
|
|
1726
1730
|
|
|
1727
1731
|
composer = _read_json(_os.path.join(cwd, "composer.json"))
|
|
1728
1732
|
if composer:
|
|
@@ -2766,6 +2770,197 @@ def detect_chained_collection_walks(conn: sqlite3.Connection) -> list[dict]:
|
|
|
2766
2770
|
return results
|
|
2767
2771
|
|
|
2768
2772
|
|
|
2773
|
+
# Z1 (2026-05-06) — React: `useEffect(() => { ... })` without a dependency
|
|
2774
|
+
# array runs on EVERY render. Almost always a bug — the dev forgot the
|
|
2775
|
+
# second argument. The fix is `useEffect(() => { ... }, [deps])` or
|
|
2776
|
+
# `useEffect(() => { ... }, [])` for mount-only.
|
|
2777
|
+
_RE_USEEFFECT_NO_DEPS = re.compile(
|
|
2778
|
+
r"\buseEffect\s*\(\s*(?:async\s+)?(?:\(\s*\)|function\s*\(\s*\))\s*=>\s*\{[^}]*?\}\s*\)",
|
|
2779
|
+
re.DOTALL,
|
|
2780
|
+
)
|
|
2781
|
+
_RE_USEEFFECT_WITH_DEPS = re.compile(
|
|
2782
|
+
r"\buseEffect\s*\(\s*[^,]+,\s*\[",
|
|
2783
|
+
)
|
|
2784
|
+
|
|
2785
|
+
|
|
2786
|
+
def detect_useeffect_missing_deps(conn: sqlite3.Connection) -> list[dict]:
|
|
2787
|
+
"""React: `useEffect(() => {...})` without a dependency array."""
|
|
2788
|
+
try:
|
|
2789
|
+
rows = conn.execute(
|
|
2790
|
+
"SELECT s.id, s.name, s.qualified_name, s.kind, f.path AS file_path, "
|
|
2791
|
+
"s.line_start, s.line_end "
|
|
2792
|
+
"FROM symbols s "
|
|
2793
|
+
"JOIN files f ON s.file_id = f.id "
|
|
2794
|
+
"WHERE s.kind IN ('function', 'method') "
|
|
2795
|
+
"AND f.language IN ('javascript', 'typescript', 'tsx', 'jsx')"
|
|
2796
|
+
).fetchall()
|
|
2797
|
+
except Exception:
|
|
2798
|
+
return []
|
|
2799
|
+
results = []
|
|
2800
|
+
for r in rows:
|
|
2801
|
+
if _is_test_path(r["file_path"]):
|
|
2802
|
+
continue
|
|
2803
|
+
snippet = _read_symbol_source(r["file_path"], r["line_start"], r["line_end"])
|
|
2804
|
+
if not snippet or "useEffect" not in snippet:
|
|
2805
|
+
continue
|
|
2806
|
+
# Skip if every useEffect call also has a deps array.
|
|
2807
|
+
no_deps = _RE_USEEFFECT_NO_DEPS.search(snippet)
|
|
2808
|
+
if not no_deps:
|
|
2809
|
+
continue
|
|
2810
|
+
# Verify the SAME call doesn't have a deps array (regex catches the
|
|
2811
|
+
# no-deps shape but a more elaborate body could trick it).
|
|
2812
|
+
# Conservative: only fire when there's NO useEffect-with-deps in body.
|
|
2813
|
+
if _RE_USEEFFECT_WITH_DEPS.search(snippet):
|
|
2814
|
+
# Mixed bag — at least one useEffect has deps, can't reliably
|
|
2815
|
+
# tell which one is the problem without a real parser. Skip.
|
|
2816
|
+
continue
|
|
2817
|
+
line_offset = snippet[: no_deps.start()].count("\n")
|
|
2818
|
+
match_line = (r["line_start"] or 1) + line_offset
|
|
2819
|
+
results.append(
|
|
2820
|
+
_finding(
|
|
2821
|
+
"useeffect-missing-deps",
|
|
2822
|
+
"no-deps-array",
|
|
2823
|
+
r,
|
|
2824
|
+
"useEffect without dependency array — runs on every render",
|
|
2825
|
+
"high",
|
|
2826
|
+
match_line=match_line,
|
|
2827
|
+
snippet=snippet,
|
|
2828
|
+
matched_patterns=["useEffect call", "no second-arg dep array"],
|
|
2829
|
+
)
|
|
2830
|
+
)
|
|
2831
|
+
return results
|
|
2832
|
+
|
|
2833
|
+
|
|
2834
|
+
# Z2 (2026-05-06) — `eval()` / `exec()` / `new Function()` / `setTimeout(string)`
|
|
2835
|
+
# in production source. These are arbitrary code execution sinks if the
|
|
2836
|
+
# input is user-derived. Even when "safe" (literal string), they trip
|
|
2837
|
+
# CSP rules and bundler optimisations. Suppress when test path.
|
|
2838
|
+
_RE_EVAL_CALLS = re.compile(
|
|
2839
|
+
r"\b(?:eval|exec|execfile|compile)\s*\("
|
|
2840
|
+
r"|\bnew\s+Function\s*\("
|
|
2841
|
+
r"|\bsetTimeout\s*\(\s*['\"]"
|
|
2842
|
+
r"|\bsetInterval\s*\(\s*['\"]",
|
|
2843
|
+
)
|
|
2844
|
+
|
|
2845
|
+
|
|
2846
|
+
def detect_dangerous_eval(conn: sqlite3.Connection) -> list[dict]:
|
|
2847
|
+
"""Detect `eval`, `exec`, `new Function(...)`, `setTimeout(string)` — code-injection sinks."""
|
|
2848
|
+
try:
|
|
2849
|
+
rows = conn.execute(
|
|
2850
|
+
"SELECT s.id, s.name, s.qualified_name, s.kind, f.path AS file_path, "
|
|
2851
|
+
"f.language AS language, s.line_start, s.line_end "
|
|
2852
|
+
"FROM symbols s "
|
|
2853
|
+
"JOIN files f ON s.file_id = f.id "
|
|
2854
|
+
"WHERE s.kind IN ('function', 'method')"
|
|
2855
|
+
).fetchall()
|
|
2856
|
+
except Exception:
|
|
2857
|
+
return []
|
|
2858
|
+
results = []
|
|
2859
|
+
for r in rows:
|
|
2860
|
+
if _is_test_path(r["file_path"]):
|
|
2861
|
+
continue
|
|
2862
|
+
# Skip non-source roles when we can tell.
|
|
2863
|
+
path = (r["file_path"] or "").replace("\\", "/").lower()
|
|
2864
|
+
if "/migration" in path or "/script" in path or "/cli" in path:
|
|
2865
|
+
# CLI / migration scripts often legitimately use exec/eval.
|
|
2866
|
+
continue
|
|
2867
|
+
snippet = _read_symbol_source(r["file_path"], r["line_start"], r["line_end"])
|
|
2868
|
+
if not snippet:
|
|
2869
|
+
continue
|
|
2870
|
+
m = _RE_EVAL_CALLS.search(snippet)
|
|
2871
|
+
if not m:
|
|
2872
|
+
continue
|
|
2873
|
+
# Skip ast.literal_eval (safe), regex.compile (different "compile"
|
|
2874
|
+
# — won't actually match because it ends in `.compile(` with a dot
|
|
2875
|
+
# before, so prefix isn't word-boundary — but be defensive).
|
|
2876
|
+
if "literal_eval" in snippet[max(0, m.start() - 20) : m.end()]:
|
|
2877
|
+
continue
|
|
2878
|
+
if ".compile(" in snippet[max(0, m.start() - 5) : m.end() + 1]:
|
|
2879
|
+
continue
|
|
2880
|
+
line_offset = snippet[: m.start()].count("\n")
|
|
2881
|
+
match_line = (r["line_start"] or 1) + line_offset
|
|
2882
|
+
called = m.group(0).rstrip("(")
|
|
2883
|
+
results.append(
|
|
2884
|
+
_finding(
|
|
2885
|
+
"dangerous-eval",
|
|
2886
|
+
"eval-or-exec",
|
|
2887
|
+
r,
|
|
2888
|
+
f"Dangerous dynamic execution sink ({called}) — code-injection risk if input is user-derived",
|
|
2889
|
+
"high",
|
|
2890
|
+
match_line=match_line,
|
|
2891
|
+
snippet=snippet,
|
|
2892
|
+
matched_patterns=[f"call: {called}", "not in test/migration/script path"],
|
|
2893
|
+
)
|
|
2894
|
+
)
|
|
2895
|
+
return results
|
|
2896
|
+
|
|
2897
|
+
|
|
2898
|
+
# Z5 (2026-05-06) — JS/TS DOM listener leak: `addEventListener` without
|
|
2899
|
+
# a paired `removeEventListener` keeps references alive after the
|
|
2900
|
+
# component unmounts. Detect ONLY when the function looks like a
|
|
2901
|
+
# component lifecycle (useEffect / componentDidMount / connectedCallback /
|
|
2902
|
+
# constructor) and addEventListener appears without remove.
|
|
2903
|
+
_RE_ADD_LISTENER = re.compile(r"\baddEventListener\s*\(")
|
|
2904
|
+
_RE_REMOVE_LISTENER = re.compile(r"\bremoveEventListener\s*\(")
|
|
2905
|
+
_RE_LIFECYCLE = re.compile(
|
|
2906
|
+
r"\b(?:useEffect|componentDidMount|componentWillMount|connectedCallback|constructor)\b",
|
|
2907
|
+
)
|
|
2908
|
+
|
|
2909
|
+
|
|
2910
|
+
def detect_unremoved_event_listener(conn: sqlite3.Connection) -> list[dict]:
|
|
2911
|
+
"""JS/TS: `addEventListener` in a lifecycle without paired `removeEventListener`."""
|
|
2912
|
+
try:
|
|
2913
|
+
rows = conn.execute(
|
|
2914
|
+
"SELECT s.id, s.name, s.qualified_name, s.kind, f.path AS file_path, "
|
|
2915
|
+
"s.line_start, s.line_end "
|
|
2916
|
+
"FROM symbols s "
|
|
2917
|
+
"JOIN files f ON s.file_id = f.id "
|
|
2918
|
+
"WHERE s.kind IN ('function', 'method') "
|
|
2919
|
+
"AND f.language IN ('javascript', 'typescript', 'tsx', 'jsx')"
|
|
2920
|
+
).fetchall()
|
|
2921
|
+
except Exception:
|
|
2922
|
+
return []
|
|
2923
|
+
results = []
|
|
2924
|
+
for r in rows:
|
|
2925
|
+
if _is_test_path(r["file_path"]):
|
|
2926
|
+
continue
|
|
2927
|
+
snippet = _read_symbol_source(r["file_path"], r["line_start"], r["line_end"])
|
|
2928
|
+
if not snippet:
|
|
2929
|
+
continue
|
|
2930
|
+
if not _RE_ADD_LISTENER.search(snippet):
|
|
2931
|
+
continue
|
|
2932
|
+
# Only fire for lifecycle-ish bodies — outside of components,
|
|
2933
|
+
# listeners are often global and intentionally never removed.
|
|
2934
|
+
if not _RE_LIFECYCLE.search(snippet):
|
|
2935
|
+
continue
|
|
2936
|
+
# Already paired: presence of removeEventListener anywhere in body.
|
|
2937
|
+
if _RE_REMOVE_LISTENER.search(snippet):
|
|
2938
|
+
continue
|
|
2939
|
+
# `useEffect` should also return a cleanup function. Check for one.
|
|
2940
|
+
if "useEffect" in snippet and re.search(r"return\s+(?:\(\s*\)|function)", snippet):
|
|
2941
|
+
continue
|
|
2942
|
+
m = _RE_ADD_LISTENER.search(snippet)
|
|
2943
|
+
line_offset = snippet[: m.start()].count("\n")
|
|
2944
|
+
match_line = (r["line_start"] or 1) + line_offset
|
|
2945
|
+
results.append(
|
|
2946
|
+
_finding(
|
|
2947
|
+
"unremoved-event-listener",
|
|
2948
|
+
"no-cleanup",
|
|
2949
|
+
r,
|
|
2950
|
+
"addEventListener in component lifecycle without removeEventListener — memory leak",
|
|
2951
|
+
"high",
|
|
2952
|
+
match_line=match_line,
|
|
2953
|
+
snippet=snippet,
|
|
2954
|
+
matched_patterns=[
|
|
2955
|
+
"addEventListener call",
|
|
2956
|
+
"lifecycle context (useEffect / componentDidMount / etc.)",
|
|
2957
|
+
"no paired removeEventListener",
|
|
2958
|
+
],
|
|
2959
|
+
)
|
|
2960
|
+
)
|
|
2961
|
+
return results
|
|
2962
|
+
|
|
2963
|
+
|
|
2769
2964
|
def detect_loop_lookup(conn: sqlite3.Connection) -> list[dict]:
|
|
2770
2965
|
""".index(), .indexOf(), .contains(), .includes() called inside a loop.
|
|
2771
2966
|
|
|
@@ -3736,6 +3931,9 @@ _MATH_DETECTORS = [
|
|
|
3736
3931
|
("spread-accumulator", "spread-rebind", detect_spread_accumulator),
|
|
3737
3932
|
("defer-in-loop", "loop-defer", detect_defer_in_loop),
|
|
3738
3933
|
("chained-collection-walk", "two-pass-walk", detect_chained_collection_walks),
|
|
3934
|
+
("useeffect-missing-deps", "no-deps-array", detect_useeffect_missing_deps),
|
|
3935
|
+
("dangerous-eval", "eval-or-exec", detect_dangerous_eval),
|
|
3936
|
+
("unremoved-event-listener", "no-cleanup", detect_unremoved_event_listener),
|
|
3739
3937
|
("list-prepend", "insert-front", detect_list_prepend),
|
|
3740
3938
|
("sort-to-select", "full-sort", detect_sort_to_select),
|
|
3741
3939
|
("loop-lookup", "method-scan", detect_loop_lookup),
|
|
@@ -400,6 +400,75 @@ CATALOG: dict[str, dict] = {
|
|
|
400
400
|
},
|
|
401
401
|
],
|
|
402
402
|
},
|
|
403
|
+
"unremoved-event-listener": {
|
|
404
|
+
"name": "addEventListener without paired removeEventListener (memory leak)",
|
|
405
|
+
"category": "concurrency",
|
|
406
|
+
"kind": "idiom",
|
|
407
|
+
"ways": [
|
|
408
|
+
{
|
|
409
|
+
"id": "with-cleanup",
|
|
410
|
+
"name": "useEffect cleanup / removeEventListener",
|
|
411
|
+
"time": "n/a",
|
|
412
|
+
"space": "n/a",
|
|
413
|
+
"rank": 1,
|
|
414
|
+
"tip": "Return a cleanup function from useEffect: `useEffect(() => { window.addEventListener('x', h); return () => window.removeEventListener('x', h); }, [])`. For class components, pair in componentWillUnmount.",
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"id": "no-cleanup",
|
|
418
|
+
"name": "addEventListener with no cleanup",
|
|
419
|
+
"time": "n/a",
|
|
420
|
+
"space": "n/a",
|
|
421
|
+
"rank": 10,
|
|
422
|
+
"tip": "",
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
},
|
|
426
|
+
"dangerous-eval": {
|
|
427
|
+
"name": "Dynamic execution sink (eval / exec / new Function)",
|
|
428
|
+
"category": "error-handling",
|
|
429
|
+
"kind": "idiom",
|
|
430
|
+
"ways": [
|
|
431
|
+
{
|
|
432
|
+
"id": "narrow-or-remove",
|
|
433
|
+
"name": "Use a parser / template / safer dispatch",
|
|
434
|
+
"time": "n/a",
|
|
435
|
+
"space": "n/a",
|
|
436
|
+
"rank": 1,
|
|
437
|
+
"tip": "Prefer ast.literal_eval, JSON.parse, a real template engine, or a switch/dispatch dict over arbitrary-string execution. Tightens CSP; eliminates injection surface.",
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"id": "eval-or-exec",
|
|
441
|
+
"name": "eval / exec / new Function with dynamic input",
|
|
442
|
+
"time": "n/a",
|
|
443
|
+
"space": "n/a",
|
|
444
|
+
"rank": 10,
|
|
445
|
+
"tip": "",
|
|
446
|
+
},
|
|
447
|
+
],
|
|
448
|
+
},
|
|
449
|
+
"useeffect-missing-deps": {
|
|
450
|
+
"name": "React useEffect without dependency array",
|
|
451
|
+
"category": "concurrency",
|
|
452
|
+
"kind": "idiom",
|
|
453
|
+
"ways": [
|
|
454
|
+
{
|
|
455
|
+
"id": "with-deps",
|
|
456
|
+
"name": "useEffect with explicit dep array",
|
|
457
|
+
"time": "n/a",
|
|
458
|
+
"space": "n/a",
|
|
459
|
+
"rank": 1,
|
|
460
|
+
"tip": "Add the dependency array as the second argument: `useEffect(() => {...}, [deps])`. Use `[]` for mount-only effects.",
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"id": "no-deps-array",
|
|
464
|
+
"name": "useEffect without deps (runs every render)",
|
|
465
|
+
"time": "n/a",
|
|
466
|
+
"space": "n/a",
|
|
467
|
+
"rank": 10,
|
|
468
|
+
"tip": "",
|
|
469
|
+
},
|
|
470
|
+
],
|
|
471
|
+
},
|
|
403
472
|
"chained-collection-walk": {
|
|
404
473
|
"name": "Chained collection walk (filter+find / map+find / filter+length)",
|
|
405
474
|
"category": "collections",
|
|
@@ -562,10 +562,17 @@ def debt(ctx, limit, by_kind, threshold, roi):
|
|
|
562
562
|
_debt_label = (
|
|
563
563
|
"low debt" if stats["mean_debt"] < 0.1 else "moderate debt" if stats["mean_debt"] < 0.3 else "high debt"
|
|
564
564
|
)
|
|
565
|
+
# Z14 (2026-05-06) — append top-1 hotspot to the verdict so the
|
|
566
|
+
# one-line summary tells you WHERE to look first, not just IF
|
|
567
|
+
# there's debt.
|
|
568
|
+
top_hint = ""
|
|
569
|
+
if all_items:
|
|
570
|
+
top1 = all_items[0]
|
|
571
|
+
top_hint = f" — top hotspot: {top1['path']} (score={top1['debt_score']})"
|
|
565
572
|
_debt_verdict = (
|
|
566
573
|
f"{_debt_label}: {_n_cycles} cycle files, "
|
|
567
574
|
f"{_n_gods} god components, {_n_hotspots} hotspots "
|
|
568
|
-
f"across {stats['total_files']} files"
|
|
575
|
+
f"across {stats['total_files']} files{top_hint}"
|
|
569
576
|
)
|
|
570
577
|
|
|
571
578
|
roi_summary, roi_by_path = ({}, {})
|
|
@@ -147,6 +147,23 @@ def math_cmd(
|
|
|
147
147
|
click.echo(name)
|
|
148
148
|
return
|
|
149
149
|
|
|
150
|
+
# Z7 (2026-05-06) — validate --task against the catalog; on typo, show
|
|
151
|
+
# the closest matches by edit distance instead of running 49 detectors
|
|
152
|
+
# silently to find zero results.
|
|
153
|
+
if task_filter:
|
|
154
|
+
from roam.catalog.tasks import CATALOG
|
|
155
|
+
|
|
156
|
+
if task_filter not in CATALOG:
|
|
157
|
+
import difflib
|
|
158
|
+
|
|
159
|
+
close = difflib.get_close_matches(task_filter, list(CATALOG.keys()), n=3, cutoff=0.4)
|
|
160
|
+
hint = f" Did you mean: {', '.join(close)}?" if close else ""
|
|
161
|
+
click.echo(
|
|
162
|
+
f"NOTE: --task '{task_filter}' is not a known task id."
|
|
163
|
+
f" Run `roam math --json` then look at distinct `task_id` values." + hint,
|
|
164
|
+
err=True,
|
|
165
|
+
)
|
|
166
|
+
|
|
150
167
|
ensure_index()
|
|
151
168
|
|
|
152
169
|
from roam.catalog.detectors import autodetect_framework_profile, run_detectors
|
|
@@ -289,7 +306,18 @@ def math_cmd(
|
|
|
289
306
|
if top_n >= max(3, total // 2):
|
|
290
307
|
category_hint = f"; mostly: {top_cat}"
|
|
291
308
|
if total == 0:
|
|
292
|
-
|
|
309
|
+
# Z3 (2026-05-06) — informative zero-state. When 0 findings,
|
|
310
|
+
# tell the user (a) which profile filter was active, (b) how
|
|
311
|
+
# many detectors ran, (c) what to try next.
|
|
312
|
+
profile_note = ""
|
|
313
|
+
if profile != "balanced":
|
|
314
|
+
profile_note = f" (profile={profile} may be too strict; try --profile balanced)"
|
|
315
|
+
verdict = (
|
|
316
|
+
f"No algorithmic issues detected{profile_note} — "
|
|
317
|
+
f"{detector_meta.get('detectors_executed', 0)} detector(s) ran cleanly. "
|
|
318
|
+
f"Try `roam math --profile aggressive` for more candidates "
|
|
319
|
+
f"or `roam debt --top 10` for refactoring ROI hotspots."
|
|
320
|
+
)
|
|
293
321
|
elif suppressed_count > 0:
|
|
294
322
|
verdict = (
|
|
295
323
|
f"{unsuppressed_total} unsuppressed candidate{'s' if unsuppressed_total != 1 else ''} "
|
|
@@ -341,6 +369,15 @@ def math_cmd(
|
|
|
341
369
|
[float(f.get("impact_score", 0.0) or 0.0) for f in findings],
|
|
342
370
|
default=0.0,
|
|
343
371
|
),
|
|
372
|
+
# Z13 (2026-05-06) — top_tasks_by_count helps CI
|
|
373
|
+
# dashboards / agents prioritise without iterating
|
|
374
|
+
# every finding. Format: [{task_id, count}, ...].
|
|
375
|
+
"top_tasks_by_count": [
|
|
376
|
+
{"task_id": tid, "count": n}
|
|
377
|
+
for tid, n in __import__("collections")
|
|
378
|
+
.Counter(f.get("task_id", "?") for f in findings)
|
|
379
|
+
.most_common(3)
|
|
380
|
+
],
|
|
344
381
|
},
|
|
345
382
|
findings=findings,
|
|
346
383
|
)
|
|
@@ -39,13 +39,11 @@ from roam.output.formatter import json_envelope, loc, to_json
|
|
|
39
39
|
|
|
40
40
|
# Patterns that identify ORM model classes by parent class or trait
|
|
41
41
|
_MODEL_PARENTS = {
|
|
42
|
-
# Laravel / Eloquent
|
|
42
|
+
# Laravel / Eloquent / Django (both use bare "Model" — single membership)
|
|
43
43
|
"Model",
|
|
44
44
|
"Eloquent",
|
|
45
45
|
"Authenticatable",
|
|
46
|
-
# Django
|
|
47
46
|
"models.Model",
|
|
48
|
-
"Model",
|
|
49
47
|
# Rails / ActiveRecord
|
|
50
48
|
"ApplicationRecord",
|
|
51
49
|
"ActiveRecord::Base",
|
|
@@ -129,7 +127,6 @@ _RELATIONSHIP_CALLS = {
|
|
|
129
127
|
"load",
|
|
130
128
|
"fetch",
|
|
131
129
|
"findOrFail",
|
|
132
|
-
"find",
|
|
133
130
|
}
|
|
134
131
|
|
|
135
132
|
# I/O operations that indicate a DB query or network call
|
|
@@ -154,7 +151,6 @@ _IO_INDICATORS = {
|
|
|
154
151
|
# HTTP
|
|
155
152
|
"fetch",
|
|
156
153
|
"request",
|
|
157
|
-
"get",
|
|
158
154
|
"post",
|
|
159
155
|
"put",
|
|
160
156
|
# File
|
|
@@ -468,17 +468,20 @@ def _analyse_orphan_routes(project_root: Path, conn, limit: int) -> dict:
|
|
|
468
468
|
# Deduplicate
|
|
469
469
|
all_matching = list(set(all_matching))
|
|
470
470
|
|
|
471
|
-
# Remove the route files themselves and the controller file from matches
|
|
471
|
+
# Remove the route files themselves and the controller file from matches.
|
|
472
|
+
# `_ctrl` and `_route_files` are bound as defaults so the closure
|
|
473
|
+
# captures THIS iteration's values (per-loop B023 fix).
|
|
472
474
|
controller_name = route.get("controller") or ""
|
|
473
475
|
|
|
474
|
-
def _is_self_reference(
|
|
476
|
+
def _is_self_reference(
|
|
477
|
+
file_path: str,
|
|
478
|
+
_ctrl: str = controller_name,
|
|
479
|
+
_route_files: set = route_file_prefixes,
|
|
480
|
+
) -> bool:
|
|
475
481
|
norm = file_path.replace("\\", "/")
|
|
476
|
-
|
|
477
|
-
if norm in route_file_prefixes:
|
|
482
|
+
if norm in _route_files:
|
|
478
483
|
return True
|
|
479
|
-
|
|
480
|
-
if controller_name and controller_name.lower() in norm.lower():
|
|
481
|
-
# Check it actually looks like a controller path
|
|
484
|
+
if _ctrl and _ctrl.lower() in norm.lower():
|
|
482
485
|
if "controller" in norm.lower() or "http" in norm.lower():
|
|
483
486
|
return True
|
|
484
487
|
return False
|
|
@@ -287,6 +287,13 @@ def _section_rule_violations(rule_violations: list[dict]) -> list[str]:
|
|
|
287
287
|
out = ["### Architecture rule violations", ""]
|
|
288
288
|
block_v = [v for v in rule_violations if v.get("severity") == "BLOCK"]
|
|
289
289
|
warn_v = [v for v in rule_violations if v.get("severity") in ("WARN", "WARNING")]
|
|
290
|
+
# Z4 (2026-05-06) — when total violations is huge, wrap the per-item
|
|
291
|
+
# detail in a collapsible <details> block so the comment doesn't
|
|
292
|
+
# dominate the PR thread on noisy diffs.
|
|
293
|
+
use_details = len(rule_violations) >= 12
|
|
294
|
+
if use_details:
|
|
295
|
+
out.append(f"<details><summary>{len(rule_violations)} violation(s) — expand for detail</summary>")
|
|
296
|
+
out.append("")
|
|
290
297
|
for v in block_v[:5]:
|
|
291
298
|
out.append(f"- **BLOCK** `{v['rule_id']}`: `{v['file']}` -> `{v['matched_import']}`")
|
|
292
299
|
if v.get("description"):
|
|
@@ -309,6 +316,10 @@ def _section_rule_violations(rule_violations: list[dict]) -> list[str]:
|
|
|
309
316
|
chunks = [f"`{rid}` x{n} ({sev})" for (sev, rid), n in counts.most_common(5)]
|
|
310
317
|
more_total = extra_block + extra_warn
|
|
311
318
|
out.append(f"- _...{more_total} more violation(s): " + ", ".join(chunks) + "._")
|
|
319
|
+
# Z4 — close the collapsible block when we opened one.
|
|
320
|
+
if use_details:
|
|
321
|
+
out.append("")
|
|
322
|
+
out.append("</details>")
|
|
312
323
|
out.append("")
|
|
313
324
|
return out
|
|
314
325
|
|
|
@@ -91,6 +91,52 @@ def _inline_match(line_text: str, command: str, task_id: str) -> bool:
|
|
|
91
91
|
return False
|
|
92
92
|
|
|
93
93
|
|
|
94
|
+
def _parse_simple_ignore_findings_yaml(text: str) -> dict:
|
|
95
|
+
"""Minimal YAML parser for .roamignore-findings — no PyYAML required.
|
|
96
|
+
|
|
97
|
+
Handles the documented shape only:
|
|
98
|
+
|
|
99
|
+
rules:
|
|
100
|
+
- task_id: io-in-loop
|
|
101
|
+
path_glob: "src/composables/**/*.ts"
|
|
102
|
+
reason: "..."
|
|
103
|
+
- task_id: branching-recursion
|
|
104
|
+
path_glob: "src/utils/object-diff.ts"
|
|
105
|
+
|
|
106
|
+
Anything more complex (anchors, multi-line strings, nested lists)
|
|
107
|
+
needs real PyYAML. Returns ``{}`` on shapes we can't recognise so
|
|
108
|
+
callers fall through to a clean empty-rules state.
|
|
109
|
+
"""
|
|
110
|
+
rules: list[dict] = []
|
|
111
|
+
current: dict | None = None
|
|
112
|
+
in_rules_block = False
|
|
113
|
+
for raw in text.splitlines():
|
|
114
|
+
line = raw.rstrip()
|
|
115
|
+
stripped = line.strip()
|
|
116
|
+
if not stripped or stripped.startswith("#"):
|
|
117
|
+
continue
|
|
118
|
+
if stripped == "rules:" or stripped.startswith("rules:"):
|
|
119
|
+
in_rules_block = True
|
|
120
|
+
continue
|
|
121
|
+
if not in_rules_block:
|
|
122
|
+
continue
|
|
123
|
+
if stripped.startswith("- "):
|
|
124
|
+
if current:
|
|
125
|
+
rules.append(current)
|
|
126
|
+
current = {}
|
|
127
|
+
stripped = stripped[2:].strip()
|
|
128
|
+
# First key on the same line as `-` is the common shape.
|
|
129
|
+
if ":" in stripped:
|
|
130
|
+
k, _, v = stripped.partition(":")
|
|
131
|
+
current[k.strip()] = v.strip().strip('"').strip("'")
|
|
132
|
+
elif current is not None and ":" in stripped:
|
|
133
|
+
k, _, v = stripped.partition(":")
|
|
134
|
+
current[k.strip()] = v.strip().strip('"').strip("'")
|
|
135
|
+
if current:
|
|
136
|
+
rules.append(current)
|
|
137
|
+
return {"rules": rules} if rules else {}
|
|
138
|
+
|
|
139
|
+
|
|
94
140
|
def _load_ignore_findings_file(path: Path) -> list[dict]:
|
|
95
141
|
"""Load `.roamignore-findings` from ``path``. Returns ``[]`` on any error.
|
|
96
142
|
|
|
@@ -116,11 +162,15 @@ def _load_ignore_findings_file(path: Path) -> list[dict]:
|
|
|
116
162
|
|
|
117
163
|
data = yaml.safe_load(text) or {}
|
|
118
164
|
except ImportError:
|
|
119
|
-
# No PyYAML:
|
|
165
|
+
# No PyYAML: try strict JSON first, then a minimal-YAML fallback so
|
|
166
|
+
# the .roamignore-findings format works on Python 3.9 / installs
|
|
167
|
+
# without PyYAML (PyYAML is not a project dependency).
|
|
120
168
|
try:
|
|
121
169
|
data = _json.loads(text)
|
|
122
170
|
except _json.JSONDecodeError:
|
|
123
|
-
|
|
171
|
+
data = _parse_simple_ignore_findings_yaml(text)
|
|
172
|
+
if not data:
|
|
173
|
+
return []
|
|
124
174
|
except Exception: # noqa: BLE001 — malformed YAML never crashes the analyser
|
|
125
175
|
return []
|
|
126
176
|
rules = data.get("rules") if isinstance(data, dict) else []
|
|
@@ -414,12 +414,14 @@ def find_symbol_with_alternatives(conn: sqlite3.Connection, name: str) -> tuple[
|
|
|
414
414
|
|
|
415
415
|
signals = _ambiguity_signals(conn, rows)
|
|
416
416
|
|
|
417
|
-
|
|
417
|
+
# Bind `signals` as default so the closure captures THIS iteration's
|
|
418
|
+
# value (avoids the late-binding-loop closure pitfall flagged by B023).
|
|
419
|
+
def _score(r, _sig=signals):
|
|
418
420
|
return (
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
421
|
+
_sig["ref"].get(r["id"], 0),
|
|
422
|
+
_sig["pr"].get(r["id"], 0),
|
|
423
|
+
_sig["cc"].get(r["id"], 0),
|
|
424
|
+
_sig["churn"].get(r["file_id"], 0) if "file_id" in r.keys() else 0,
|
|
423
425
|
_path_rank(r["file_path"]),
|
|
424
426
|
-r["id"],
|
|
425
427
|
)
|
|
@@ -1362,8 +1362,8 @@ MAP_METADATA: dict[str, dict[str, object]] = {
|
|
|
1362
1362
|
"relationship": "self",
|
|
1363
1363
|
"peer": True,
|
|
1364
1364
|
"graph": "PageRank + Tarjan + Louvain + layers",
|
|
1365
|
-
"note": "Graph algorithms (PageRank, SCC, Louvain, Fiedler) on tree-sitter ASTs fused with git history in SQLite. 136 MCP tools, 187 CLI commands. 19 Python idiom detectors (v12.7+).
|
|
1366
|
-
"version_evaluated": "12.
|
|
1365
|
+
"note": "Graph algorithms (PageRank, SCC, Louvain, Fiedler) on tree-sitter ASTs fused with git history in SQLite. 136 MCP tools, 187 CLI commands. 19 Python idiom detectors (v12.7+). 54 algo detectors (12.33).",
|
|
1366
|
+
"version_evaluated": "12.33",
|
|
1367
1367
|
"repo_url": "https://github.com/Cranot/roam-code",
|
|
1368
1368
|
},
|
|
1369
1369
|
"CKB/CodeMCP": {
|
|
@@ -158,29 +158,19 @@ def _jaccard_bags(a: Counter, b: Counter) -> float:
|
|
|
158
158
|
|
|
159
159
|
_FUNCTION_NODE_TYPES = frozenset(
|
|
160
160
|
{
|
|
161
|
-
# Python
|
|
161
|
+
# Python / C / C++ all share `function_definition`
|
|
162
162
|
"function_definition",
|
|
163
|
-
# JS/TS
|
|
163
|
+
# JS/TS / Swift share `function_declaration`
|
|
164
164
|
"function_declaration",
|
|
165
165
|
"method_definition",
|
|
166
166
|
"arrow_function",
|
|
167
|
-
# Java/C#/Kotlin/Scala
|
|
167
|
+
# Java/C#/Kotlin/Scala / Go / PHP all share `method_declaration`
|
|
168
168
|
"method_declaration",
|
|
169
169
|
"constructor_declaration",
|
|
170
|
-
# Go
|
|
171
|
-
"function_declaration",
|
|
172
|
-
"method_declaration",
|
|
173
170
|
# Rust
|
|
174
171
|
"function_item",
|
|
175
|
-
# C/C++
|
|
176
|
-
"function_definition",
|
|
177
172
|
# Ruby
|
|
178
173
|
"method",
|
|
179
|
-
# PHP
|
|
180
|
-
"function_definition",
|
|
181
|
-
"method_declaration",
|
|
182
|
-
# Swift
|
|
183
|
-
"function_declaration",
|
|
184
174
|
}
|
|
185
175
|
)
|
|
186
176
|
|
|
@@ -28,20 +28,13 @@ _CONTROL_FLOW = {
|
|
|
28
28
|
"with_statement",
|
|
29
29
|
"match_statement",
|
|
30
30
|
# JS/TS
|
|
31
|
-
"if_statement",
|
|
32
|
-
"for_statement",
|
|
33
31
|
"for_in_statement",
|
|
34
|
-
"while_statement",
|
|
35
32
|
"do_statement",
|
|
36
33
|
"switch_statement",
|
|
37
|
-
"try_statement",
|
|
38
34
|
"catch_clause",
|
|
39
35
|
# Java/C#/Go/Rust
|
|
40
|
-
"for_statement",
|
|
41
36
|
"enhanced_for_statement",
|
|
42
37
|
"foreach_statement",
|
|
43
|
-
"while_statement",
|
|
44
|
-
"do_statement",
|
|
45
38
|
"if_expression",
|
|
46
39
|
"match_expression",
|
|
47
40
|
# General
|