roam-code 11.1.3__tar.gz → 11.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. {roam_code-11.1.3/src/roam_code.egg-info → roam_code-11.2.0}/PKG-INFO +15 -8
  2. {roam_code-11.1.3 → roam_code-11.2.0}/README.md +14 -7
  3. {roam_code-11.1.3 → roam_code-11.2.0}/pyproject.toml +1 -1
  4. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/cli.py +3 -1
  5. roam_code-11.2.0/src/roam/commands/cmd_clones.py +163 -0
  6. roam_code-11.2.0/src/roam/graph/clone_detect.py +552 -0
  7. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/mcp_server.py +31 -0
  8. {roam_code-11.1.3 → roam_code-11.2.0/src/roam_code.egg-info}/PKG-INFO +15 -8
  9. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam_code.egg-info/SOURCES.txt +3 -0
  10. roam_code-11.2.0/tests/test_clones.py +400 -0
  11. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_surface_counts.py +6 -6
  12. {roam_code-11.1.3 → roam_code-11.2.0}/LICENSE +0 -0
  13. {roam_code-11.1.3 → roam_code-11.2.0}/setup.cfg +0 -0
  14. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/__init__.py +0 -0
  15. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/__main__.py +0 -0
  16. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/analysis/__init__.py +0 -0
  17. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/analysis/effects.py +0 -0
  18. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/analysis/taint.py +0 -0
  19. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/api.py +0 -0
  20. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/__init__.py +0 -0
  21. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/base.py +0 -0
  22. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/bridge_config.py +0 -0
  23. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/bridge_protobuf.py +0 -0
  24. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/bridge_rest_api.py +0 -0
  25. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/bridge_salesforce.py +0 -0
  26. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/bridge_template.py +0 -0
  27. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/bridges/registry.py +0 -0
  28. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/catalog/__init__.py +0 -0
  29. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/catalog/detectors.py +0 -0
  30. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/catalog/fixes.py +0 -0
  31. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/catalog/smells.py +0 -0
  32. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/catalog/tasks.py +0 -0
  33. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/__init__.py +0 -0
  34. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/changed_files.py +0 -0
  35. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_adrs.py +0 -0
  36. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_adversarial.py +0 -0
  37. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_affected.py +0 -0
  38. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_affected_tests.py +0 -0
  39. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_agent_context.py +0 -0
  40. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_agent_export.py +0 -0
  41. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_agent_plan.py +0 -0
  42. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_ai_ratio.py +0 -0
  43. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_ai_readiness.py +0 -0
  44. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_alerts.py +0 -0
  45. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_annotate.py +0 -0
  46. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_api_changes.py +0 -0
  47. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_api_drift.py +0 -0
  48. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_attest.py +0 -0
  49. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_auth_gaps.py +0 -0
  50. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_bisect.py +0 -0
  51. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_breaking.py +0 -0
  52. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_budget.py +0 -0
  53. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_bus_factor.py +0 -0
  54. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_capsule.py +0 -0
  55. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_check_rules.py +0 -0
  56. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_ci_setup.py +0 -0
  57. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_clean.py +0 -0
  58. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_closure.py +0 -0
  59. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_clusters.py +0 -0
  60. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_codeowners.py +0 -0
  61. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_complexity.py +0 -0
  62. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_config.py +0 -0
  63. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_congestion.py +0 -0
  64. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_context.py +0 -0
  65. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_conventions.py +0 -0
  66. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_coupling.py +0 -0
  67. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_coverage_gaps.py +0 -0
  68. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_cut.py +0 -0
  69. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_dark_matter.py +0 -0
  70. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_dashboard.py +0 -0
  71. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_dead.py +0 -0
  72. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_debt.py +0 -0
  73. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_deps.py +0 -0
  74. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_describe.py +0 -0
  75. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_dev_profile.py +0 -0
  76. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_diagnose.py +0 -0
  77. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_diff.py +0 -0
  78. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_doc_staleness.py +0 -0
  79. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_docs_coverage.py +0 -0
  80. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_doctor.py +0 -0
  81. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_drift.py +0 -0
  82. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_duplicates.py +0 -0
  83. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_effects.py +0 -0
  84. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_endpoints.py +0 -0
  85. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_entry_points.py +0 -0
  86. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_fan.py +0 -0
  87. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_file.py +0 -0
  88. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_fingerprint.py +0 -0
  89. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_fitness.py +0 -0
  90. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_flag_dead.py +0 -0
  91. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_fn_coupling.py +0 -0
  92. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_forecast.py +0 -0
  93. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_grep.py +0 -0
  94. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_guard.py +0 -0
  95. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_health.py +0 -0
  96. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_hooks.py +0 -0
  97. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_hotspots.py +0 -0
  98. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_impact.py +0 -0
  99. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_index.py +0 -0
  100. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_ingest_trace.py +0 -0
  101. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_init.py +0 -0
  102. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_intent.py +0 -0
  103. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_invariants.py +0 -0
  104. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_layers.py +0 -0
  105. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_map.py +0 -0
  106. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_math.py +0 -0
  107. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_mcp_setup.py +0 -0
  108. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_metrics.py +0 -0
  109. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_migration_safety.py +0 -0
  110. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_minimap.py +0 -0
  111. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_missing_index.py +0 -0
  112. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_module.py +0 -0
  113. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_mutate.py +0 -0
  114. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_n1.py +0 -0
  115. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_orchestrate.py +0 -0
  116. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_orphan_routes.py +0 -0
  117. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_over_fetch.py +0 -0
  118. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_owner.py +0 -0
  119. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_partition.py +0 -0
  120. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_path_coverage.py +0 -0
  121. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_patterns.py +0 -0
  122. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_plan.py +0 -0
  123. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_plan_refactor.py +0 -0
  124. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_pr_diff.py +0 -0
  125. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_pr_risk.py +0 -0
  126. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_preflight.py +0 -0
  127. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_relate.py +0 -0
  128. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_report.py +0 -0
  129. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_reset.py +0 -0
  130. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_risk.py +0 -0
  131. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_rules.py +0 -0
  132. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_safe_delete.py +0 -0
  133. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_safe_zones.py +0 -0
  134. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_sbom.py +0 -0
  135. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_schema.py +0 -0
  136. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_search.py +0 -0
  137. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_search_semantic.py +0 -0
  138. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_secrets.py +0 -0
  139. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_semantic_diff.py +0 -0
  140. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_simulate.py +0 -0
  141. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_simulate_departure.py +0 -0
  142. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_sketch.py +0 -0
  143. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_smells.py +0 -0
  144. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_spectral.py +0 -0
  145. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_split.py +0 -0
  146. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
  147. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
  148. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_supply_chain.py +0 -0
  149. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_symbol.py +0 -0
  150. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_syntax_check.py +0 -0
  151. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_test_gaps.py +0 -0
  152. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_test_scaffold.py +0 -0
  153. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_testmap.py +0 -0
  154. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_tour.py +0 -0
  155. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_trace.py +0 -0
  156. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_trends.py +0 -0
  157. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_triage.py +0 -0
  158. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_understand.py +0 -0
  159. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_uses.py +0 -0
  160. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_verify.py +0 -0
  161. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_verify_imports.py +0 -0
  162. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_vibe_check.py +0 -0
  163. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_visualize.py +0 -0
  164. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_vuln_map.py +0 -0
  165. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_vuln_reach.py +0 -0
  166. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_vulns.py +0 -0
  167. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_watch.py +0 -0
  168. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_weather.py +0 -0
  169. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_why.py +0 -0
  170. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_ws.py +0 -0
  171. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/cmd_xlang.py +0 -0
  172. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/codeowners_helpers.py +0 -0
  173. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/context_helpers.py +0 -0
  174. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/gate_presets.py +0 -0
  175. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/graph_helpers.py +0 -0
  176. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/metrics_history.py +0 -0
  177. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/next_steps.py +0 -0
  178. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/resolve.py +0 -0
  179. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/commands/suppression.py +0 -0
  180. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/competitor_site_data.py +0 -0
  181. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/coverage_reports.py +0 -0
  182. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/db/__init__.py +0 -0
  183. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/db/connection.py +0 -0
  184. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/db/queries.py +0 -0
  185. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/db/schema.py +0 -0
  186. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/exit_codes.py +0 -0
  187. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/__init__.py +0 -0
  188. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/anomaly.py +0 -0
  189. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/builder.py +0 -0
  190. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/clusters.py +0 -0
  191. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/cycles.py +0 -0
  192. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/dark_matter.py +0 -0
  193. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/diff.py +0 -0
  194. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/fingerprint.py +0 -0
  195. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/layers.py +0 -0
  196. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/pagerank.py +0 -0
  197. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/partition.py +0 -0
  198. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/pathfinding.py +0 -0
  199. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/propagation.py +0 -0
  200. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/simulate.py +0 -0
  201. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/spectral.py +0 -0
  202. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/graph/stats.py +0 -0
  203. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/__init__.py +0 -0
  204. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/complexity.py +0 -0
  205. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/discovery.py +0 -0
  206. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/file_roles.py +0 -0
  207. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/git_stats.py +0 -0
  208. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/gitignore.py +0 -0
  209. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/incremental.py +0 -0
  210. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/indexer.py +0 -0
  211. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/parser.py +0 -0
  212. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/relations.py +0 -0
  213. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/symbols.py +0 -0
  214. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/index/test_conventions.py +0 -0
  215. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/__init__.py +0 -0
  216. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/apex_lang.py +0 -0
  217. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/aura_lang.py +0 -0
  218. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/base.py +0 -0
  219. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/c_lang.py +0 -0
  220. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/csharp_lang.py +0 -0
  221. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/extractor_schema.py +0 -0
  222. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/foxpro_lang.py +0 -0
  223. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/generic_lang.py +0 -0
  224. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/go_lang.py +0 -0
  225. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/hcl_lang.py +0 -0
  226. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/java_lang.py +0 -0
  227. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/javascript_lang.py +0 -0
  228. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/kotlin_lang.py +0 -0
  229. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/php_lang.py +0 -0
  230. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/python_lang.py +0 -0
  231. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/query_engine.py +0 -0
  232. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/registry.py +0 -0
  233. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/ruby_lang.py +0 -0
  234. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/rust_lang.py +0 -0
  235. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/scala_lang.py +0 -0
  236. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/sfxml_lang.py +0 -0
  237. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/sql_lang.py +0 -0
  238. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/swift_lang.py +0 -0
  239. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/typescript_lang.py +0 -0
  240. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/visualforce_lang.py +0 -0
  241. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/languages/yaml_lang.py +0 -0
  242. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/output/__init__.py +0 -0
  243. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/output/formatter.py +0 -0
  244. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/output/mermaid.py +0 -0
  245. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/output/sarif.py +0 -0
  246. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/output/schema_registry.py +0 -0
  247. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/plugins.py +0 -0
  248. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/refactor/__init__.py +0 -0
  249. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/refactor/codegen.py +0 -0
  250. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/refactor/transforms.py +0 -0
  251. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/rules/__init__.py +0 -0
  252. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/rules/ast_match.py +0 -0
  253. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/rules/builtin.py +0 -0
  254. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/rules/dataflow.py +0 -0
  255. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/rules/engine.py +0 -0
  256. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/runtime/__init__.py +0 -0
  257. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/runtime/hotspots.py +0 -0
  258. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/runtime/trace_ingest.py +0 -0
  259. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/search/__init__.py +0 -0
  260. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/search/framework_packs.py +0 -0
  261. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/search/index_embeddings.py +0 -0
  262. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/search/onnx_embeddings.py +0 -0
  263. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/search/tfidf.py +0 -0
  264. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/security/__init__.py +0 -0
  265. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/security/vuln_reach.py +0 -0
  266. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/security/vuln_store.py +0 -0
  267. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/surface_counts.py +0 -0
  268. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/templates/__init__.py +0 -0
  269. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/templates/ci/__init__.py +0 -0
  270. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/workspace/__init__.py +0 -0
  271. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/workspace/aggregator.py +0 -0
  272. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/workspace/api_scanner.py +0 -0
  273. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/workspace/config.py +0 -0
  274. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam/workspace/db.py +0 -0
  275. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam_code.egg-info/dependency_links.txt +0 -0
  276. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam_code.egg-info/entry_points.txt +0 -0
  277. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam_code.egg-info/requires.txt +0 -0
  278. {roam_code-11.1.3 → roam_code-11.2.0}/src/roam_code.egg-info/top_level.txt +0 -0
  279. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_adrs.py +0 -0
  280. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_adversarial.py +0 -0
  281. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_affected.py +0 -0
  282. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_agent_export.py +0 -0
  283. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_agent_mode.py +0 -0
  284. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_agent_plan_context.py +0 -0
  285. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_ai_ratio.py +0 -0
  286. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_ai_readiness.py +0 -0
  287. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_alerts_cmd.py +0 -0
  288. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_annotations.py +0 -0
  289. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_anomaly.py +0 -0
  290. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_api_changes.py +0 -0
  291. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_api_drift.py +0 -0
  292. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_attest.py +0 -0
  293. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_auth_gaps.py +0 -0
  294. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_backend_fixes_round2.py +0 -0
  295. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_backend_fixes_round3.py +0 -0
  296. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_basic.py +0 -0
  297. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_batch_mcp.py +0 -0
  298. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_bisect.py +0 -0
  299. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_bridges.py +0 -0
  300. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_bridges_extended.py +0 -0
  301. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_budget.py +0 -0
  302. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_budget_flag.py +0 -0
  303. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_budget_phase2.py +0 -0
  304. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_bus_factor.py +0 -0
  305. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_capsule.py +0 -0
  306. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_check_rules.py +0 -0
  307. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_ci_gate_eval.py +0 -0
  308. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_ci_sarif_guard.py +0 -0
  309. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_ci_setup.py +0 -0
  310. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_closure.py +0 -0
  311. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_codeowners.py +0 -0
  312. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_commands_architecture.py +0 -0
  313. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_commands_exploration.py +0 -0
  314. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_commands_health.py +0 -0
  315. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_commands_refactoring.py +0 -0
  316. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_commands_workflow.py +0 -0
  317. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_competitor_site_data.py +0 -0
  318. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_comprehensive.py +0 -0
  319. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_congestion.py +0 -0
  320. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_context_propagation.py +0 -0
  321. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_conventions_cmd.py +0 -0
  322. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_coverage_gaps_cmd.py +0 -0
  323. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_coverage_ingestion.py +0 -0
  324. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_cut.py +0 -0
  325. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_dark_matter.py +0 -0
  326. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_dashboard.py +0 -0
  327. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_dataflow_dead.py +0 -0
  328. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_dead_aging.py +0 -0
  329. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_defer_loading.py +0 -0
  330. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_demo_gif_asset.py +0 -0
  331. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_describe.py +0 -0
  332. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_deterministic_output.py +0 -0
  333. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_dev_profile.py +0 -0
  334. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_difficulty_scoring.py +0 -0
  335. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_doc_staleness.py +0 -0
  336. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_docker_assets.py +0 -0
  337. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_docs_coverage.py +0 -0
  338. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_docs_site_quality.py +0 -0
  339. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_doctor.py +0 -0
  340. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_drift.py +0 -0
  341. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_duplicates.py +0 -0
  342. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_effects.py +0 -0
  343. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_effects_propagation.py +0 -0
  344. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_endpoints.py +0 -0
  345. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_entry_points_cmd.py +0 -0
  346. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_exclude_patterns.py +0 -0
  347. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_exit_codes.py +0 -0
  348. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_file_roles.py +0 -0
  349. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_fingerprint.py +0 -0
  350. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_fixes.py +0 -0
  351. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_flag_dead.py +0 -0
  352. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_fn_coupling.py +0 -0
  353. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_forecast.py +0 -0
  354. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_formatters.py +0 -0
  355. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_foxpro.py +0 -0
  356. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_framework_detection.py +0 -0
  357. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_gate_presets.py +0 -0
  358. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_guard.py +0 -0
  359. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_health_gate.py +0 -0
  360. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_hooks.py +0 -0
  361. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_hotspots.py +0 -0
  362. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_index.py +0 -0
  363. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_init_cmd.py +0 -0
  364. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_install_check.py +0 -0
  365. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_intent.py +0 -0
  366. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_invariants.py +0 -0
  367. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_json_contracts.py +0 -0
  368. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_kotlin_swift_extractors.py +0 -0
  369. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_language_corpus.py +0 -0
  370. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_languages.py +0 -0
  371. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_library_api.py +0 -0
  372. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_math.py +0 -0
  373. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_math_tips.py +0 -0
  374. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_mcp_server.py +0 -0
  375. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_mcp_setup.py +0 -0
  376. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_mermaid.py +0 -0
  377. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_metrics_cmd.py +0 -0
  378. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_migration_safety.py +0 -0
  379. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_minimap.py +0 -0
  380. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_missing_index.py +0 -0
  381. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_mutate.py +0 -0
  382. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_n1.py +0 -0
  383. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_next_steps.py +0 -0
  384. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_onboard.py +0 -0
  385. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_orchestrate.py +0 -0
  386. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_orphan_routes.py +0 -0
  387. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_oss_bench_harness.py +0 -0
  388. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_over_fetch.py +0 -0
  389. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_pagerank_truncation.py +0 -0
  390. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_partition.py +0 -0
  391. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_path_coverage.py +0 -0
  392. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_patterns_cmd.py +0 -0
  393. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_performance.py +0 -0
  394. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_plan.py +0 -0
  395. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_plugin_discovery.py +0 -0
  396. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_pr_comment_script.py +0 -0
  397. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_pr_diff.py +0 -0
  398. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_pr_risk_author.py +0 -0
  399. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_progress.py +0 -0
  400. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_progressive_disclosure.py +0 -0
  401. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_properties.py +0 -0
  402. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_python_extractor_v2.py +0 -0
  403. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_readme_surface_consistency.py +0 -0
  404. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_refactoring_intelligence.py +0 -0
  405. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_relate.py +0 -0
  406. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_report.py +0 -0
  407. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_reset_clean.py +0 -0
  408. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_resolve.py +0 -0
  409. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_risk.py +0 -0
  410. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_ruby.py +0 -0
  411. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_rule_profiles.py +0 -0
  412. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_rules.py +0 -0
  413. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_rules_ast_match.py +0 -0
  414. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_rules_community_pack.py +0 -0
  415. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_rules_dataflow.py +0 -0
  416. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_rules_symbol_requirements.py +0 -0
  417. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_runtime.py +0 -0
  418. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_salesforce.py +0 -0
  419. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_sarif_flag.py +0 -0
  420. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_sbom.py +0 -0
  421. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_scala.py +0 -0
  422. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_schema_versioning.py +0 -0
  423. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_search_explain.py +0 -0
  424. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_secrets.py +0 -0
  425. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_secrets_v2.py +0 -0
  426. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_semantic_diff.py +0 -0
  427. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_semantic_onnx.py +0 -0
  428. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_semantic_search.py +0 -0
  429. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_simulate.py +0 -0
  430. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_simulate_departure.py +0 -0
  431. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_sketch.py +0 -0
  432. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_smells.py +0 -0
  433. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_smoke.py +0 -0
  434. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_sna_metrics.py +0 -0
  435. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_spectral.py +0 -0
  436. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_split_cmd.py +0 -0
  437. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_sql.py +0 -0
  438. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_suggest_reviewers.py +0 -0
  439. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_supply_chain.py +0 -0
  440. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_syntax_check.py +0 -0
  441. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_taint_analysis.py +0 -0
  442. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_test_conventions.py +0 -0
  443. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_test_gaps.py +0 -0
  444. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_test_scaffold.py +0 -0
  445. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_testmap.py +0 -0
  446. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_tour_cmd.py +0 -0
  447. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_trends.py +0 -0
  448. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_trends_cohort.py +0 -0
  449. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_triage.py +0 -0
  450. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_uses_cmd.py +0 -0
  451. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_v6_features.py +0 -0
  452. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_v71_features.py +0 -0
  453. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_v7_features.py +0 -0
  454. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_v82_features.py +0 -0
  455. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_verify.py +0 -0
  456. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_verify_imports.py +0 -0
  457. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_vibe_check.py +0 -0
  458. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_visualize.py +0 -0
  459. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_vuln.py +0 -0
  460. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_vulns_cmd.py +0 -0
  461. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_watch.py +0 -0
  462. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_why.py +0 -0
  463. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_workspace.py +0 -0
  464. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_xlang.py +0 -0
  465. {roam_code-11.1.3 → roam_code-11.2.0}/tests/test_yaml_hcl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roam-code
