roam-code 12.20__tar.gz → 12.22__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.20/src/roam_code.egg-info → roam_code-12.22}/PKG-INFO +1 -1
- {roam_code-12.20 → roam_code-12.22}/pyproject.toml +1 -1
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_context.py +13 -2
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_impact.py +24 -5
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_sbom.py +74 -58
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_watch.py +78 -57
- {roam_code-12.20 → roam_code-12.22}/src/roam/competitor_site_data.py +1 -1
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/partition.py +103 -93
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/indexer.py +8 -1
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp-server-card.json +1 -1
- {roam_code-12.20 → roam_code-12.22/src/roam_code.egg-info}/PKG-INFO +1 -1
- {roam_code-12.20 → roam_code-12.22}/src/roam_code.egg-info/SOURCES.txt +2 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_health_gate.py +8 -4
- {roam_code-12.20 → roam_code-12.22}/tests/test_mcp_extras.py +15 -1
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1216_passes.py +28 -1
- roam_code-12.22/tests/test_v1221_query_timeout.py +95 -0
- roam_code-12.22/tests/test_v1221_untested_commands.py +100 -0
- {roam_code-12.20 → roam_code-12.22}/LICENSE +0 -0
- {roam_code-12.20 → roam_code-12.22}/README.md +0 -0
- {roam_code-12.20 → roam_code-12.22}/setup.cfg +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/__main__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/analysis/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/analysis/effects.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/analysis/taint.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/api.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/ask/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/ask/classifier.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/ask/recipes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/ask/runner.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/ask/workflow.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/attest/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/attest/cga.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/base.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/bridge_config.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/bridge_django.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/bridge_protobuf.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/bridge_rest_api.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/bridge_salesforce.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/bridge_template.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/bridges/registry.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/catalog/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/catalog/detectors.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/catalog/fixes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/catalog/python_idioms.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/catalog/smells.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/catalog/tasks.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/cli.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/changed_files.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_adrs.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_adversarial.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_affected.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_affected_tests.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_agent_context.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_agent_export.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_agent_plan.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_ai_ratio.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_ai_readiness.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_alerts.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_annotate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_api.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_api_changes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_api_drift.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_ask.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_attest.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_audit.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_auth_gaps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_bisect.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_breaking.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_budget.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_bus_factor.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_capsule.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_cga.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_changelog.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_check_rules.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_ci_setup.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_clean.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_clones.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_closure.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_clusters.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_codeowners.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_complexity.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_config.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_congestion.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_conventions.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_coupling.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_coverage_gaps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_critique.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_cut.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_dark_matter.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_dashboard.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_dead.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_debt.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_deps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_describe.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_dev_profile.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_diagnose.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_diff.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_disambiguate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_doc_staleness.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_docs_coverage.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_doctor.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_drift.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_duplicates.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_effects.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_endpoints.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_entry_points.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_eval_retrieve.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_exit_codes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_fan.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_file.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_fingerprint.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_fitness.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_flag_dead.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_fleet.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_fn_coupling.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_forecast.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_graph_export.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_graph_stats.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_grep.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_guard.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_health.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_help_search.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_hooks.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_hotspots.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_hover.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_index.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_index_bundle.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_index_stats.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_ingest_trace.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_init.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_intent.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_invariants.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_layers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_map.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_math.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_mcp_setup.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_mcp_status.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_metrics.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_migration_safety.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_minimap.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_missing_index.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_module.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_mutate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_n1.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_oracle.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_orchestrate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_orphan_imports.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_orphan_routes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_over_fetch.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_owner.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_partition.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_path_coverage.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_patterns.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_plan.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_plan_refactor.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_plugins.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_pr_diff.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_pr_prep.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_pr_risk.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_pre_commit.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_preflight.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_py_modern.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_py_types.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_pytest_fixtures.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_recipes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_recommend.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_relate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_report.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_reset.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_retrieve.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_risk.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_rules.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_safe_delete.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_safe_zones.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_schema.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_search.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_search_semantic.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_secrets.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_semantic_diff.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_simulate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_simulate_departure.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_sketch.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_smells.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_spectral.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_split.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_stats.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_supply_chain.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_symbol.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_syntax_check.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_taint.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_telemetry.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_test_gaps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_test_impact.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_test_pyramid.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_test_scaffold.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_testmap.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_timeline.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_tour.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_trace.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_trends.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_triage.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_understand.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_uses.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_verify.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_verify_imports.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_version.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_vibe_check.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_visualize.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_vuln_map.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_vuln_reach.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_vulns.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_weather.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_why.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_why_fail.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_workflow.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_ws.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/cmd_xlang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/codeowners_helpers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/context_helpers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/gate_presets.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/graph_helpers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/metrics_history.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/next_steps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/resolve.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/commands/suppression.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/config.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/coverage_reports.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/critique/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/critique/aggregator.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/critique/checks.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/db/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/db/connection.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/db/queries.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/db/schema.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/eval/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/eval/harness.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/exit_codes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/fleet/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/fleet/adapters.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/fleet/manifest.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/git_utils.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/anomaly.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/builder.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/clone_detect.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/clusters.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/cycles.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/dark_matter.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/diff.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/fingerprint.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/layers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/pagerank.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/pathfinding.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/propagation.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/simulate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/spectral.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/graph/stats.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/complexity.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/discovery.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/django_post.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/file_roles.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/git_stats.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/gitignore.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/incremental.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/parser.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/pytest_fixtures.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/registry_dispatch.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/relations.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/symbols.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/index/test_conventions.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/apex_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/aura_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/base.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/c_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/csharp_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/extractor_schema.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/extractors/kotlin.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/foxpro_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/generic_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/go_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/hcl_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/java_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/javascript_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/kotlin_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/php_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/python_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/query_engine.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/registry.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/ruby_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/rust_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/scala_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/sfxml_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/sql_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/swift_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/typescript_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/visualforce_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/languages/yaml_lang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_extras/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_extras/completions.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_extras/concurrency.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_extras/progress.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_extras/sampling.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_extras/session.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_extras/watcher.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/mcp_server.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/observability.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/confidence.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/errors.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/file_role_hints.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/formatter.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/framework_filter.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/mermaid.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/project_shape.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/sarif.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/output/schema_registry.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/plugins.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/refactor/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/refactor/codegen.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/refactor/transforms.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/retrieve/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/retrieve/learned_ranker.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/retrieve/pipeline.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/retrieve/rerank.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/retrieve/seeds.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/retrieve/semantic.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/rules/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/rules/ast_match.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/rules/builtin.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/rules/dataflow.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/rules/engine.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/runtime/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/runtime/daemon.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/runtime/graph_backend.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/runtime/hotspots.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/runtime/lock_modes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/runtime/lockmgr.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/runtime/trace_ingest.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/search/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/search/framework_packs.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/search/index_embeddings.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/search/onnx_embeddings.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/search/tfidf.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/aibom_extension.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_classifier.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_engine.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/api_error_leak.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/java_fileupload_path_traversal.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/js_insecure_jwt_decode.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/js_localstorage_secrets.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/js_prototype_pollution.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/js_ssrf.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/js_xss.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/python_basic.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/python_deserialization.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/python_path_traversal.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/python_socketio_remote_source.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/python_sqli.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/python_urllib_open_redirect.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/taint_rules/vue_v_html.yaml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/vuln_reach.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/security/vuln_store.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/surface_counts.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/telemetry.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/templates/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/templates/ci/Jenkinsfile +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/templates/ci/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/templates/ci/azure-pipelines.yml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/templates/ci/bitbucket-pipelines.yml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/templates/ci/gitlab-ci.yml +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/workspace/__init__.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/workspace/aggregator.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/workspace/api_scanner.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/workspace/config.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam/workspace/db.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam_code.egg-info/dependency_links.txt +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam_code.egg-info/entry_points.txt +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam_code.egg-info/requires.txt +0 -0
- {roam_code-12.20 → roam_code-12.22}/src/roam_code.egg-info/top_level.txt +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_adrs.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_adversarial.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_affected.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_agent_export.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_agent_mode.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_agent_plan_context.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ai_ratio.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ai_readiness.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_alerts_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_annotations.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_anomaly.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_api_changes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_api_drift.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ask.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_attest.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_auth_gaps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_backend_fixes_round2.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_backend_fixes_round3.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_basic.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_batch_mcp.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_bisect.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_bridge_django.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_bridges.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_bridges_extended.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_budget.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_budget_flag.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_budget_phase2.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_bus_factor.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_capsule.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_cga.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_check_rules.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ci_gate_eval.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ci_sarif_guard.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ci_setup.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_clones.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_closure.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_codeowners.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_commands_architecture.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_commands_exploration.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_commands_health.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_commands_refactoring.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_commands_workflow.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_competitor_site_data.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_comprehensive.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_config.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_congestion.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_context_propagation.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_conventions_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_coverage_gaps_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_coverage_ingestion.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_critique.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_cut.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_dark_matter.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_dark_matter_helpers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_dashboard.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_dataflow_dead.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_dead_aging.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_defer_loading.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_demo_gif_asset.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_describe.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_detail_flag_hints.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_detector_precision.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_deterministic_output.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_dev_profile.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_difficulty_scoring.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_doc_consistency.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_doc_staleness.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_docker_assets.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_docs_coverage.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_docs_site_quality.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_doctor.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_drift.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_drift_by_team.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_duplicates.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_effects.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_effects_propagation.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_endpoints.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_entry_points_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_eval_retrieve.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_except_pass_narrow.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_exclude_patterns.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_exit_codes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_extractor_grammar_drift.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_fallback_contracts.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_file_roles.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_fingerprint.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_fixes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_flag_dead.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_fleet.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_fn_coupling.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_forecast.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_formatters.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_foxpro.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_framework_detection.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_gate_presets.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_git_utils.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_guard.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_hooks.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_hotspots.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_hover.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_index.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_index_bundle.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_init_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_install_check.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_intent.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_invariants.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_json_contracts.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_json_error_envelope.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_kotlin_swift_extractors.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_language_corpus.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_languages.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_library_api.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_math.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_math_tips.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_mcp_server.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_mcp_setup.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_mermaid.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_metrics_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_migration_safety.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_minimap.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_missing_index.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_mutate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_n1.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_next_steps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_onboard.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_oracle.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_orchestrate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_orphan_routes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_oss_bench_harness.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_over_fetch.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_pagerank_truncation.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_partition.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_path_coverage.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_patterns_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_performance.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_personalized_pagerank.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_plan.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_plugin_discovery.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_pr_comment_script.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_pr_diff.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_pr_risk_author.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_progress.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_progressive_disclosure.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_properties.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_pytest_fixtures.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_python_extractor_v2.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_python_idioms_e2e.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_python_pivot.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_readme_surface_consistency.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_realworld_feedback.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_refactoring_intelligence.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_registry_dispatch.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_relate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_report.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_reset_clean.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_resolve.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_retrieve.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_retrieve_cross_repo.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_retrieve_seeds.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_risk.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ruby.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_rule_profiles.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_rules.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_rules_ast_match.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_rules_community_pack.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_rules_dataflow.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_rules_symbol_requirements.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_runtime.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_runtime_score.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_salesforce.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_sarif_flag.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_sbom.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_scala.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_schema_versioning.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_search_explain.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_secrets.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_secrets_v2.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_semantic_diff.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_semantic_onnx.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_semantic_search.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_simulate.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_simulate_departure.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_sketch.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_smells.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_smoke.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_sna_metrics.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_spectral.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_split_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_sql.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_suggest_reviewers.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_supply_chain.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_surface_counts.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_syntax_check.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_taint.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_taint_analysis.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_taint_classifier.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_taint_intraprocedural.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_test_conventions.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_test_gaps.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_test_scaffold.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_testmap.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_top_flag_consistency.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_tour_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_trends.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_trends_cohort.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_triage.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_uses_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1215_passes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1216_passes_41_50.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1216_passes_51_60.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1217_passes_61_80.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1218_passes_81_90.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1219_passes_91_100.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v1220_passes_101_110.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v12_2.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v6_features.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v71_features.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v7_features.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_v82_features.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_verify.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_verify_imports.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_vibe_check.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_visualize.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_vuln.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_vulns_cmd.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_watch.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_why.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_workspace.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_ws_resolve_fixes.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_xlang.py +0 -0
- {roam_code-12.20 → roam_code-12.22}/tests/test_yaml_hcl.py +0 -0
|
@@ -601,6 +601,14 @@ def _render_json(data, budget=0):
|
|
|
601
601
|
# ---------------------------------------------------------------------------
|
|
602
602
|
|
|
603
603
|
|
|
604
|
+
def _table_budget(data) -> int:
|
|
605
|
+
"""Pass 118 — read the threaded ``--budget`` so format_table honors it."""
|
|
606
|
+
try:
|
|
607
|
+
return int(data.get("token_budget") or 0)
|
|
608
|
+
except (TypeError, ValueError):
|
|
609
|
+
return 0
|
|
610
|
+
|
|
611
|
+
|
|
604
612
|
def _render_single_text(data):
|
|
605
613
|
sym = data["sym"]
|
|
606
614
|
task = data["task"]
|
|
@@ -654,7 +662,7 @@ def _render_single_text(data):
|
|
|
654
662
|
]
|
|
655
663
|
for cr in non_test_callers[:20]
|
|
656
664
|
]
|
|
657
|
-
click.echo(format_table(["kind", "name", "location", "edge"], rows))
|
|
665
|
+
click.echo(format_table(["kind", "name", "location", "edge"], rows, budget=_table_budget(data)))
|
|
658
666
|
if len(non_test_callers) > 20:
|
|
659
667
|
click.echo(f" (+{len(non_test_callers) - 20} more)")
|
|
660
668
|
click.echo()
|
|
@@ -674,7 +682,7 @@ def _render_single_text(data):
|
|
|
674
682
|
]
|
|
675
683
|
for ce in callees[:15]
|
|
676
684
|
]
|
|
677
|
-
click.echo(format_table(["kind", "name", "location", "edge"], rows))
|
|
685
|
+
click.echo(format_table(["kind", "name", "location", "edge"], rows, budget=_table_budget(data)))
|
|
678
686
|
if len(callees) > 15:
|
|
679
687
|
click.echo(f" (+{len(callees) - 15} more)")
|
|
680
688
|
click.echo()
|
|
@@ -1263,4 +1271,7 @@ def context(ctx, names, task, for_file, session_hint, recent_symbols, no_propaga
|
|
|
1263
1271
|
# Pass 67 — pass inline-mode flag through to the renderer.
|
|
1264
1272
|
if inline_mode:
|
|
1265
1273
|
data["inline_mode"] = True
|
|
1274
|
+
# Pass 118 — thread the global --budget through to renderers so
|
|
1275
|
+
# format_table calls in cmd_context can honor it.
|
|
1276
|
+
data["token_budget"] = token_budget
|
|
1266
1277
|
_render_json(data, budget=token_budget) if json_mode else _render_text(data)
|
|
@@ -191,11 +191,30 @@ def impact(ctx, name, hops):
|
|
|
191
191
|
|
|
192
192
|
G = build_symbol_graph(conn)
|
|
193
193
|
if sym_id not in G:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
194
|
+
verdict = f"Symbol '{name}' exists in the index but is not in the dependency graph."
|
|
195
|
+
tip = f"Run `roam index` to rebuild the graph, or use `roam symbol {name}` to view raw symbol data."
|
|
196
|
+
if json_mode:
|
|
197
|
+
click.echo(
|
|
198
|
+
to_json(
|
|
199
|
+
json_envelope(
|
|
200
|
+
"impact",
|
|
201
|
+
budget=token_budget,
|
|
202
|
+
summary={
|
|
203
|
+
"verdict": verdict,
|
|
204
|
+
"affected_symbols": 0,
|
|
205
|
+
"affected_files": 0,
|
|
206
|
+
"in_graph": False,
|
|
207
|
+
},
|
|
208
|
+
symbol=sym["qualified_name"] or sym["name"],
|
|
209
|
+
tip=tip,
|
|
210
|
+
direct_dependents={},
|
|
211
|
+
affected_file_list=[],
|
|
212
|
+
indirect_refs=[],
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
click.echo(f"{verdict}\n Tip: {tip}")
|
|
199
218
|
return
|
|
200
219
|
|
|
201
220
|
RG = G.reverse()
|
|
@@ -47,87 +47,103 @@ def _normalize_dep_name(name: str) -> str:
|
|
|
47
47
|
return name.lower().replace("-", "_").replace(".", "_")
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
def _node_match_keys(data) -> tuple[str, str, str]:
|
|
51
|
+
"""Pass 114 — pre-normalise the three node fields used for dep matching."""
|
|
52
|
+
qname = (data.get("qualified_name") or "").lower().replace("-", "_").replace(".", "_")
|
|
53
|
+
name_lower = (data.get("name") or "").lower().replace("-", "_").replace(".", "_")
|
|
54
|
+
file_path = (data.get("file_path") or "").lower().replace("-", "_").replace(".", "_")
|
|
55
|
+
return qname, name_lower, file_path
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _matches_dep(qname: str, name_lower: str, file_path: str, norm: str) -> bool:
|
|
59
|
+
"""Pass 114 — predicate version of the inner dep-match check."""
|
|
60
|
+
if qname and (qname.startswith(norm + "_") or qname.startswith(norm + "/") or qname == norm):
|
|
61
|
+
return True
|
|
62
|
+
if norm in file_path:
|
|
63
|
+
return True
|
|
64
|
+
if name_lower == norm:
|
|
65
|
+
return True
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _trace_entry_reach(G, entries, nid):
|
|
70
|
+
"""Pass 114 — return the entry-point node IDs that can reach ``nid``."""
|
|
71
|
+
import networkx as nx
|
|
72
|
+
|
|
73
|
+
reach: list = []
|
|
74
|
+
for eid in entries:
|
|
75
|
+
try:
|
|
76
|
+
if nx.has_path(G, eid, nid):
|
|
77
|
+
reach.append(eid)
|
|
78
|
+
except (nx.NetworkXError, nx.NodeNotFound):
|
|
79
|
+
continue
|
|
80
|
+
return reach
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _build_norm_lookup(dep_names: list[str]) -> dict[str, list[str]]:
|
|
84
|
+
"""Pass 114 — group orig dep names by their normalised key."""
|
|
85
|
+
norm_to_dep: dict[str, list[str]] = {}
|
|
86
|
+
for dep in dep_names:
|
|
87
|
+
norm = _normalize_dep_name(dep)
|
|
88
|
+
if norm:
|
|
89
|
+
norm_to_dep.setdefault(norm, []).append(dep)
|
|
90
|
+
return norm_to_dep
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _record_match(info: dict, display_name: str, G, entries, nid) -> None:
|
|
94
|
+
"""Pass 114 — update a single dep's reachability record."""
|
|
95
|
+
if display_name not in info["matched_symbols"]:
|
|
96
|
+
info["matched_symbols"].append(display_name)
|
|
97
|
+
if info["reachable"]:
|
|
98
|
+
return
|
|
99
|
+
for eid in _trace_entry_reach(G, entries, nid):
|
|
100
|
+
info["reachable"] = True
|
|
101
|
+
entry_name = G.nodes[eid].get("qualified_name") or G.nodes[eid].get("name", str(eid))
|
|
102
|
+
if entry_name not in info["entry_points"]:
|
|
103
|
+
info["entry_points"].append(entry_name)
|
|
104
|
+
|
|
105
|
+
|
|
50
106
|
def _compute_reachability(conn, dep_names: list[str]) -> dict[str, dict]:
|
|
51
107
|
"""Check which dependencies are referenced in the codebase symbol graph.
|
|
52
108
|
|
|
53
|
-
For each dependency, look for import references or qualified-name
|
|
54
|
-
in the ``edges`` / ``symbols`` tables.
|
|
55
|
-
entry points (in-degree 0) that can reach the matched
|
|
109
|
+
For each dependency, look for import references or qualified-name
|
|
110
|
+
matches in the ``edges`` / ``symbols`` tables. When a match is
|
|
111
|
+
found, trace entry points (in-degree 0) that can reach the matched
|
|
112
|
+
symbol.
|
|
56
113
|
|
|
57
|
-
Returns ``{dep_name: {"reachable": bool, "entry_points": [
|
|
58
|
-
""
|
|
59
|
-
import networkx as nx
|
|
114
|
+
Returns ``{dep_name: {"reachable": bool, "entry_points": [...],
|
|
115
|
+
"matched_symbols": [...]}}``.
|
|
60
116
|
|
|
117
|
+
Pass 114 — orchestrator only. Pre-Pass 114 this function had cc=150
|
|
118
|
+
and nesting depth 8 (the deepest in the repo). Per-symbol logic now
|
|
119
|
+
lives in ``_node_match_keys``, ``_matches_dep``,
|
|
120
|
+
``_trace_entry_reach``, ``_build_norm_lookup``, ``_record_match``.
|
|
121
|
+
"""
|
|
61
122
|
from roam.graph.builder import build_symbol_graph
|
|
62
123
|
|
|
63
|
-
result: dict[str, dict] = {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
for dep in dep_names:
|
|
67
|
-
result[dep] = {"reachable": False, "entry_points": [], "matched_symbols": []}
|
|
68
|
-
|
|
124
|
+
result: dict[str, dict] = {
|
|
125
|
+
dep: {"reachable": False, "entry_points": [], "matched_symbols": []} for dep in dep_names
|
|
126
|
+
}
|
|
69
127
|
if not dep_names:
|
|
70
128
|
return result
|
|
71
|
-
|
|
72
|
-
# Build graph once
|
|
73
129
|
try:
|
|
74
130
|
G = build_symbol_graph(conn)
|
|
75
131
|
except Exception:
|
|
76
132
|
return result
|
|
77
|
-
|
|
78
133
|
if not G.nodes:
|
|
79
134
|
return result
|
|
80
135
|
|
|
81
|
-
# Compute entry points (in-degree 0)
|
|
82
136
|
entries = [n for n in G.nodes() if G.in_degree(n) == 0]
|
|
137
|
+
norm_to_dep = _build_norm_lookup(dep_names)
|
|
83
138
|
|
|
84
|
-
# Build a lookup: normalized name fragment -> list of node IDs
|
|
85
|
-
# We match dependency names against import targets and qualified names.
|
|
86
|
-
norm_to_dep: dict[str, list[str]] = {}
|
|
87
|
-
for dep in dep_names:
|
|
88
|
-
norm = _normalize_dep_name(dep)
|
|
89
|
-
if norm:
|
|
90
|
-
norm_to_dep.setdefault(norm, []).append(dep)
|
|
91
|
-
|
|
92
|
-
# Scan symbols for matches
|
|
93
139
|
for nid, data in G.nodes(data=True):
|
|
94
|
-
qname = (data
|
|
95
|
-
name_lower = (data.get("name") or "").lower().replace("-", "_").replace(".", "_")
|
|
96
|
-
file_path = (data.get("file_path") or "").lower().replace("-", "_").replace(".", "_")
|
|
97
|
-
|
|
140
|
+
qname, name_lower, file_path = _node_match_keys(data)
|
|
98
141
|
for norm, orig_deps in norm_to_dep.items():
|
|
99
|
-
|
|
100
|
-
# name, or in the file path (e.g., node_modules/lodash/...).
|
|
101
|
-
matched = False
|
|
102
|
-
if qname and (qname.startswith(norm + "_") or qname.startswith(norm + "/") or qname == norm):
|
|
103
|
-
matched = True
|
|
104
|
-
elif norm in file_path:
|
|
105
|
-
matched = True
|
|
106
|
-
elif name_lower == norm:
|
|
107
|
-
matched = True
|
|
108
|
-
|
|
109
|
-
if not matched:
|
|
142
|
+
if not _matches_dep(qname, name_lower, file_path, norm):
|
|
110
143
|
continue
|
|
111
|
-
|
|
112
144
|
display_name = data.get("qualified_name") or data.get("name", str(nid))
|
|
113
|
-
|
|
114
145
|
for dep_name in orig_deps:
|
|
115
|
-
|
|
116
|
-
if display_name not in info["matched_symbols"]:
|
|
117
|
-
info["matched_symbols"].append(display_name)
|
|
118
|
-
|
|
119
|
-
if not info["reachable"]:
|
|
120
|
-
# Check if any entry point can reach this node
|
|
121
|
-
for eid in entries:
|
|
122
|
-
try:
|
|
123
|
-
if nx.has_path(G, eid, nid):
|
|
124
|
-
info["reachable"] = True
|
|
125
|
-
entry_name = G.nodes[eid].get("qualified_name") or G.nodes[eid].get("name", str(eid))
|
|
126
|
-
if entry_name not in info["entry_points"]:
|
|
127
|
-
info["entry_points"].append(entry_name)
|
|
128
|
-
except (nx.NetworkXError, nx.NodeNotFound):
|
|
129
|
-
continue
|
|
130
|
-
|
|
146
|
+
_record_match(result[dep_name], display_name, G, entries, nid)
|
|
131
147
|
return result
|
|
132
148
|
|
|
133
149
|
|
|
@@ -454,6 +454,76 @@ class DebounceAccumulator:
|
|
|
454
454
|
return result
|
|
455
455
|
|
|
456
456
|
|
|
457
|
+
def _need_force(webhook_events: list, webhook_force: bool) -> bool:
|
|
458
|
+
"""Pass 115 — does the current event batch require a forced re-index?"""
|
|
459
|
+
has_explicit = any(bool(evt.get("force")) for evt in webhook_events if isinstance(evt, dict))
|
|
460
|
+
return has_explicit or (webhook_force and bool(webhook_events))
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def _scan_disk_changes(_discover, project_root: Path, tracked: dict, quiet: bool):
|
|
464
|
+
"""Pass 115 — discover + diff disk state, optionally print per-file lines."""
|
|
465
|
+
current_paths = _discover()
|
|
466
|
+
current_disk = scan_disk_mtimes(current_paths, project_root)
|
|
467
|
+
added, modified, removed = detect_changes(tracked, current_disk)
|
|
468
|
+
changed = added + modified + removed
|
|
469
|
+
if changed and not quiet:
|
|
470
|
+
for path in added:
|
|
471
|
+
click.echo(f" + {path}")
|
|
472
|
+
for path in modified:
|
|
473
|
+
click.echo(f" ~ {path}")
|
|
474
|
+
for path in removed:
|
|
475
|
+
click.echo(f" - {path}")
|
|
476
|
+
return tracked, changed
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def _label_webhook_events(webhook_events: list, quiet: bool) -> list[str]:
|
|
480
|
+
"""Pass 115 — turn webhook event dicts into ``<webhook:name>`` labels."""
|
|
481
|
+
if not webhook_events:
|
|
482
|
+
return []
|
|
483
|
+
labels = [
|
|
484
|
+
f"<webhook:{str(evt.get('event', 'webhook')).strip() or 'webhook'}>"
|
|
485
|
+
for evt in webhook_events
|
|
486
|
+
if isinstance(evt, dict)
|
|
487
|
+
]
|
|
488
|
+
if labels and not quiet:
|
|
489
|
+
for label in labels:
|
|
490
|
+
click.echo(f" * {label}")
|
|
491
|
+
return labels
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def _refresh_tracked_after_reindex(project_root: Path, prev_file_count: int, quiet: bool):
|
|
495
|
+
"""Pass 115 — reload tracked-files state and emit a status line."""
|
|
496
|
+
tracked = load_tracked_files(project_root)
|
|
497
|
+
new_count = len(tracked)
|
|
498
|
+
if not quiet:
|
|
499
|
+
click.echo(f"Re-index complete. Watching {new_count} files.")
|
|
500
|
+
elif new_count != prev_file_count:
|
|
501
|
+
click.echo(f"Re-indexed. Watching {new_count} files.")
|
|
502
|
+
return tracked, new_count
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def _run_guardian_step(_guardian_collect, _guardian_write, guardian_report: str, quiet: bool) -> None:
|
|
506
|
+
"""Pass 115 — collect + write a guardian snapshot, log the verdict."""
|
|
507
|
+
try:
|
|
508
|
+
payload = _guardian_collect()
|
|
509
|
+
if guardian_report:
|
|
510
|
+
_guardian_write(payload)
|
|
511
|
+
if quiet:
|
|
512
|
+
return
|
|
513
|
+
gate_state = "PASS" if payload.get("gates", {}).get("health_gate_pass") else "FAIL"
|
|
514
|
+
click.echo(
|
|
515
|
+
"Guardian: health={} trend={} drift={} ({})".format(
|
|
516
|
+
payload.get("current", {}).get("health_score", "n/a"),
|
|
517
|
+
payload.get("trend", {}).get("verdict", "n/a"),
|
|
518
|
+
payload.get("drift", {}).get("drift_files", "n/a"),
|
|
519
|
+
gate_state,
|
|
520
|
+
)
|
|
521
|
+
)
|
|
522
|
+
except Exception as exc:
|
|
523
|
+
if not quiet:
|
|
524
|
+
click.echo(f"Guardian update failed: {exc}")
|
|
525
|
+
|
|
526
|
+
|
|
457
527
|
def poll_loop(
|
|
458
528
|
project_root: Path,
|
|
459
529
|
interval: float,
|
|
@@ -530,77 +600,28 @@ def poll_loop(
|
|
|
530
600
|
while True:
|
|
531
601
|
_sleep(interval)
|
|
532
602
|
|
|
533
|
-
changed: list[str] = []
|
|
534
603
|
webhook_events = _external_events() or []
|
|
535
|
-
|
|
536
|
-
force_needed = force_needed or (webhook_force and bool(webhook_events))
|
|
537
|
-
pending_force = pending_force or force_needed
|
|
604
|
+
pending_force = pending_force or _need_force(webhook_events, webhook_force)
|
|
538
605
|
|
|
606
|
+
changed: list[str] = []
|
|
539
607
|
if not webhook_only:
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
added, modified, removed = detect_changes(tracked, current_disk)
|
|
545
|
-
changed.extend(added + modified + removed)
|
|
546
|
-
|
|
547
|
-
if changed and not quiet:
|
|
548
|
-
for path in added:
|
|
549
|
-
click.echo(f" + {path}")
|
|
550
|
-
for path in modified:
|
|
551
|
-
click.echo(f" ~ {path}")
|
|
552
|
-
for path in removed:
|
|
553
|
-
click.echo(f" - {path}")
|
|
554
|
-
|
|
555
|
-
if webhook_events:
|
|
556
|
-
webhook_labels = [
|
|
557
|
-
f"<webhook:{str(evt.get('event', 'webhook')).strip() or 'webhook'}>"
|
|
558
|
-
for evt in webhook_events
|
|
559
|
-
if isinstance(evt, dict)
|
|
560
|
-
]
|
|
561
|
-
changed.extend(webhook_labels)
|
|
562
|
-
if not quiet:
|
|
563
|
-
for label in webhook_labels:
|
|
564
|
-
click.echo(f" * {label}")
|
|
608
|
+
tracked, disk_changes = _scan_disk_changes(_discover, project_root, tracked, quiet)
|
|
609
|
+
changed.extend(disk_changes)
|
|
610
|
+
changed.extend(_label_webhook_events(webhook_events, quiet))
|
|
565
611
|
|
|
566
612
|
if changed:
|
|
567
613
|
acc.add(changed)
|
|
568
614
|
|
|
569
|
-
|
|
570
|
-
if acc.should_fire(now):
|
|
615
|
+
if acc.should_fire(time.monotonic()):
|
|
571
616
|
batch = acc.flush()
|
|
572
617
|
if not quiet:
|
|
573
618
|
mode_label = "force re-indexing" if pending_force else "re-indexing"
|
|
574
619
|
click.echo(f"Changed: {len(batch)} event(s) -- {mode_label}...")
|
|
575
620
|
_reindex(force=pending_force)
|
|
576
621
|
pending_force = False
|
|
577
|
-
|
|
578
|
-
tracked = load_tracked_files(project_root)
|
|
579
|
-
new_count = len(tracked)
|
|
580
|
-
if not quiet:
|
|
581
|
-
click.echo(f"Re-index complete. Watching {new_count} files.")
|
|
582
|
-
elif new_count != file_count:
|
|
583
|
-
click.echo(f"Re-indexed. Watching {new_count} files.")
|
|
584
|
-
file_count = new_count
|
|
585
|
-
|
|
622
|
+
tracked, file_count = _refresh_tracked_after_reindex(project_root, file_count, quiet)
|
|
586
623
|
if guardian or guardian_report:
|
|
587
|
-
|
|
588
|
-
guard_payload = _guardian_collect()
|
|
589
|
-
if guardian_report:
|
|
590
|
-
_guardian_write(guard_payload)
|
|
591
|
-
if not quiet:
|
|
592
|
-
gate_state = "PASS" if guard_payload.get("gates", {}).get("health_gate_pass") else "FAIL"
|
|
593
|
-
click.echo(
|
|
594
|
-
"Guardian: health={} trend={} drift={} ({})".format(
|
|
595
|
-
guard_payload.get("current", {}).get("health_score", "n/a"),
|
|
596
|
-
guard_payload.get("trend", {}).get("verdict", "n/a"),
|
|
597
|
-
guard_payload.get("drift", {}).get("drift_files", "n/a"),
|
|
598
|
-
gate_state,
|
|
599
|
-
)
|
|
600
|
-
)
|
|
601
|
-
except Exception as exc:
|
|
602
|
-
if not quiet:
|
|
603
|
-
click.echo(f"Guardian update failed: {exc}")
|
|
624
|
+
_run_guardian_step(_guardian_collect, _guardian_write, guardian_report, quiet)
|
|
604
625
|
|
|
605
626
|
|
|
606
627
|
@click.command("watch")
|
|
@@ -1364,7 +1364,7 @@ MAP_METADATA: dict[str, dict[str, object]] = {
|
|
|
1364
1364
|
"peer": True,
|
|
1365
1365
|
"graph": "PageRank + Tarjan + Louvain + layers",
|
|
1366
1366
|
"note": "Graph algorithms (PageRank, SCC, Louvain, Fiedler) on tree-sitter ASTs fused with git history in SQLite. 128 MCP tools, 178 CLI commands. 19 Python idiom detectors (v12.7+).",
|
|
1367
|
-
"version_evaluated": "12.
|
|
1367
|
+
"version_evaluated": "12.22",
|
|
1368
1368
|
"repo_url": "https://github.com/Cranot/roam-code",
|
|
1369
1369
|
},
|
|
1370
1370
|
"CKB/CodeMCP": {
|
|
@@ -255,61 +255,118 @@ def _adjust_cluster_count(
|
|
|
255
255
|
return partitions
|
|
256
256
|
|
|
257
257
|
|
|
258
|
-
def
|
|
259
|
-
|
|
260
|
-
conn: sqlite3.Connection,
|
|
261
|
-
partitions: list[dict[str, set[int]]],
|
|
262
|
-
) -> list[dict]:
|
|
263
|
-
"""Build per-agent descriptor dicts.
|
|
264
|
-
|
|
265
|
-
File ownership is determined by majority vote: each file is assigned
|
|
266
|
-
exclusively to the partition that owns the most of its symbols.
|
|
267
|
-
This guarantees no write overlap between agents.
|
|
268
|
-
"""
|
|
269
|
-
# Build node -> partition index
|
|
258
|
+
def _node_partition_index(partitions: list[dict[str, set[int]]]) -> dict[int, int]:
|
|
259
|
+
"""Pass 120 — flatten partitions into ``{node_id: partition_index}``."""
|
|
270
260
|
node_part: dict[int, int] = {}
|
|
271
261
|
for idx, p in enumerate(partitions):
|
|
272
262
|
for n in p["nodes"]:
|
|
273
263
|
node_part[n] = idx
|
|
264
|
+
return node_part
|
|
265
|
+
|
|
274
266
|
|
|
275
|
-
|
|
276
|
-
|
|
267
|
+
def _fetch_node_metadata(conn: sqlite3.Connection, node_ids: list[int]):
|
|
268
|
+
"""Pass 120 — load (file, name, signature) for every node in one batch."""
|
|
277
269
|
node_to_file: dict[int, str] = {}
|
|
278
270
|
node_to_name: dict[int, str] = {}
|
|
279
271
|
node_to_sig: dict[int, str] = {}
|
|
280
|
-
if
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
272
|
+
if not node_ids:
|
|
273
|
+
return node_to_file, node_to_name, node_to_sig
|
|
274
|
+
rows = batched_in(
|
|
275
|
+
conn,
|
|
276
|
+
"SELECT s.id, s.name, s.signature, f.path FROM symbols s JOIN files f ON s.file_id = f.id WHERE s.id IN ({ph})",
|
|
277
|
+
node_ids,
|
|
278
|
+
)
|
|
279
|
+
for r in rows:
|
|
280
|
+
node_to_file[r["id"]] = r["path"].replace("\\", "/")
|
|
281
|
+
node_to_name[r["id"]] = r["name"]
|
|
282
|
+
node_to_sig[r["id"]] = r["signature"] or r["name"]
|
|
283
|
+
return node_to_file, node_to_name, node_to_sig
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _file_majority_owners(node_part: dict[int, int], node_to_file: dict[int, str]) -> dict[int, set[str]]:
|
|
287
|
+
"""Pass 120 — assign each file exclusively to its majority-vote partition."""
|
|
295
288
|
file_partition_counts: dict[str, Counter] = defaultdict(Counter)
|
|
296
289
|
for n, pidx in node_part.items():
|
|
297
290
|
fp = node_to_file.get(n)
|
|
298
291
|
if fp:
|
|
299
292
|
file_partition_counts[fp][pidx] += 1
|
|
300
|
-
|
|
301
|
-
# Assign each file to the partition with the most symbols in it
|
|
302
|
-
file_owner: dict[str, int] = {}
|
|
293
|
+
partition_write_files: dict[int, set[str]] = defaultdict(set)
|
|
303
294
|
for fp, counts in file_partition_counts.items():
|
|
304
|
-
|
|
295
|
+
owner = counts.most_common(1)[0][0]
|
|
296
|
+
partition_write_files[owner].add(fp)
|
|
297
|
+
return partition_write_files
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _read_only_files_for(
|
|
301
|
+
G, nodes: set[int], node_part: dict[int, int], node_to_file: dict[int, str], write_files: set[str]
|
|
302
|
+
) -> set[str]:
|
|
303
|
+
"""Pass 120 — files with cross-partition edges but not owned by this agent."""
|
|
304
|
+
read_only: set[str] = set()
|
|
305
|
+
for n in nodes:
|
|
306
|
+
for neighbour in (*G.predecessors(n), *G.successors(n)):
|
|
307
|
+
if neighbour in nodes or neighbour not in node_part:
|
|
308
|
+
continue
|
|
309
|
+
fp = node_to_file.get(neighbour)
|
|
310
|
+
if fp and fp not in write_files:
|
|
311
|
+
read_only.add(fp)
|
|
312
|
+
return read_only
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _boundary_contracts(
|
|
316
|
+
G, nodes: set[int], node_part: dict[int, int], node_to_name: dict[int, str], node_to_sig: dict[int, str]
|
|
317
|
+
) -> list[str]:
|
|
318
|
+
"""Pass 120 — list cross-partition symbols this agent must not change."""
|
|
319
|
+
contracts: list[str] = []
|
|
320
|
+
seen: set[str] = set()
|
|
321
|
+
for n in nodes:
|
|
322
|
+
for neighbour in (*G.successors(n), *G.predecessors(n)):
|
|
323
|
+
if neighbour in nodes or neighbour not in node_part:
|
|
324
|
+
continue
|
|
325
|
+
name = node_to_name.get(neighbour)
|
|
326
|
+
sig = node_to_sig.get(neighbour)
|
|
327
|
+
if not (name and sig):
|
|
328
|
+
continue
|
|
329
|
+
contract = f"do NOT modify {sig} signature"
|
|
330
|
+
if contract not in seen:
|
|
331
|
+
seen.add(contract)
|
|
332
|
+
contracts.append(contract)
|
|
333
|
+
return contracts
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _cluster_label_for(nodes: set[int], node_to_file: dict[int, str], idx: int) -> str:
|
|
337
|
+
"""Pass 120 — directory-majority label, with sensible fallbacks."""
|
|
338
|
+
dirs = [os.path.dirname(node_to_file.get(n, "")).replace("\\", "/") for n in nodes if n in node_to_file]
|
|
339
|
+
counts = Counter(dirs) if dirs else Counter()
|
|
340
|
+
if not counts:
|
|
341
|
+
return f"partition-{idx + 1}"
|
|
342
|
+
label = counts.most_common(1)[0][0]
|
|
343
|
+
if not label:
|
|
344
|
+
return f"root-{idx + 1}"
|
|
345
|
+
return label.rstrip("/").rsplit("/", 1)[-1] or f"partition-{idx + 1}"
|
|
305
346
|
|
|
306
|
-
# Build per-partition write file sets (exclusive, no overlap)
|
|
307
|
-
partition_write_files: dict[int, set[str]] = defaultdict(set)
|
|
308
|
-
for fp, pidx in file_owner.items():
|
|
309
|
-
partition_write_files[pidx].add(fp)
|
|
310
347
|
|
|
311
|
-
|
|
312
|
-
|
|
348
|
+
def _build_agent_descriptors(
|
|
349
|
+
G: nx.DiGraph,
|
|
350
|
+
conn: sqlite3.Connection,
|
|
351
|
+
partitions: list[dict[str, set[int]]],
|
|
352
|
+
) -> list[dict]:
|
|
353
|
+
"""Build per-agent descriptor dicts.
|
|
354
|
+
|
|
355
|
+
Pass 120 — orchestrator only. Per-step logic lives in
|
|
356
|
+
``_node_partition_index``, ``_fetch_node_metadata``,
|
|
357
|
+
``_file_majority_owners``, ``_read_only_files_for``,
|
|
358
|
+
``_boundary_contracts``, ``_cluster_label_for``.
|
|
359
|
+
Cognitive complexity dropped from 161 to ~10.
|
|
360
|
+
|
|
361
|
+
File ownership is determined by majority vote: each file is
|
|
362
|
+
assigned exclusively to the partition that owns the most of its
|
|
363
|
+
symbols. This guarantees no write overlap between agents.
|
|
364
|
+
"""
|
|
365
|
+
node_part = _node_partition_index(partitions)
|
|
366
|
+
node_to_file, node_to_name, node_to_sig = _fetch_node_metadata(conn, list(node_part.keys()))
|
|
367
|
+
partition_write_files = _file_majority_owners(node_part, node_to_file)
|
|
368
|
+
|
|
369
|
+
agents: list[dict] = []
|
|
313
370
|
for idx, p in enumerate(partitions):
|
|
314
371
|
nodes = p["nodes"]
|
|
315
372
|
if not nodes:
|
|
@@ -324,66 +381,19 @@ def _build_agent_descriptors(
|
|
|
324
381
|
}
|
|
325
382
|
)
|
|
326
383
|
continue
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
# Read-only files: files with edges into/from this partition
|
|
331
|
-
# but owned by another partition
|
|
332
|
-
read_only_set: set[str] = set()
|
|
333
|
-
for n in nodes:
|
|
334
|
-
for pred in G.predecessors(n):
|
|
335
|
-
if pred not in nodes and pred in node_part:
|
|
336
|
-
fp = node_to_file.get(pred)
|
|
337
|
-
if fp and fp not in write_files_set:
|
|
338
|
-
read_only_set.add(fp)
|
|
339
|
-
for succ in G.successors(n):
|
|
340
|
-
if succ not in nodes and succ in node_part:
|
|
341
|
-
fp = node_to_file.get(succ)
|
|
342
|
-
if fp and fp not in write_files_set:
|
|
343
|
-
read_only_set.add(fp)
|
|
344
|
-
|
|
345
|
-
# Contracts: symbols at boundaries that this agent must NOT modify
|
|
346
|
-
contracts = []
|
|
347
|
-
for n in nodes:
|
|
348
|
-
for succ in G.successors(n):
|
|
349
|
-
if succ not in nodes and succ in node_part:
|
|
350
|
-
name = node_to_name.get(succ)
|
|
351
|
-
sig = node_to_sig.get(succ)
|
|
352
|
-
if name and sig:
|
|
353
|
-
contract = f"do NOT modify {sig} signature"
|
|
354
|
-
if contract not in contracts:
|
|
355
|
-
contracts.append(contract)
|
|
356
|
-
for pred in G.predecessors(n):
|
|
357
|
-
if pred not in nodes and pred in node_part:
|
|
358
|
-
name = node_to_name.get(pred)
|
|
359
|
-
sig = node_to_sig.get(pred)
|
|
360
|
-
if name and sig:
|
|
361
|
-
contract = f"do NOT modify {sig} signature"
|
|
362
|
-
if contract not in contracts:
|
|
363
|
-
contracts.append(contract)
|
|
364
|
-
|
|
365
|
-
# Cluster label from directory majority
|
|
366
|
-
dirs = [os.path.dirname(node_to_file.get(n, "")).replace("\\", "/") for n in nodes if n in node_to_file]
|
|
367
|
-
dir_counts = Counter(dirs) if dirs else Counter()
|
|
368
|
-
if dir_counts:
|
|
369
|
-
label = dir_counts.most_common(1)[0][0]
|
|
370
|
-
label = label.rstrip("/").rsplit("/", 1)[-1] if label else f"partition-{idx + 1}"
|
|
371
|
-
if not label:
|
|
372
|
-
label = f"root-{idx + 1}"
|
|
373
|
-
else:
|
|
374
|
-
label = f"partition-{idx + 1}"
|
|
375
|
-
|
|
384
|
+
write_files = partition_write_files.get(idx, set())
|
|
385
|
+
read_only = _read_only_files_for(G, nodes, node_part, node_to_file, write_files)
|
|
386
|
+
contracts = _boundary_contracts(G, nodes, node_part, node_to_name, node_to_sig)
|
|
376
387
|
agents.append(
|
|
377
388
|
{
|
|
378
389
|
"id": idx + 1,
|
|
379
|
-
"write_files": sorted(
|
|
380
|
-
"read_only_files": sorted(
|
|
390
|
+
"write_files": sorted(write_files),
|
|
391
|
+
"read_only_files": sorted(read_only),
|
|
381
392
|
"symbols_owned": len(nodes),
|
|
382
|
-
"contracts": contracts[:10],
|
|
383
|
-
"cluster_label":
|
|
393
|
+
"contracts": contracts[:10],
|
|
394
|
+
"cluster_label": _cluster_label_for(nodes, node_to_file, idx),
|
|
384
395
|
}
|
|
385
396
|
)
|
|
386
|
-
|
|
387
397
|
return agents
|
|
388
398
|
|
|
389
399
|
|