3
- Version: 11.1.3
3
+ Version: 11.2.0
4
4
  Summary: Instant codebase comprehension for AI coding agents
5
5
  Author: CosmoHac
6
6
  License-Expression: MIT
@@ -51,7 +51,7 @@ Dynamic: license-file
51
51
 
52
52
  **The architectural intelligence layer for AI coding agents. Structural graph, architecture governance, multi-agent orchestration, vulnerability mapping, runtime analysis -- one CLI, zero API keys.**
53
53
 
54
- *139 commands · 101 MCP tools · 27 languages · 100% local*
54
+ *140 commands · 102 MCP tools · 27 languages · 100% local*
55
55
 
56
56
  [![PyPI version](https://img.shields.io/pypi/v/roam-code?style=flat-square&color=blue)](https://pypi.org/project/roam-code/)
57
57
  [![GitHub stars](https://img.shields.io/github/stars/Cranot/roam-code?style=flat-square)](https://github.com/Cranot/roam-code/stargazers)
@@ -111,6 +111,11 @@ $ roam diff # blast radius of uncommitted changes
111
111
 
112
112
  ## What's New in v11
113
113
 
114
+ ### v11.2 -- AST Clone Detection + Debug Artifact Rules
115
+ - **`roam clones`**: New AST structural clone detection via subtree hashing. Finds Type-2 clones (identical control flow, different identifiers/literals) with Jaccard similarity scoring, Union-Find clustering, and automated refactoring suggestions. More precise than the metric-based `duplicates` command.
116
+ - **9 debug artifact rules** (COR-560 through COR-568): Detect leftover `print()`, `breakpoint()`, `pdb.set_trace()`, `console.log()`, `debugger`, and `System.out.println()` in Python, JavaScript, TypeScript, and Java code. All use `ast_match` type with test file exemptions.
117
+ - **140 commands, 102 MCP tools**.
118
+
114
119
  ### v11.1.2 -- SQL + Scala Tier 1, 27 Languages
115
120
  - **SQL DDL promoted to Tier 1** with dedicated `SqlExtractor` -- tables, columns, views, functions, triggers, schemas, types (enums), sequences, ALTER TABLE ADD COLUMN. Foreign keys produce graph edges; views and triggers reference source tables. Database-schema projects now work with `roam health`, `roam layers`, `roam impact`, `roam coupling` and all graph commands.
116
121
  - **Scala promoted to Tier 1** with dedicated `ScalaExtractor` -- classes, traits, objects, case classes, sealed hierarchies, val/var properties, type aliases, imports, and inheritance. Full `extends` + `with` trait mixin resolution.
@@ -118,7 +123,7 @@ $ roam diff # blast radius of uncommitted changes
118
123
  - `server.json` for official MCP Registry submission.
119
124
 
120
125
  ### v11.1.1 -- Command Quality Audit
121
- - **Full command audit**: all 139 commands reviewed for usefulness, duplicates, and test coverage. ~20 bugs fixed, 21 new test files (700+ tests), every command docstring updated with cross-references to related commands.
126
+ - **Full command audit**: all 140 commands reviewed for usefulness, duplicates, and test coverage. ~20 bugs fixed, 21 new test files (700+ tests), every command docstring updated with cross-references to related commands.
122
127
  - **Kotlin promoted to Tier 1** via new YAML-based declarative extractor architecture. Classes, interfaces, enums, objects, functions, methods, properties, and inheritance fully extracted.
123
128
  - **7 new commands**: `roam congestion`, `roam adrs`, `roam flag-dead`, `roam test-scaffold`, `roam sbom`, `roam triage`, `roam ci-setup`.
124
129
  - **CI templates**: `roam ci-setup` generates pipelines for GitHub Actions, GitLab CI, Azure Pipelines, Jenkins, and Bitbucket.
@@ -273,7 +278,7 @@ roam health
273
278
 
274
279
  ## Commands
275
280
 
276
- The [5 core commands](#core-commands) shown above cover ~80% of agent workflows. All 139 commands are organized into 7 categories.
281
+ The [5 core commands](#core-commands) shown above cover ~80% of agent workflows. All 140 commands are organized into 7 categories.
277
282
 
278
283
  <details>
279
284
  <summary><strong>Full command reference</strong></summary>
@@ -531,6 +536,7 @@ The sentinel pair `<!-- roam:minimap -->` / `<!-- /roam:minimap -->` is replaced
531
536
  | `roam safe-zones` | Graph-based containment boundaries |
532
537
  | `roam coverage-gaps` | Unprotected entry points with no path to gate symbols |
533
538
  | `roam duplicates [--threshold T] [--min-lines N]` | Semantic duplicate detector: functionally equivalent code clusters with divergent edge-case handling |
539
+ | `roam clones [--threshold T] [--min-lines N] [--scope P]` | AST structural clone detection: Type-2 clones via subtree hashing (more precise than `duplicates`) |
534
540
 
535
541
  ### Exploration
536
542
 
@@ -869,7 +875,7 @@ pip install "roam-code[mcp]"
869
875
  roam mcp
870
876
  ```
871
877
 
872
- 101 tools, 10 resources, and 5 prompts are available in the full preset. Most tools are read-only index queries; side-effect tools are explicitly annotated.
878
+ 102 tools, 10 resources, and 5 prompts are available in the full preset. Most tools are read-only index queries; side-effect tools are explicitly annotated.
873
879
 
874
880
  **MCP v2 highlights (v11):**
875
881
  - In-process MCP execution (no subprocess shell-out per call)
@@ -936,6 +942,7 @@ Core preset tools: `roam_affected_tests`, `roam_batch_get`, `roam_batch_search`,
936
942
  | `roam_bisect_blame` | Architectural git bisect |
937
943
  | `roam_doc_intent` | Doc-to-code linking |
938
944
  | `roam_cut_analysis` | Minimum graph cut analysis |
945
+ | `roam_clones` | AST structural clone detection (Type-2 clones) |
939
946
  | `roam_annotate_symbol` | Attach persistent notes to symbols |
940
947
  | `roam_get_annotations` | View stored annotations |
941
948
  | `roam_relate` | Show relationship between two symbols |
@@ -1512,8 +1519,8 @@ roam-code/
1512
1519
  ├── action.yml # Reusable GitHub Action
1513
1520
  ├── src/roam/
1514
1521
  │ ├── __init__.py # Version (from pyproject.toml)
1515
- │ ├── cli.py # Click CLI (139 commands)
1516
- │ ├── mcp_server.py # MCP server (101 tools, 10 resources, 5 prompts)
1522
+ │ ├── cli.py # Click CLI (140 commands)
1523
+ │ ├── mcp_server.py # MCP server (102 tools, 10 resources, 5 prompts)
1517
1524
  │ ├── db/
1518
1525
  │ │ ├── connection.py # SQLite (WAL, pragmas, batched IN)
1519
1526
  │ │ ├── schema.py # Tables, indexes, migrations
@@ -1607,7 +1614,7 @@ Optional: Local semantic ONNX stack (`numpy`, `onnxruntime`, `tokenizers`) via `
1607
1614
  ### Shipped
1608
1615
 
1609
1616
  - [x] MCP v2 agent surface: in-process execution, compound operations, presets, schemas, annotations, and compatibility profiles.
1610
- - [x] Full command and MCP inventory parity in docs: 139 CLI commands and 101 MCP tools.
1617
+ - [x] Full command and MCP inventory parity in docs: 140 CLI commands and 102 MCP tools.
1611
1618
  - [x] CI hardening: composite action, changed-only mode, trend-aware gates, sticky PR updater, and SARIF guardrails.
1612
1619
  - [x] Performance foundation: FTS5/BM25 search, O(changed) incremental indexing, DB/index optimizations.
1613
1620
  - [x] Agent governance suite: `vibe-check`, `ai-readiness`, `verify`, `ai-ratio`, `duplicates`, advanced `algo` scoring/SARIF.
@@ -4,7 +4,7 @@
4
4
 
5
5
  **The architectural intelligence layer for AI coding agents. Structural graph, architecture governance, multi-agent orchestration, vulnerability mapping, runtime analysis -- one CLI, zero API keys.**
6
6
 
7
- *139 commands · 101 MCP tools · 27 languages · 100% local*
7
+ *140 commands · 102 MCP tools · 27 languages · 100% local*
8
8
 
9
9
  [![PyPI version](https://img.shields.io/pypi/v/roam-code?style=flat-square&color=blue)](https://pypi.org/project/roam-code/)
10
10
  [![GitHub stars](https://img.shields.io/github/stars/Cranot/roam-code?style=flat-square)](https://github.com/Cranot/roam-code/stargazers)
@@ -64,6 +64,11 @@ $ roam diff # blast radius of uncommitted changes
64
64
 
65
65
  ## What's New in v11
66
66
 
67
+ ### v11.2 -- AST Clone Detection + Debug Artifact Rules
68
+ - **`roam clones`**: New AST structural clone detection via subtree hashing. Finds Type-2 clones (identical control flow, different identifiers/literals) with Jaccard similarity scoring, Union-Find clustering, and automated refactoring suggestions. More precise than the metric-based `duplicates` command.
69
+ - **9 debug artifact rules** (COR-560 through COR-568): Detect leftover `print()`, `breakpoint()`, `pdb.set_trace()`, `console.log()`, `debugger`, and `System.out.println()` in Python, JavaScript, TypeScript, and Java code. All use `ast_match` type with test file exemptions.
70
+ - **140 commands, 102 MCP tools**.
71
+
67
72
  ### v11.1.2 -- SQL + Scala Tier 1, 27 Languages
68
73
  - **SQL DDL promoted to Tier 1** with dedicated `SqlExtractor` -- tables, columns, views, functions, triggers, schemas, types (enums), sequences, ALTER TABLE ADD COLUMN. Foreign keys produce graph edges; views and triggers reference source tables. Database-schema projects now work with `roam health`, `roam layers`, `roam impact`, `roam coupling` and all graph commands.
69
74
  - **Scala promoted to Tier 1** with dedicated `ScalaExtractor` -- classes, traits, objects, case classes, sealed hierarchies, val/var properties, type aliases, imports, and inheritance. Full `extends` + `with` trait mixin resolution.
@@ -71,7 +76,7 @@ $ roam diff # blast radius of uncommitted changes
71
76
  - `server.json` for official MCP Registry submission.
72
77
 
73
78
  ### v11.1.1 -- Command Quality Audit
74
- - **Full command audit**: all 139 commands reviewed for usefulness, duplicates, and test coverage. ~20 bugs fixed, 21 new test files (700+ tests), every command docstring updated with cross-references to related commands.
79
+ - **Full command audit**: all 140 commands reviewed for usefulness, duplicates, and test coverage. ~20 bugs fixed, 21 new test files (700+ tests), every command docstring updated with cross-references to related commands.
75
80
  - **Kotlin promoted to Tier 1** via new YAML-based declarative extractor architecture. Classes, interfaces, enums, objects, functions, methods, properties, and inheritance fully extracted.
76
81
  - **7 new commands**: `roam congestion`, `roam adrs`, `roam flag-dead`, `roam test-scaffold`, `roam sbom`, `roam triage`, `roam ci-setup`.
77
82
  - **CI templates**: `roam ci-setup` generates pipelines for GitHub Actions, GitLab CI, Azure Pipelines, Jenkins, and Bitbucket.
@@ -226,7 +231,7 @@ roam health
226
231
 
227
232
  ## Commands
228
233
 
229
- The [5 core commands](#core-commands) shown above cover ~80% of agent workflows. All 139 commands are organized into 7 categories.
234
+ The [5 core commands](#core-commands) shown above cover ~80% of agent workflows. All 140 commands are organized into 7 categories.
230
235
 
231
236
  <details>
232
237
  <summary><strong>Full command reference</strong></summary>
@@ -484,6 +489,7 @@ The sentinel pair `<!-- roam:minimap -->` / `<!-- /roam:minimap -->` is replaced
484
489
  | `roam safe-zones` | Graph-based containment boundaries |
485
490
  | `roam coverage-gaps` | Unprotected entry points with no path to gate symbols |
486
491
  | `roam duplicates [--threshold T] [--min-lines N]` | Semantic duplicate detector: functionally equivalent code clusters with divergent edge-case handling |
492
+ | `roam clones [--threshold T] [--min-lines N] [--scope P]` | AST structural clone detection: Type-2 clones via subtree hashing (more precise than `duplicates`) |
487
493
 
488
494
  ### Exploration
489
495
 
@@ -822,7 +828,7 @@ pip install "roam-code[mcp]"
822
828
  roam mcp
823
829
  ```
824
830
 
825
- 101 tools, 10 resources, and 5 prompts are available in the full preset. Most tools are read-only index queries; side-effect tools are explicitly annotated.
831
+ 102 tools, 10 resources, and 5 prompts are available in the full preset. Most tools are read-only index queries; side-effect tools are explicitly annotated.
826
832
 
827
833
  **MCP v2 highlights (v11):**
828
834
  - In-process MCP execution (no subprocess shell-out per call)
@@ -889,6 +895,7 @@ Core preset tools: `roam_affected_tests`, `roam_batch_get`, `roam_batch_search`,
889
895
  | `roam_bisect_blame` | Architectural git bisect |
890
896
  | `roam_doc_intent` | Doc-to-code linking |
891
897
  | `roam_cut_analysis` | Minimum graph cut analysis |
898
+ | `roam_clones` | AST structural clone detection (Type-2 clones) |
892
899
  | `roam_annotate_symbol` | Attach persistent notes to symbols |
893
900
  | `roam_get_annotations` | View stored annotations |
894
901
  | `roam_relate` | Show relationship between two symbols |
@@ -1465,8 +1472,8 @@ roam-code/
1465
1472
  ├── action.yml # Reusable GitHub Action
1466
1473
  ├── src/roam/
1467
1474
  │ ├── __init__.py # Version (from pyproject.toml)
1468
- │ ├── cli.py # Click CLI (139 commands)
1469
- │ ├── mcp_server.py # MCP server (101 tools, 10 resources, 5 prompts)
1475
+ │ ├── cli.py # Click CLI (140 commands)
1476
+ │ ├── mcp_server.py # MCP server (102 tools, 10 resources, 5 prompts)
1470
1477
  │ ├── db/
1471
1478
  │ │ ├── connection.py # SQLite (WAL, pragmas, batched IN)
1472
1479
  │ │ ├── schema.py # Tables, indexes, migrations
@@ -1560,7 +1567,7 @@ Optional: Local semantic ONNX stack (`numpy`, `onnxruntime`, `tokenizers`) via `
1560
1567
  ### Shipped
1561
1568
 
1562
1569
  - [x] MCP v2 agent surface: in-process execution, compound operations, presets, schemas, annotations, and compatibility profiles.
1563
- - [x] Full command and MCP inventory parity in docs: 139 CLI commands and 101 MCP tools.
1570
+ - [x] Full command and MCP inventory parity in docs: 140 CLI commands and 102 MCP tools.
1564
1571
  - [x] CI hardening: composite action, changed-only mode, trend-aware gates, sticky PR updater, and SARIF guardrails.
1565
1572
  - [x] Performance foundation: FTS5/BM25 search, O(changed) incremental indexing, DB/index optimizations.
1566
1573
  - [x] Agent governance suite: `vibe-check`, `ai-readiness`, `verify`, `ai-ratio`, `duplicates`, advanced `algo` scoring/SARIF.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "roam-code"
7
- version = "11.1.3"
7
+ version = "11.2.0"
8
8
  description = "Instant codebase comprehension for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -14,7 +14,7 @@ import click
14
14
 
15
15
  # Lazy-loading command group: imports command modules only when invoked.
16
16
  # This avoids importing networkx (~500ms) on every CLI call.
17
- # Total: 142 invokable command names (139 canonical commands + 3 alias pairs).
17
+ # Total: 143 invokable command names (140 canonical commands + 3 alias pairs).
18
18
  # If this changes, update README.md, CLAUDE.md, llms-install.md, and docs copy.
19
19
  _COMMANDS = {
20
20
  "index": ("roam.commands.cmd_index", "index"),
@@ -159,6 +159,7 @@ _COMMANDS = {
159
159
  "sbom": ("roam.commands.cmd_sbom", "sbom"),
160
160
  "triage": ("roam.commands.cmd_triage", "triage"),
161
161
  "ci-setup": ("roam.commands.cmd_ci_setup", "ci_setup"),
162
+ "clones": ("roam.commands.cmd_clones", "clones"),
162
163
  }
163
164
 
164
165
  # Command categories for organized --help display
@@ -252,6 +253,7 @@ _CATEGORIES = {
252
253
  "visualize",
253
254
  "x-lang",
254
255
  "fingerprint",
256
+ "clones",
255
257
  ],
256
258
  "Exploration": [
257
259
  "search",
@@ -0,0 +1,163 @@
1
+ """Detect near-duplicate code via AST structural hashing.
2
+
3
+ Unlike ``duplicates`` (which uses metric-based similarity from the DB),
4
+ this command re-parses source files and compares actual AST subtree
5
+ structures. Detects Type-2 clones: identical control flow with different
6
+ identifiers or literals.
7
+
8
+ Related commands: ``duplicates`` (metric-based), ``suggest-refactoring``,
9
+ ``split`` (extract responsibilities).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import click
15
+
16
+ from roam.commands.resolve import ensure_index
17
+ from roam.db.connection import open_db
18
+ from roam.output.formatter import (
19
+ abbrev_kind,
20
+ format_table,
21
+ json_envelope,
22
+ loc,
23
+ to_json,
24
+ )
25
+
26
+
27
+ @click.command()
28
+ @click.option(
29
+ "--threshold",
30
+ default=0.70,
31
+ show_default=True,
32
+ type=click.FloatRange(0.0, 1.0),
33
+ help="Minimum Jaccard similarity (0.0-1.0)",
34
+ )
35
+ @click.option(
36
+ "--min-lines",
37
+ default=5,
38
+ show_default=True,
39
+ type=int,
40
+ help="Skip functions shorter than N lines",
41
+ )
42
+ @click.option("--scope", default=None, type=str, help="Limit to files under this path prefix")
43
+ @click.option("--top", default=0, type=int, help="Show only top N clusters (0=all)")
44
+ @click.pass_context
45
+ def clones(ctx, threshold, min_lines, scope, top):
46
+ """Detect near-duplicate code via AST structural hashing.
47
+
48
+ Re-parses source files and compares function AST structures via subtree
49
+ hashing. Finds Type-2 clones: identical control flow with different
50
+ identifiers or literals.
51
+
52
+ Unlike ``duplicates`` (metric-based), this uses actual tree-sitter AST
53
+ comparison for higher precision.
54
+ """
55
+ json_mode = ctx.obj.get("json") if ctx.obj else False
56
+ token_budget = ctx.obj.get("budget", 0) if ctx.obj else 0
57
+ ensure_index()
58
+
59
+ from roam.graph.clone_detect import detect_clones
60
+
61
+ with open_db(readonly=True) as conn:
62
+ pairs, clusters = detect_clones(
63
+ conn,
64
+ min_similarity=threshold,
65
+ min_lines=min_lines,
66
+ scope=scope,
67
+ )
68
+
69
+ if top > 0:
70
+ clusters = clusters[:top]
71
+
72
+ # Summary stats
73
+ total_functions = sum(len(c.members) for c in clusters)
74
+ total_pairs = len(pairs)
75
+ avg_sim = sum(c.avg_similarity for c in clusters) / len(clusters) if clusters else 0.0
76
+
77
+ # Estimate reducible lines
78
+ reducible_lines = 0
79
+ for c in clusters:
80
+ lines = sorted(m["line_end"] - m["line_start"] + 1 for m in c.members)
81
+ if len(lines) > 1:
82
+ reducible_lines += sum(lines[:-1])
83
+
84
+ verdict = (
85
+ f"{len(clusters)} clone cluster{'s' if len(clusters) != 1 else ''} "
86
+ f"found ({total_functions} functions, {round(avg_sim * 100)}% avg similarity)"
87
+ if clusters
88
+ else "No structural clones detected"
89
+ )
90
+
91
+ if json_mode:
92
+ clusters_json = []
93
+ for c in clusters:
94
+ clusters_json.append(
95
+ {
96
+ "cluster_id": c.cluster_id,
97
+ "avg_similarity": c.avg_similarity,
98
+ "size": len(c.members),
99
+ "members": c.members,
100
+ "pattern": c.pattern,
101
+ "suggestion": c.suggestion,
102
+ }
103
+ )
104
+
105
+ pairs_json = [
106
+ {
107
+ "file_a": p.file_a,
108
+ "func_a": p.func_a,
109
+ "line_a": p.line_a,
110
+ "file_b": p.file_b,
111
+ "func_b": p.func_b,
112
+ "line_b": p.line_b,
113
+ "similarity": p.similarity,
114
+ }
115
+ for p in pairs[:50] # Cap pair output
116
+ ]
117
+
118
+ click.echo(
119
+ to_json(
120
+ json_envelope(
121
+ "clones",
122
+ summary={
123
+ "verdict": verdict,
124
+ "clusters": len(clusters),
125
+ "clone_pairs": total_pairs,
126
+ "total_functions": total_functions,
127
+ "avg_similarity": round(avg_sim, 3),
128
+ "estimated_reducible_lines": reducible_lines,
129
+ },
130
+ budget=token_budget,
131
+ clusters=clusters_json,
132
+ pairs=pairs_json,
133
+ )
134
+ )
135
+ )
136
+ return
137
+
138
+ # Text output
139
+ click.echo(f"VERDICT: {verdict}")
140
+
141
+ if not clusters:
142
+ return
143
+
144
+ click.echo()
145
+ for c in clusters:
146
+ sim_pct = round(c.avg_similarity * 100)
147
+ click.echo(f"CLUSTER {c.cluster_id} -- {sim_pct}% similarity, {len(c.members)} functions:")
148
+ for m in c.members:
149
+ lines = m["line_end"] - m["line_start"] + 1
150
+ click.echo(
151
+ f" {m['function']:<40s} "
152
+ f"{loc(m['file'], m['line_start'])}"
153
+ f" ({lines} lines, {m['ast_nodes']} AST nodes)"
154
+ )
155
+ click.echo(f" Pattern: {c.pattern}")
156
+ click.echo(f" Suggestion: {c.suggestion}")
157
+ click.echo()
158
+
159
+ click.echo(
160
+ f"SUMMARY: {len(clusters)} clusters, "
161
+ f"{total_functions} functions, "
162
+ f"~{reducible_lines} lines of reducible duplication"
163
+ )