roam-code 12.17__tar.gz → 12.18__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 (612) hide show
  1. {roam_code-12.17/src/roam_code.egg-info → roam_code-12.18}/PKG-INFO +13 -8
  2. {roam_code-12.17 → roam_code-12.18}/README.md +12 -7
  3. {roam_code-12.17 → roam_code-12.18}/pyproject.toml +1 -1
  4. {roam_code-12.17 → roam_code-12.18}/src/roam/cli.py +10 -0
  5. roam_code-12.18/src/roam/commands/cmd_disambiguate.py +98 -0
  6. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_map.py +46 -1
  7. roam_code-12.18/src/roam/commands/cmd_mcp_status.py +89 -0
  8. roam_code-12.18/src/roam/commands/cmd_pre_commit.py +120 -0
  9. roam_code-12.18/src/roam/commands/cmd_recipes.py +53 -0
  10. roam_code-12.18/src/roam/commands/cmd_test_impact.py +145 -0
  11. {roam_code-12.17 → roam_code-12.18}/src/roam/competitor_site_data.py +2 -2
  12. {roam_code-12.17 → roam_code-12.18}/src/roam/config.py +21 -2
  13. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp-server-card.json +1 -1
  14. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_server.py +37 -0
  15. {roam_code-12.17 → roam_code-12.18/src/roam_code.egg-info}/PKG-INFO +13 -8
  16. {roam_code-12.17 → roam_code-12.18}/src/roam_code.egg-info/SOURCES.txt +6 -0
  17. {roam_code-12.17 → roam_code-12.18}/tests/test_mcp_server.py +6 -4
  18. roam_code-12.18/tests/test_v1218_passes_81_90.py +118 -0
  19. {roam_code-12.17 → roam_code-12.18}/LICENSE +0 -0
  20. {roam_code-12.17 → roam_code-12.18}/setup.cfg +0 -0
  21. {roam_code-12.17 → roam_code-12.18}/src/roam/__init__.py +0 -0
  22. {roam_code-12.17 → roam_code-12.18}/src/roam/__main__.py +0 -0
  23. {roam_code-12.17 → roam_code-12.18}/src/roam/analysis/__init__.py +0 -0
  24. {roam_code-12.17 → roam_code-12.18}/src/roam/analysis/effects.py +0 -0
  25. {roam_code-12.17 → roam_code-12.18}/src/roam/analysis/taint.py +0 -0
  26. {roam_code-12.17 → roam_code-12.18}/src/roam/api.py +0 -0
  27. {roam_code-12.17 → roam_code-12.18}/src/roam/ask/__init__.py +0 -0
  28. {roam_code-12.17 → roam_code-12.18}/src/roam/ask/classifier.py +0 -0
  29. {roam_code-12.17 → roam_code-12.18}/src/roam/ask/recipes.py +0 -0
  30. {roam_code-12.17 → roam_code-12.18}/src/roam/ask/runner.py +0 -0
  31. {roam_code-12.17 → roam_code-12.18}/src/roam/ask/workflow.py +0 -0
  32. {roam_code-12.17 → roam_code-12.18}/src/roam/attest/__init__.py +0 -0
  33. {roam_code-12.17 → roam_code-12.18}/src/roam/attest/cga.py +0 -0
  34. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/__init__.py +0 -0
  35. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/base.py +0 -0
  36. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/bridge_config.py +0 -0
  37. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/bridge_django.py +0 -0
  38. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/bridge_protobuf.py +0 -0
  39. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/bridge_rest_api.py +0 -0
  40. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/bridge_salesforce.py +0 -0
  41. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/bridge_template.py +0 -0
  42. {roam_code-12.17 → roam_code-12.18}/src/roam/bridges/registry.py +0 -0
  43. {roam_code-12.17 → roam_code-12.18}/src/roam/catalog/__init__.py +0 -0
  44. {roam_code-12.17 → roam_code-12.18}/src/roam/catalog/detectors.py +0 -0
  45. {roam_code-12.17 → roam_code-12.18}/src/roam/catalog/fixes.py +0 -0
  46. {roam_code-12.17 → roam_code-12.18}/src/roam/catalog/python_idioms.py +0 -0
  47. {roam_code-12.17 → roam_code-12.18}/src/roam/catalog/smells.py +0 -0
  48. {roam_code-12.17 → roam_code-12.18}/src/roam/catalog/tasks.py +0 -0
  49. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/__init__.py +0 -0
  50. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/changed_files.py +0 -0
  51. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_adrs.py +0 -0
  52. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_adversarial.py +0 -0
  53. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_affected.py +0 -0
  54. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_affected_tests.py +0 -0
  55. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_agent_context.py +0 -0
  56. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_agent_export.py +0 -0
  57. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_agent_plan.py +0 -0
  58. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_ai_ratio.py +0 -0
  59. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_ai_readiness.py +0 -0
  60. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_alerts.py +0 -0
  61. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_annotate.py +0 -0
  62. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_api.py +0 -0
  63. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_api_changes.py +0 -0
  64. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_api_drift.py +0 -0
  65. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_ask.py +0 -0
  66. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_attest.py +0 -0
  67. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_auth_gaps.py +0 -0
  68. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_bisect.py +0 -0
  69. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_breaking.py +0 -0
  70. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_budget.py +0 -0
  71. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_bus_factor.py +0 -0
  72. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_capsule.py +0 -0
  73. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_cga.py +0 -0
  74. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_changelog.py +0 -0
  75. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_check_rules.py +0 -0
  76. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_ci_setup.py +0 -0
  77. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_clean.py +0 -0
  78. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_clones.py +0 -0
  79. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_closure.py +0 -0
  80. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_clusters.py +0 -0
  81. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_codeowners.py +0 -0
  82. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_complexity.py +0 -0
  83. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_config.py +0 -0
  84. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_congestion.py +0 -0
  85. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_context.py +0 -0
  86. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_conventions.py +0 -0
  87. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_coupling.py +0 -0
  88. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_coverage_gaps.py +0 -0
  89. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_critique.py +0 -0
  90. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_cut.py +0 -0
  91. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_dark_matter.py +0 -0
  92. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_dashboard.py +0 -0
  93. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_dead.py +0 -0
  94. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_debt.py +0 -0
  95. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_deps.py +0 -0
  96. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_describe.py +0 -0
  97. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_dev_profile.py +0 -0
  98. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_diagnose.py +0 -0
  99. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_diff.py +0 -0
  100. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_doc_staleness.py +0 -0
  101. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_docs_coverage.py +0 -0
  102. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_doctor.py +0 -0
  103. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_drift.py +0 -0
  104. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_duplicates.py +0 -0
  105. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_effects.py +0 -0
  106. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_endpoints.py +0 -0
  107. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_entry_points.py +0 -0
  108. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_eval_retrieve.py +0 -0
  109. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_exit_codes.py +0 -0
  110. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_fan.py +0 -0
  111. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_file.py +0 -0
  112. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_fingerprint.py +0 -0
  113. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_fitness.py +0 -0
  114. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_flag_dead.py +0 -0
  115. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_fleet.py +0 -0
  116. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_fn_coupling.py +0 -0
  117. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_forecast.py +0 -0
  118. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_graph_export.py +0 -0
  119. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_graph_stats.py +0 -0
  120. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_grep.py +0 -0
  121. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_guard.py +0 -0
  122. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_health.py +0 -0
  123. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_help_search.py +0 -0
  124. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_hooks.py +0 -0
  125. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_hotspots.py +0 -0
  126. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_hover.py +0 -0
  127. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_impact.py +0 -0
  128. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_index.py +0 -0
  129. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_index_bundle.py +0 -0
  130. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_index_stats.py +0 -0
  131. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_ingest_trace.py +0 -0
  132. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_init.py +0 -0
  133. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_intent.py +0 -0
  134. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_invariants.py +0 -0
  135. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_layers.py +0 -0
  136. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_math.py +0 -0
  137. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_mcp_setup.py +0 -0
  138. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_metrics.py +0 -0
  139. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_migration_safety.py +0 -0
  140. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_minimap.py +0 -0
  141. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_missing_index.py +0 -0
  142. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_module.py +0 -0
  143. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_mutate.py +0 -0
  144. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_n1.py +0 -0
  145. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_oracle.py +0 -0
  146. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_orchestrate.py +0 -0
  147. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_orphan_imports.py +0 -0
  148. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_orphan_routes.py +0 -0
  149. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_over_fetch.py +0 -0
  150. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_owner.py +0 -0
  151. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_partition.py +0 -0
  152. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_path_coverage.py +0 -0
  153. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_patterns.py +0 -0
  154. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_plan.py +0 -0
  155. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_plan_refactor.py +0 -0
  156. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_plugins.py +0 -0
  157. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_pr_diff.py +0 -0
  158. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_pr_prep.py +0 -0
  159. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_pr_risk.py +0 -0
  160. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_preflight.py +0 -0
  161. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_py_modern.py +0 -0
  162. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_py_types.py +0 -0
  163. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_pytest_fixtures.py +0 -0
  164. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_recommend.py +0 -0
  165. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_relate.py +0 -0
  166. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_report.py +0 -0
  167. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_reset.py +0 -0
  168. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_retrieve.py +0 -0
  169. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_risk.py +0 -0
  170. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_rules.py +0 -0
  171. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_safe_delete.py +0 -0
  172. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_safe_zones.py +0 -0
  173. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_sbom.py +0 -0
  174. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_schema.py +0 -0
  175. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_search.py +0 -0
  176. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_search_semantic.py +0 -0
  177. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_secrets.py +0 -0
  178. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_semantic_diff.py +0 -0
  179. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_simulate.py +0 -0
  180. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_simulate_departure.py +0 -0
  181. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_sketch.py +0 -0
  182. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_smells.py +0 -0
  183. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_spectral.py +0 -0
  184. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_split.py +0 -0
  185. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_stats.py +0 -0
  186. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
  187. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
  188. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_supply_chain.py +0 -0
  189. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_symbol.py +0 -0
  190. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_syntax_check.py +0 -0
  191. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_taint.py +0 -0
  192. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_telemetry.py +0 -0
  193. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_test_gaps.py +0 -0
  194. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_test_pyramid.py +0 -0
  195. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_test_scaffold.py +0 -0
  196. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_testmap.py +0 -0
  197. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_timeline.py +0 -0
  198. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_tour.py +0 -0
  199. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_trace.py +0 -0
  200. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_trends.py +0 -0
  201. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_triage.py +0 -0
  202. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_understand.py +0 -0
  203. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_uses.py +0 -0
  204. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_verify.py +0 -0
  205. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_verify_imports.py +0 -0
  206. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_version.py +0 -0
  207. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_vibe_check.py +0 -0
  208. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_visualize.py +0 -0
  209. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_vuln_map.py +0 -0
  210. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_vuln_reach.py +0 -0
  211. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_vulns.py +0 -0
  212. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_watch.py +0 -0
  213. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_weather.py +0 -0
  214. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_why.py +0 -0
  215. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_why_fail.py +0 -0
  216. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_workflow.py +0 -0
  217. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_ws.py +0 -0
  218. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/cmd_xlang.py +0 -0
  219. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/codeowners_helpers.py +0 -0
  220. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/context_helpers.py +0 -0
  221. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/gate_presets.py +0 -0
  222. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/graph_helpers.py +0 -0
  223. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/metrics_history.py +0 -0
  224. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/next_steps.py +0 -0
  225. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/resolve.py +0 -0
  226. {roam_code-12.17 → roam_code-12.18}/src/roam/commands/suppression.py +0 -0
  227. {roam_code-12.17 → roam_code-12.18}/src/roam/coverage_reports.py +0 -0
  228. {roam_code-12.17 → roam_code-12.18}/src/roam/critique/__init__.py +0 -0
  229. {roam_code-12.17 → roam_code-12.18}/src/roam/critique/aggregator.py +0 -0
  230. {roam_code-12.17 → roam_code-12.18}/src/roam/critique/checks.py +0 -0
  231. {roam_code-12.17 → roam_code-12.18}/src/roam/db/__init__.py +0 -0
  232. {roam_code-12.17 → roam_code-12.18}/src/roam/db/connection.py +0 -0
  233. {roam_code-12.17 → roam_code-12.18}/src/roam/db/queries.py +0 -0
  234. {roam_code-12.17 → roam_code-12.18}/src/roam/db/schema.py +0 -0
  235. {roam_code-12.17 → roam_code-12.18}/src/roam/eval/__init__.py +0 -0
  236. {roam_code-12.17 → roam_code-12.18}/src/roam/eval/harness.py +0 -0
  237. {roam_code-12.17 → roam_code-12.18}/src/roam/exit_codes.py +0 -0
  238. {roam_code-12.17 → roam_code-12.18}/src/roam/fleet/__init__.py +0 -0
  239. {roam_code-12.17 → roam_code-12.18}/src/roam/fleet/adapters.py +0 -0
  240. {roam_code-12.17 → roam_code-12.18}/src/roam/fleet/manifest.py +0 -0
  241. {roam_code-12.17 → roam_code-12.18}/src/roam/git_utils.py +0 -0
  242. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/__init__.py +0 -0
  243. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/anomaly.py +0 -0
  244. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/builder.py +0 -0
  245. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/clone_detect.py +0 -0
  246. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/clusters.py +0 -0
  247. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/cycles.py +0 -0
  248. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/dark_matter.py +0 -0
  249. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/diff.py +0 -0
  250. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/fingerprint.py +0 -0
  251. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/layers.py +0 -0
  252. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/pagerank.py +0 -0
  253. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/partition.py +0 -0
  254. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/pathfinding.py +0 -0
  255. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/propagation.py +0 -0
  256. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/simulate.py +0 -0
  257. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/spectral.py +0 -0
  258. {roam_code-12.17 → roam_code-12.18}/src/roam/graph/stats.py +0 -0
  259. {roam_code-12.17 → roam_code-12.18}/src/roam/index/__init__.py +0 -0
  260. {roam_code-12.17 → roam_code-12.18}/src/roam/index/complexity.py +0 -0
  261. {roam_code-12.17 → roam_code-12.18}/src/roam/index/discovery.py +0 -0
  262. {roam_code-12.17 → roam_code-12.18}/src/roam/index/django_post.py +0 -0
  263. {roam_code-12.17 → roam_code-12.18}/src/roam/index/file_roles.py +0 -0
  264. {roam_code-12.17 → roam_code-12.18}/src/roam/index/git_stats.py +0 -0
  265. {roam_code-12.17 → roam_code-12.18}/src/roam/index/gitignore.py +0 -0
  266. {roam_code-12.17 → roam_code-12.18}/src/roam/index/incremental.py +0 -0
  267. {roam_code-12.17 → roam_code-12.18}/src/roam/index/indexer.py +0 -0
  268. {roam_code-12.17 → roam_code-12.18}/src/roam/index/parser.py +0 -0
  269. {roam_code-12.17 → roam_code-12.18}/src/roam/index/pytest_fixtures.py +0 -0
  270. {roam_code-12.17 → roam_code-12.18}/src/roam/index/registry_dispatch.py +0 -0
  271. {roam_code-12.17 → roam_code-12.18}/src/roam/index/relations.py +0 -0
  272. {roam_code-12.17 → roam_code-12.18}/src/roam/index/symbols.py +0 -0
  273. {roam_code-12.17 → roam_code-12.18}/src/roam/index/test_conventions.py +0 -0
  274. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/__init__.py +0 -0
  275. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/apex_lang.py +0 -0
  276. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/aura_lang.py +0 -0
  277. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/base.py +0 -0
  278. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/c_lang.py +0 -0
  279. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/csharp_lang.py +0 -0
  280. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/extractor_schema.py +0 -0
  281. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/extractors/kotlin.yaml +0 -0
  282. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/foxpro_lang.py +0 -0
  283. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/generic_lang.py +0 -0
  284. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/go_lang.py +0 -0
  285. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/hcl_lang.py +0 -0
  286. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/java_lang.py +0 -0
  287. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/javascript_lang.py +0 -0
  288. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/kotlin_lang.py +0 -0
  289. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/php_lang.py +0 -0
  290. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/python_lang.py +0 -0
  291. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/query_engine.py +0 -0
  292. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/registry.py +0 -0
  293. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/ruby_lang.py +0 -0
  294. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/rust_lang.py +0 -0
  295. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/scala_lang.py +0 -0
  296. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/sfxml_lang.py +0 -0
  297. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/sql_lang.py +0 -0
  298. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/swift_lang.py +0 -0
  299. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/typescript_lang.py +0 -0
  300. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/visualforce_lang.py +0 -0
  301. {roam_code-12.17 → roam_code-12.18}/src/roam/languages/yaml_lang.py +0 -0
  302. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_extras/__init__.py +0 -0
  303. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_extras/completions.py +0 -0
  304. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_extras/concurrency.py +0 -0
  305. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_extras/progress.py +0 -0
  306. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_extras/sampling.py +0 -0
  307. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_extras/session.py +0 -0
  308. {roam_code-12.17 → roam_code-12.18}/src/roam/mcp_extras/watcher.py +0 -0
  309. {roam_code-12.17 → roam_code-12.18}/src/roam/output/__init__.py +0 -0
  310. {roam_code-12.17 → roam_code-12.18}/src/roam/output/confidence.py +0 -0
  311. {roam_code-12.17 → roam_code-12.18}/src/roam/output/errors.py +0 -0
  312. {roam_code-12.17 → roam_code-12.18}/src/roam/output/file_role_hints.py +0 -0
  313. {roam_code-12.17 → roam_code-12.18}/src/roam/output/formatter.py +0 -0
  314. {roam_code-12.17 → roam_code-12.18}/src/roam/output/framework_filter.py +0 -0
  315. {roam_code-12.17 → roam_code-12.18}/src/roam/output/mermaid.py +0 -0
  316. {roam_code-12.17 → roam_code-12.18}/src/roam/output/project_shape.py +0 -0
  317. {roam_code-12.17 → roam_code-12.18}/src/roam/output/sarif.py +0 -0
  318. {roam_code-12.17 → roam_code-12.18}/src/roam/output/schema_registry.py +0 -0
  319. {roam_code-12.17 → roam_code-12.18}/src/roam/plugins.py +0 -0
  320. {roam_code-12.17 → roam_code-12.18}/src/roam/refactor/__init__.py +0 -0
  321. {roam_code-12.17 → roam_code-12.18}/src/roam/refactor/codegen.py +0 -0
  322. {roam_code-12.17 → roam_code-12.18}/src/roam/refactor/transforms.py +0 -0
  323. {roam_code-12.17 → roam_code-12.18}/src/roam/retrieve/__init__.py +0 -0
  324. {roam_code-12.17 → roam_code-12.18}/src/roam/retrieve/learned_ranker.py +0 -0
  325. {roam_code-12.17 → roam_code-12.18}/src/roam/retrieve/pipeline.py +0 -0
  326. {roam_code-12.17 → roam_code-12.18}/src/roam/retrieve/rerank.py +0 -0
  327. {roam_code-12.17 → roam_code-12.18}/src/roam/retrieve/seeds.py +0 -0
  328. {roam_code-12.17 → roam_code-12.18}/src/roam/retrieve/semantic.py +0 -0
  329. {roam_code-12.17 → roam_code-12.18}/src/roam/rules/__init__.py +0 -0
  330. {roam_code-12.17 → roam_code-12.18}/src/roam/rules/ast_match.py +0 -0
  331. {roam_code-12.17 → roam_code-12.18}/src/roam/rules/builtin.py +0 -0
  332. {roam_code-12.17 → roam_code-12.18}/src/roam/rules/dataflow.py +0 -0
  333. {roam_code-12.17 → roam_code-12.18}/src/roam/rules/engine.py +0 -0
  334. {roam_code-12.17 → roam_code-12.18}/src/roam/runtime/__init__.py +0 -0
  335. {roam_code-12.17 → roam_code-12.18}/src/roam/runtime/daemon.py +0 -0
  336. {roam_code-12.17 → roam_code-12.18}/src/roam/runtime/graph_backend.py +0 -0
  337. {roam_code-12.17 → roam_code-12.18}/src/roam/runtime/hotspots.py +0 -0
  338. {roam_code-12.17 → roam_code-12.18}/src/roam/runtime/lock_modes.py +0 -0
  339. {roam_code-12.17 → roam_code-12.18}/src/roam/runtime/lockmgr.py +0 -0
  340. {roam_code-12.17 → roam_code-12.18}/src/roam/runtime/trace_ingest.py +0 -0
  341. {roam_code-12.17 → roam_code-12.18}/src/roam/search/__init__.py +0 -0
  342. {roam_code-12.17 → roam_code-12.18}/src/roam/search/framework_packs.py +0 -0
  343. {roam_code-12.17 → roam_code-12.18}/src/roam/search/index_embeddings.py +0 -0
  344. {roam_code-12.17 → roam_code-12.18}/src/roam/search/onnx_embeddings.py +0 -0
  345. {roam_code-12.17 → roam_code-12.18}/src/roam/search/tfidf.py +0 -0
  346. {roam_code-12.17 → roam_code-12.18}/src/roam/security/__init__.py +0 -0
  347. {roam_code-12.17 → roam_code-12.18}/src/roam/security/aibom_extension.py +0 -0
  348. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_classifier.py +0 -0
  349. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_engine.py +0 -0
  350. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/api_error_leak.yaml +0 -0
  351. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/java_fileupload_path_traversal.yaml +0 -0
  352. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/js_insecure_jwt_decode.yaml +0 -0
  353. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/js_localstorage_secrets.yaml +0 -0
  354. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/js_prototype_pollution.yaml +0 -0
  355. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/js_ssrf.yaml +0 -0
  356. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/js_xss.yaml +0 -0
  357. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/python_basic.yaml +0 -0
  358. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/python_deserialization.yaml +0 -0
  359. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/python_path_traversal.yaml +0 -0
  360. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/python_socketio_remote_source.yaml +0 -0
  361. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/python_sqli.yaml +0 -0
  362. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/python_urllib_open_redirect.yaml +0 -0
  363. {roam_code-12.17 → roam_code-12.18}/src/roam/security/taint_rules/vue_v_html.yaml +0 -0
  364. {roam_code-12.17 → roam_code-12.18}/src/roam/security/vuln_reach.py +0 -0
  365. {roam_code-12.17 → roam_code-12.18}/src/roam/security/vuln_store.py +0 -0
  366. {roam_code-12.17 → roam_code-12.18}/src/roam/surface_counts.py +0 -0
  367. {roam_code-12.17 → roam_code-12.18}/src/roam/telemetry.py +0 -0
  368. {roam_code-12.17 → roam_code-12.18}/src/roam/templates/__init__.py +0 -0
  369. {roam_code-12.17 → roam_code-12.18}/src/roam/templates/ci/Jenkinsfile +0 -0
  370. {roam_code-12.17 → roam_code-12.18}/src/roam/templates/ci/__init__.py +0 -0
  371. {roam_code-12.17 → roam_code-12.18}/src/roam/templates/ci/azure-pipelines.yml +0 -0
  372. {roam_code-12.17 → roam_code-12.18}/src/roam/templates/ci/bitbucket-pipelines.yml +0 -0
  373. {roam_code-12.17 → roam_code-12.18}/src/roam/templates/ci/gitlab-ci.yml +0 -0
  374. {roam_code-12.17 → roam_code-12.18}/src/roam/workspace/__init__.py +0 -0
  375. {roam_code-12.17 → roam_code-12.18}/src/roam/workspace/aggregator.py +0 -0
  376. {roam_code-12.17 → roam_code-12.18}/src/roam/workspace/api_scanner.py +0 -0
  377. {roam_code-12.17 → roam_code-12.18}/src/roam/workspace/config.py +0 -0
  378. {roam_code-12.17 → roam_code-12.18}/src/roam/workspace/db.py +0 -0
  379. {roam_code-12.17 → roam_code-12.18}/src/roam_code.egg-info/dependency_links.txt +0 -0
  380. {roam_code-12.17 → roam_code-12.18}/src/roam_code.egg-info/entry_points.txt +0 -0
  381. {roam_code-12.17 → roam_code-12.18}/src/roam_code.egg-info/requires.txt +0 -0
  382. {roam_code-12.17 → roam_code-12.18}/src/roam_code.egg-info/top_level.txt +0 -0
  383. {roam_code-12.17 → roam_code-12.18}/tests/test_adrs.py +0 -0
  384. {roam_code-12.17 → roam_code-12.18}/tests/test_adversarial.py +0 -0
  385. {roam_code-12.17 → roam_code-12.18}/tests/test_affected.py +0 -0
  386. {roam_code-12.17 → roam_code-12.18}/tests/test_agent_export.py +0 -0
  387. {roam_code-12.17 → roam_code-12.18}/tests/test_agent_mode.py +0 -0
  388. {roam_code-12.17 → roam_code-12.18}/tests/test_agent_plan_context.py +0 -0
  389. {roam_code-12.17 → roam_code-12.18}/tests/test_ai_ratio.py +0 -0
  390. {roam_code-12.17 → roam_code-12.18}/tests/test_ai_readiness.py +0 -0
  391. {roam_code-12.17 → roam_code-12.18}/tests/test_alerts_cmd.py +0 -0
  392. {roam_code-12.17 → roam_code-12.18}/tests/test_annotations.py +0 -0
  393. {roam_code-12.17 → roam_code-12.18}/tests/test_anomaly.py +0 -0
  394. {roam_code-12.17 → roam_code-12.18}/tests/test_api_changes.py +0 -0
  395. {roam_code-12.17 → roam_code-12.18}/tests/test_api_drift.py +0 -0
  396. {roam_code-12.17 → roam_code-12.18}/tests/test_ask.py +0 -0
  397. {roam_code-12.17 → roam_code-12.18}/tests/test_attest.py +0 -0
  398. {roam_code-12.17 → roam_code-12.18}/tests/test_auth_gaps.py +0 -0
  399. {roam_code-12.17 → roam_code-12.18}/tests/test_backend_fixes_round2.py +0 -0
  400. {roam_code-12.17 → roam_code-12.18}/tests/test_backend_fixes_round3.py +0 -0
  401. {roam_code-12.17 → roam_code-12.18}/tests/test_basic.py +0 -0
  402. {roam_code-12.17 → roam_code-12.18}/tests/test_batch_mcp.py +0 -0
  403. {roam_code-12.17 → roam_code-12.18}/tests/test_bisect.py +0 -0
  404. {roam_code-12.17 → roam_code-12.18}/tests/test_bridge_django.py +0 -0
  405. {roam_code-12.17 → roam_code-12.18}/tests/test_bridges.py +0 -0
  406. {roam_code-12.17 → roam_code-12.18}/tests/test_bridges_extended.py +0 -0
  407. {roam_code-12.17 → roam_code-12.18}/tests/test_budget.py +0 -0
  408. {roam_code-12.17 → roam_code-12.18}/tests/test_budget_flag.py +0 -0
  409. {roam_code-12.17 → roam_code-12.18}/tests/test_budget_phase2.py +0 -0
  410. {roam_code-12.17 → roam_code-12.18}/tests/test_bus_factor.py +0 -0
  411. {roam_code-12.17 → roam_code-12.18}/tests/test_capsule.py +0 -0
  412. {roam_code-12.17 → roam_code-12.18}/tests/test_cga.py +0 -0
  413. {roam_code-12.17 → roam_code-12.18}/tests/test_check_rules.py +0 -0
  414. {roam_code-12.17 → roam_code-12.18}/tests/test_ci_gate_eval.py +0 -0
  415. {roam_code-12.17 → roam_code-12.18}/tests/test_ci_sarif_guard.py +0 -0
  416. {roam_code-12.17 → roam_code-12.18}/tests/test_ci_setup.py +0 -0
  417. {roam_code-12.17 → roam_code-12.18}/tests/test_clones.py +0 -0
  418. {roam_code-12.17 → roam_code-12.18}/tests/test_closure.py +0 -0
  419. {roam_code-12.17 → roam_code-12.18}/tests/test_codeowners.py +0 -0
  420. {roam_code-12.17 → roam_code-12.18}/tests/test_commands_architecture.py +0 -0
  421. {roam_code-12.17 → roam_code-12.18}/tests/test_commands_exploration.py +0 -0
  422. {roam_code-12.17 → roam_code-12.18}/tests/test_commands_health.py +0 -0
  423. {roam_code-12.17 → roam_code-12.18}/tests/test_commands_refactoring.py +0 -0
  424. {roam_code-12.17 → roam_code-12.18}/tests/test_commands_workflow.py +0 -0
  425. {roam_code-12.17 → roam_code-12.18}/tests/test_competitor_site_data.py +0 -0
  426. {roam_code-12.17 → roam_code-12.18}/tests/test_comprehensive.py +0 -0
  427. {roam_code-12.17 → roam_code-12.18}/tests/test_config.py +0 -0
  428. {roam_code-12.17 → roam_code-12.18}/tests/test_congestion.py +0 -0
  429. {roam_code-12.17 → roam_code-12.18}/tests/test_context_propagation.py +0 -0
  430. {roam_code-12.17 → roam_code-12.18}/tests/test_conventions_cmd.py +0 -0
  431. {roam_code-12.17 → roam_code-12.18}/tests/test_coverage_gaps_cmd.py +0 -0
  432. {roam_code-12.17 → roam_code-12.18}/tests/test_coverage_ingestion.py +0 -0
  433. {roam_code-12.17 → roam_code-12.18}/tests/test_critique.py +0 -0
  434. {roam_code-12.17 → roam_code-12.18}/tests/test_cut.py +0 -0
  435. {roam_code-12.17 → roam_code-12.18}/tests/test_dark_matter.py +0 -0
  436. {roam_code-12.17 → roam_code-12.18}/tests/test_dark_matter_helpers.py +0 -0
  437. {roam_code-12.17 → roam_code-12.18}/tests/test_dashboard.py +0 -0
  438. {roam_code-12.17 → roam_code-12.18}/tests/test_dataflow_dead.py +0 -0
  439. {roam_code-12.17 → roam_code-12.18}/tests/test_dead_aging.py +0 -0
  440. {roam_code-12.17 → roam_code-12.18}/tests/test_defer_loading.py +0 -0
  441. {roam_code-12.17 → roam_code-12.18}/tests/test_demo_gif_asset.py +0 -0
  442. {roam_code-12.17 → roam_code-12.18}/tests/test_describe.py +0 -0
  443. {roam_code-12.17 → roam_code-12.18}/tests/test_detail_flag_hints.py +0 -0
  444. {roam_code-12.17 → roam_code-12.18}/tests/test_detector_precision.py +0 -0
  445. {roam_code-12.17 → roam_code-12.18}/tests/test_deterministic_output.py +0 -0
  446. {roam_code-12.17 → roam_code-12.18}/tests/test_dev_profile.py +0 -0
  447. {roam_code-12.17 → roam_code-12.18}/tests/test_difficulty_scoring.py +0 -0
  448. {roam_code-12.17 → roam_code-12.18}/tests/test_doc_consistency.py +0 -0
  449. {roam_code-12.17 → roam_code-12.18}/tests/test_doc_staleness.py +0 -0
  450. {roam_code-12.17 → roam_code-12.18}/tests/test_docker_assets.py +0 -0
  451. {roam_code-12.17 → roam_code-12.18}/tests/test_docs_coverage.py +0 -0
  452. {roam_code-12.17 → roam_code-12.18}/tests/test_docs_site_quality.py +0 -0
  453. {roam_code-12.17 → roam_code-12.18}/tests/test_doctor.py +0 -0
  454. {roam_code-12.17 → roam_code-12.18}/tests/test_drift.py +0 -0
  455. {roam_code-12.17 → roam_code-12.18}/tests/test_drift_by_team.py +0 -0
  456. {roam_code-12.17 → roam_code-12.18}/tests/test_duplicates.py +0 -0
  457. {roam_code-12.17 → roam_code-12.18}/tests/test_effects.py +0 -0
  458. {roam_code-12.17 → roam_code-12.18}/tests/test_effects_propagation.py +0 -0
  459. {roam_code-12.17 → roam_code-12.18}/tests/test_endpoints.py +0 -0
  460. {roam_code-12.17 → roam_code-12.18}/tests/test_entry_points_cmd.py +0 -0
  461. {roam_code-12.17 → roam_code-12.18}/tests/test_eval_retrieve.py +0 -0
  462. {roam_code-12.17 → roam_code-12.18}/tests/test_except_pass_narrow.py +0 -0
  463. {roam_code-12.17 → roam_code-12.18}/tests/test_exclude_patterns.py +0 -0
  464. {roam_code-12.17 → roam_code-12.18}/tests/test_exit_codes.py +0 -0
  465. {roam_code-12.17 → roam_code-12.18}/tests/test_extractor_grammar_drift.py +0 -0
  466. {roam_code-12.17 → roam_code-12.18}/tests/test_fallback_contracts.py +0 -0
  467. {roam_code-12.17 → roam_code-12.18}/tests/test_file_roles.py +0 -0
  468. {roam_code-12.17 → roam_code-12.18}/tests/test_fingerprint.py +0 -0
  469. {roam_code-12.17 → roam_code-12.18}/tests/test_fixes.py +0 -0
  470. {roam_code-12.17 → roam_code-12.18}/tests/test_flag_dead.py +0 -0
  471. {roam_code-12.17 → roam_code-12.18}/tests/test_fleet.py +0 -0
  472. {roam_code-12.17 → roam_code-12.18}/tests/test_fn_coupling.py +0 -0
  473. {roam_code-12.17 → roam_code-12.18}/tests/test_forecast.py +0 -0
  474. {roam_code-12.17 → roam_code-12.18}/tests/test_formatters.py +0 -0
  475. {roam_code-12.17 → roam_code-12.18}/tests/test_foxpro.py +0 -0
  476. {roam_code-12.17 → roam_code-12.18}/tests/test_framework_detection.py +0 -0
  477. {roam_code-12.17 → roam_code-12.18}/tests/test_gate_presets.py +0 -0
  478. {roam_code-12.17 → roam_code-12.18}/tests/test_git_utils.py +0 -0
  479. {roam_code-12.17 → roam_code-12.18}/tests/test_guard.py +0 -0
  480. {roam_code-12.17 → roam_code-12.18}/tests/test_health_gate.py +0 -0
  481. {roam_code-12.17 → roam_code-12.18}/tests/test_hooks.py +0 -0
  482. {roam_code-12.17 → roam_code-12.18}/tests/test_hotspots.py +0 -0
  483. {roam_code-12.17 → roam_code-12.18}/tests/test_hover.py +0 -0
  484. {roam_code-12.17 → roam_code-12.18}/tests/test_index.py +0 -0
  485. {roam_code-12.17 → roam_code-12.18}/tests/test_index_bundle.py +0 -0
  486. {roam_code-12.17 → roam_code-12.18}/tests/test_init_cmd.py +0 -0
  487. {roam_code-12.17 → roam_code-12.18}/tests/test_install_check.py +0 -0
  488. {roam_code-12.17 → roam_code-12.18}/tests/test_intent.py +0 -0
  489. {roam_code-12.17 → roam_code-12.18}/tests/test_invariants.py +0 -0
  490. {roam_code-12.17 → roam_code-12.18}/tests/test_json_contracts.py +0 -0
  491. {roam_code-12.17 → roam_code-12.18}/tests/test_json_error_envelope.py +0 -0
  492. {roam_code-12.17 → roam_code-12.18}/tests/test_kotlin_swift_extractors.py +0 -0
  493. {roam_code-12.17 → roam_code-12.18}/tests/test_language_corpus.py +0 -0
  494. {roam_code-12.17 → roam_code-12.18}/tests/test_languages.py +0 -0
  495. {roam_code-12.17 → roam_code-12.18}/tests/test_library_api.py +0 -0
  496. {roam_code-12.17 → roam_code-12.18}/tests/test_math.py +0 -0
  497. {roam_code-12.17 → roam_code-12.18}/tests/test_math_tips.py +0 -0
  498. {roam_code-12.17 → roam_code-12.18}/tests/test_mcp_extras.py +0 -0
  499. {roam_code-12.17 → roam_code-12.18}/tests/test_mcp_setup.py +0 -0
  500. {roam_code-12.17 → roam_code-12.18}/tests/test_mermaid.py +0 -0
  501. {roam_code-12.17 → roam_code-12.18}/tests/test_metrics_cmd.py +0 -0
  502. {roam_code-12.17 → roam_code-12.18}/tests/test_migration_safety.py +0 -0
  503. {roam_code-12.17 → roam_code-12.18}/tests/test_minimap.py +0 -0
  504. {roam_code-12.17 → roam_code-12.18}/tests/test_missing_index.py +0 -0
  505. {roam_code-12.17 → roam_code-12.18}/tests/test_mutate.py +0 -0
  506. {roam_code-12.17 → roam_code-12.18}/tests/test_n1.py +0 -0
  507. {roam_code-12.17 → roam_code-12.18}/tests/test_next_steps.py +0 -0
  508. {roam_code-12.17 → roam_code-12.18}/tests/test_onboard.py +0 -0
  509. {roam_code-12.17 → roam_code-12.18}/tests/test_oracle.py +0 -0
  510. {roam_code-12.17 → roam_code-12.18}/tests/test_orchestrate.py +0 -0
  511. {roam_code-12.17 → roam_code-12.18}/tests/test_orphan_routes.py +0 -0
  512. {roam_code-12.17 → roam_code-12.18}/tests/test_oss_bench_harness.py +0 -0
  513. {roam_code-12.17 → roam_code-12.18}/tests/test_over_fetch.py +0 -0
  514. {roam_code-12.17 → roam_code-12.18}/tests/test_pagerank_truncation.py +0 -0
  515. {roam_code-12.17 → roam_code-12.18}/tests/test_partition.py +0 -0
  516. {roam_code-12.17 → roam_code-12.18}/tests/test_path_coverage.py +0 -0
  517. {roam_code-12.17 → roam_code-12.18}/tests/test_patterns_cmd.py +0 -0
  518. {roam_code-12.17 → roam_code-12.18}/tests/test_performance.py +0 -0
  519. {roam_code-12.17 → roam_code-12.18}/tests/test_personalized_pagerank.py +0 -0
  520. {roam_code-12.17 → roam_code-12.18}/tests/test_plan.py +0 -0
  521. {roam_code-12.17 → roam_code-12.18}/tests/test_plugin_discovery.py +0 -0
  522. {roam_code-12.17 → roam_code-12.18}/tests/test_pr_comment_script.py +0 -0
  523. {roam_code-12.17 → roam_code-12.18}/tests/test_pr_diff.py +0 -0
  524. {roam_code-12.17 → roam_code-12.18}/tests/test_pr_risk_author.py +0 -0
  525. {roam_code-12.17 → roam_code-12.18}/tests/test_progress.py +0 -0
  526. {roam_code-12.17 → roam_code-12.18}/tests/test_progressive_disclosure.py +0 -0
  527. {roam_code-12.17 → roam_code-12.18}/tests/test_properties.py +0 -0
  528. {roam_code-12.17 → roam_code-12.18}/tests/test_pytest_fixtures.py +0 -0
  529. {roam_code-12.17 → roam_code-12.18}/tests/test_python_extractor_v2.py +0 -0
  530. {roam_code-12.17 → roam_code-12.18}/tests/test_python_idioms_e2e.py +0 -0
  531. {roam_code-12.17 → roam_code-12.18}/tests/test_python_pivot.py +0 -0
  532. {roam_code-12.17 → roam_code-12.18}/tests/test_readme_surface_consistency.py +0 -0
  533. {roam_code-12.17 → roam_code-12.18}/tests/test_realworld_feedback.py +0 -0
  534. {roam_code-12.17 → roam_code-12.18}/tests/test_refactoring_intelligence.py +0 -0
  535. {roam_code-12.17 → roam_code-12.18}/tests/test_registry_dispatch.py +0 -0
  536. {roam_code-12.17 → roam_code-12.18}/tests/test_relate.py +0 -0
  537. {roam_code-12.17 → roam_code-12.18}/tests/test_report.py +0 -0
  538. {roam_code-12.17 → roam_code-12.18}/tests/test_reset_clean.py +0 -0
  539. {roam_code-12.17 → roam_code-12.18}/tests/test_resolve.py +0 -0
  540. {roam_code-12.17 → roam_code-12.18}/tests/test_retrieve.py +0 -0
  541. {roam_code-12.17 → roam_code-12.18}/tests/test_retrieve_cross_repo.py +0 -0
  542. {roam_code-12.17 → roam_code-12.18}/tests/test_retrieve_seeds.py +0 -0
  543. {roam_code-12.17 → roam_code-12.18}/tests/test_risk.py +0 -0
  544. {roam_code-12.17 → roam_code-12.18}/tests/test_ruby.py +0 -0
  545. {roam_code-12.17 → roam_code-12.18}/tests/test_rule_profiles.py +0 -0
  546. {roam_code-12.17 → roam_code-12.18}/tests/test_rules.py +0 -0
  547. {roam_code-12.17 → roam_code-12.18}/tests/test_rules_ast_match.py +0 -0
  548. {roam_code-12.17 → roam_code-12.18}/tests/test_rules_community_pack.py +0 -0
  549. {roam_code-12.17 → roam_code-12.18}/tests/test_rules_dataflow.py +0 -0
  550. {roam_code-12.17 → roam_code-12.18}/tests/test_rules_symbol_requirements.py +0 -0
  551. {roam_code-12.17 → roam_code-12.18}/tests/test_runtime.py +0 -0
  552. {roam_code-12.17 → roam_code-12.18}/tests/test_runtime_score.py +0 -0
  553. {roam_code-12.17 → roam_code-12.18}/tests/test_salesforce.py +0 -0
  554. {roam_code-12.17 → roam_code-12.18}/tests/test_sarif_flag.py +0 -0
  555. {roam_code-12.17 → roam_code-12.18}/tests/test_sbom.py +0 -0
  556. {roam_code-12.17 → roam_code-12.18}/tests/test_scala.py +0 -0
  557. {roam_code-12.17 → roam_code-12.18}/tests/test_schema_versioning.py +0 -0
  558. {roam_code-12.17 → roam_code-12.18}/tests/test_search_explain.py +0 -0
  559. {roam_code-12.17 → roam_code-12.18}/tests/test_secrets.py +0 -0
  560. {roam_code-12.17 → roam_code-12.18}/tests/test_secrets_v2.py +0 -0
  561. {roam_code-12.17 → roam_code-12.18}/tests/test_semantic_diff.py +0 -0
  562. {roam_code-12.17 → roam_code-12.18}/tests/test_semantic_onnx.py +0 -0
  563. {roam_code-12.17 → roam_code-12.18}/tests/test_semantic_search.py +0 -0
  564. {roam_code-12.17 → roam_code-12.18}/tests/test_simulate.py +0 -0
  565. {roam_code-12.17 → roam_code-12.18}/tests/test_simulate_departure.py +0 -0
  566. {roam_code-12.17 → roam_code-12.18}/tests/test_sketch.py +0 -0
  567. {roam_code-12.17 → roam_code-12.18}/tests/test_smells.py +0 -0
  568. {roam_code-12.17 → roam_code-12.18}/tests/test_smoke.py +0 -0
  569. {roam_code-12.17 → roam_code-12.18}/tests/test_sna_metrics.py +0 -0
  570. {roam_code-12.17 → roam_code-12.18}/tests/test_spectral.py +0 -0
  571. {roam_code-12.17 → roam_code-12.18}/tests/test_split_cmd.py +0 -0
  572. {roam_code-12.17 → roam_code-12.18}/tests/test_sql.py +0 -0
  573. {roam_code-12.17 → roam_code-12.18}/tests/test_suggest_reviewers.py +0 -0
  574. {roam_code-12.17 → roam_code-12.18}/tests/test_supply_chain.py +0 -0
  575. {roam_code-12.17 → roam_code-12.18}/tests/test_surface_counts.py +0 -0
  576. {roam_code-12.17 → roam_code-12.18}/tests/test_syntax_check.py +0 -0
  577. {roam_code-12.17 → roam_code-12.18}/tests/test_taint.py +0 -0
  578. {roam_code-12.17 → roam_code-12.18}/tests/test_taint_analysis.py +0 -0
  579. {roam_code-12.17 → roam_code-12.18}/tests/test_taint_classifier.py +0 -0
  580. {roam_code-12.17 → roam_code-12.18}/tests/test_taint_intraprocedural.py +0 -0
  581. {roam_code-12.17 → roam_code-12.18}/tests/test_test_conventions.py +0 -0
  582. {roam_code-12.17 → roam_code-12.18}/tests/test_test_gaps.py +0 -0
  583. {roam_code-12.17 → roam_code-12.18}/tests/test_test_scaffold.py +0 -0
  584. {roam_code-12.17 → roam_code-12.18}/tests/test_testmap.py +0 -0
  585. {roam_code-12.17 → roam_code-12.18}/tests/test_top_flag_consistency.py +0 -0
  586. {roam_code-12.17 → roam_code-12.18}/tests/test_tour_cmd.py +0 -0
  587. {roam_code-12.17 → roam_code-12.18}/tests/test_trends.py +0 -0
  588. {roam_code-12.17 → roam_code-12.18}/tests/test_trends_cohort.py +0 -0
  589. {roam_code-12.17 → roam_code-12.18}/tests/test_triage.py +0 -0
  590. {roam_code-12.17 → roam_code-12.18}/tests/test_uses_cmd.py +0 -0
  591. {roam_code-12.17 → roam_code-12.18}/tests/test_v1215_passes.py +0 -0
  592. {roam_code-12.17 → roam_code-12.18}/tests/test_v1216_passes.py +0 -0
  593. {roam_code-12.17 → roam_code-12.18}/tests/test_v1216_passes_41_50.py +0 -0
  594. {roam_code-12.17 → roam_code-12.18}/tests/test_v1216_passes_51_60.py +0 -0
  595. {roam_code-12.17 → roam_code-12.18}/tests/test_v1217_passes_61_80.py +0 -0
  596. {roam_code-12.17 → roam_code-12.18}/tests/test_v12_2.py +0 -0
  597. {roam_code-12.17 → roam_code-12.18}/tests/test_v6_features.py +0 -0
  598. {roam_code-12.17 → roam_code-12.18}/tests/test_v71_features.py +0 -0
  599. {roam_code-12.17 → roam_code-12.18}/tests/test_v7_features.py +0 -0
  600. {roam_code-12.17 → roam_code-12.18}/tests/test_v82_features.py +0 -0
  601. {roam_code-12.17 → roam_code-12.18}/tests/test_verify.py +0 -0
  602. {roam_code-12.17 → roam_code-12.18}/tests/test_verify_imports.py +0 -0
  603. {roam_code-12.17 → roam_code-12.18}/tests/test_vibe_check.py +0 -0
  604. {roam_code-12.17 → roam_code-12.18}/tests/test_visualize.py +0 -0
  605. {roam_code-12.17 → roam_code-12.18}/tests/test_vuln.py +0 -0
  606. {roam_code-12.17 → roam_code-12.18}/tests/test_vulns_cmd.py +0 -0
  607. {roam_code-12.17 → roam_code-12.18}/tests/test_watch.py +0 -0
  608. {roam_code-12.17 → roam_code-12.18}/tests/test_why.py +0 -0
  609. {roam_code-12.17 → roam_code-12.18}/tests/test_workspace.py +0 -0
  610. {roam_code-12.17 → roam_code-12.18}/tests/test_ws_resolve_fixes.py +0 -0
  611. {roam_code-12.17 → roam_code-12.18}/tests/test_xlang.py +0 -0
  612. {roam_code-12.17 → roam_code-12.18}/tests/test_yaml_hcl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roam-code
3
- Version: 12.17
3
+ Version: 12.18
4
4
  Summary: Instant codebase comprehension for AI coding agents
5
5
  Author: CosmoHac
6
6
  License-Expression: MIT
@@ -62,9 +62,9 @@ Dynamic: license-file
62
62
 
63
63
  **Architectural sight for AI coding agents — before they edit.**
64
64
 
65
- A local code graph (SQLite + tree-sitter + git history) that gives any agent — Claude Code, Cursor, Aider, Continue, your own — five high-leverage verbs: `understand`, `retrieve`, `context`, `preflight`, `critique`. The other 167 specialised commands are advanced surface for specialised workflows.
65
+ A local code graph (SQLite + tree-sitter + git history) that gives any agent — Claude Code, Cursor, Aider, Continue, your own — five high-leverage verbs: `understand`, `retrieve`, `context`, `preflight`, `critique`. The other 172 specialised commands are advanced surface for specialised workflows.
66
66
 
67
- *172 commands · 123 MCP tools · 27 languages · 100% local · zero API keys*
67
+ *177 commands · 123 MCP tools · 27 languages · 100% local · zero API keys*
68
68
 
69
69
  [![PyPI version](https://img.shields.io/pypi/v/roam-code?style=flat-square&color=blue)](https://pypi.org/project/roam-code/)
70
70
  [![GitHub stars](https://img.shields.io/github/stars/Cranot/roam-code?style=flat-square)](https://github.com/Cranot/roam-code/stargazers)
@@ -83,7 +83,7 @@ Roam is a structural intelligence engine for software. It pre-indexes your codeb
83
83
  Unlike LSPs (editor-bound, language-specific) or Sourcegraph (hosted search), Roam provides architecture-level graph queries -- offline, cross-language, and compact. It goes beyond comprehension: Roam governs architecture through budget gates, simulates refactoring outcomes, orchestrates multi-agent swarms with zero-conflict guarantees, maps vulnerability reachability paths, and enables graph-level code editing without syntax errors.
84
84
 
85
85
  ```
86
- Codebase ──> [Index] ──> Semantic Graph ──> 155 Commands ──> AI Agent
86
+ Codebase ──> [Index] ──> Semantic Graph ──> 177 Commands ──> AI Agent
87
87
  │ │ │
88
88
  tree-sitter symbols comprehend
89
89
  27 languages + edges govern
@@ -156,7 +156,7 @@ $ roam diff # blast radius of uncommitted changes
156
156
  - **`personalized_pagerank()`** in `graph/pagerank.py`: NetworkX `personalization=` wrapper with empty-seed fallback to global PR; biases ranking toward query-relevant nodes for the retrieve reranker.
157
157
  - **`.roam/config.toml`** (new): zero-dep TOML loader (stdlib `tomllib` → `tomli` → in-tree subset parser). Tunable retrieve weights (`alpha`/`beta`/`gamma`/`delta`/`epsilon`), `tokens_per_line`, `lexical_baseline`, `first_stage_token_cap`, `default_budget`, `default_k`, `default_rerank`.
158
158
  - **DX corrections from dogfood pass**: `roam --detail <cmd>` is the canonical group-level flag; misleading "use --detail" hints in 7 commands rewritten to point users at `roam --detail <cmd>`. `--top N` aliased on `complexity`/`algo`/`rules` (`--top 0` means unlimited on `rules`). `roam fingerprint` no longer refuses graphs ≥5,000 symbols (new soft-warn threshold 20k, hard cap 100k).
159
- - **155 CLI commands, 123 MCP tools** (`fleet`, `ask`, `workflow`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`), `roam_taint_classify`, `roam_pytest_fixtures`, and `roam_hover` as MCP tools). 35-tool `core` preset is the default for token-budget-conscious clients.
159
+ - **177 CLI commands, 123 MCP tools** (`fleet`, `ask`, `workflow`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`), `roam_taint_classify`, `roam_pytest_fixtures`, and `roam_hover` as MCP tools). 35-tool `core` preset is the default for token-budget-conscious clients.
160
160
 
161
161
  ## What's New in v11
162
162
 
@@ -327,7 +327,7 @@ roam health
327
327
 
328
328
  ## Commands
329
329
 
330
- **Lead with the 5 verbs.** The [5 core commands](#core-commands) cover ~80% of agent workflows: `understand`, `context`, `retrieve`, `preflight`, `critique`. The remaining 167 commands are detail surface for specialised workflows (taint, fleet, cga, oracle, eval, …) — they're called by agents on demand, not memorised. This is intentional design; under the hood the canonical surface is **172 commands organised into 7 categories** (plus 6 aliases for muscle memory: `algo` → `math`, `weather` → `churn`, `digest` / `snapshot` / `trend` → `trends`, `onboard` → `understand`), but you don't need to know that to start.
330
+ **Lead with the 5 verbs.** The [5 core commands](#core-commands) cover ~80% of agent workflows: `understand`, `context`, `retrieve`, `preflight`, `critique`. The remaining 172 commands are detail surface for specialised workflows (taint, fleet, cga, oracle, eval, …) — they're called by agents on demand, not memorised. This is intentional design; under the hood the canonical surface is **177 commands organised into 7 categories** (plus 6 aliases for muscle memory: `algo` → `math`, `weather` → `churn`, `digest` / `snapshot` / `trend` → `trends`, `onboard` → `understand`), but you don't need to know that to start.
331
331
 
332
332
  <details>
333
333
  <summary><strong>Full command reference</strong></summary>
@@ -375,6 +375,11 @@ roam health
375
375
  | `roam api [--scope <dir>]` | List the public API surface (exported public symbols + signatures) |
376
376
  | `roam exit-codes` | List every roam exit code with its meaning |
377
377
  | `roam version [--check]` | Show installed version; with `--check` also queries PyPI for newer releases |
378
+ | `roam disambiguate <name>` | List every symbol matching the name with file/line/kind/signature/docstring snippet to pick the right one |
379
+ | `roam pre-commit [--install\|--print]` | Install or preview a roam-critique git pre-commit hook |
380
+ | `roam mcp-status` | MCP server health: preset, registered tools, backpressure limits, cache entries, watcher state |
381
+ | `roam test-impact [<range>]` | Tests transitively reachable from changed symbols (sharper scope than `affected-tests`) |
382
+ | `roam recipes` | List every `roam ask` recipe with intent + example queries (sugar over `ask --list`) |
378
383
 
379
384
  ### Daily Workflow
380
385
 
@@ -1628,7 +1633,7 @@ roam-code/
1628
1633
  ├── action.yml # Reusable GitHub Action
1629
1634
  ├── src/roam/
1630
1635
  │ ├── __init__.py # Version (from pyproject.toml)
1631
- │ ├── cli.py # Click CLI (155 canonical + 6 aliases)
1636
+ │ ├── cli.py # Click CLI (177 canonical + 7 aliases)
1632
1637
  │ ├── mcp_server.py # MCP server (122 tools, 10 resources, 5 prompts)
1633
1638
  │ ├── db/
1634
1639
  │ │ ├── connection.py # SQLite (WAL, pragmas, batched IN)
@@ -1723,7 +1728,7 @@ Optional: Local semantic ONNX stack (`numpy`, `onnxruntime`, `tokenizers`) via `
1723
1728
  ### Shipped
1724
1729
 
1725
1730
  - [x] MCP v2 agent surface: in-process execution, compound operations, presets, schemas, annotations, and compatibility profiles.
1726
- - [x] Full command and MCP inventory parity in docs: 155 canonical CLI commands and 123 MCP tools.
1731
+ - [x] Full command and MCP inventory parity in docs: 177 canonical CLI commands and 123 MCP tools.
1727
1732
  - [x] CI hardening: composite action, changed-only mode, trend-aware gates, sticky PR updater, and SARIF guardrails.
1728
1733
  - [x] Performance foundation: FTS5/BM25 search, O(changed) incremental indexing, DB/index optimizations.
1729
1734
  - [x] Agent governance suite: `vibe-check`, `ai-readiness`, `verify`, `ai-ratio`, `duplicates`, advanced `algo` scoring/SARIF.
@@ -4,9 +4,9 @@
4
4
 
5
5
  **Architectural sight for AI coding agents — before they edit.**
6
6
 
7
- A local code graph (SQLite + tree-sitter + git history) that gives any agent — Claude Code, Cursor, Aider, Continue, your own — five high-leverage verbs: `understand`, `retrieve`, `context`, `preflight`, `critique`. The other 167 specialised commands are advanced surface for specialised workflows.
7
+ A local code graph (SQLite + tree-sitter + git history) that gives any agent — Claude Code, Cursor, Aider, Continue, your own — five high-leverage verbs: `understand`, `retrieve`, `context`, `preflight`, `critique`. The other 172 specialised commands are advanced surface for specialised workflows.
8
8
 
9
- *172 commands · 123 MCP tools · 27 languages · 100% local · zero API keys*
9
+ *177 commands · 123 MCP tools · 27 languages · 100% local · zero API keys*
10
10
 
11
11
  [![PyPI version](https://img.shields.io/pypi/v/roam-code?style=flat-square&color=blue)](https://pypi.org/project/roam-code/)
12
12
  [![GitHub stars](https://img.shields.io/github/stars/Cranot/roam-code?style=flat-square)](https://github.com/Cranot/roam-code/stargazers)
@@ -25,7 +25,7 @@ Roam is a structural intelligence engine for software. It pre-indexes your codeb
25
25
  Unlike LSPs (editor-bound, language-specific) or Sourcegraph (hosted search), Roam provides architecture-level graph queries -- offline, cross-language, and compact. It goes beyond comprehension: Roam governs architecture through budget gates, simulates refactoring outcomes, orchestrates multi-agent swarms with zero-conflict guarantees, maps vulnerability reachability paths, and enables graph-level code editing without syntax errors.
26
26
 
27
27
  ```
28
- Codebase ──> [Index] ──> Semantic Graph ──> 155 Commands ──> AI Agent
28
+ Codebase ──> [Index] ──> Semantic Graph ──> 177 Commands ──> AI Agent
29
29
  │ │ │
30
30
  tree-sitter symbols comprehend
31
31
  27 languages + edges govern
@@ -98,7 +98,7 @@ $ roam diff # blast radius of uncommitted changes
98
98
  - **`personalized_pagerank()`** in `graph/pagerank.py`: NetworkX `personalization=` wrapper with empty-seed fallback to global PR; biases ranking toward query-relevant nodes for the retrieve reranker.
99
99
  - **`.roam/config.toml`** (new): zero-dep TOML loader (stdlib `tomllib` → `tomli` → in-tree subset parser). Tunable retrieve weights (`alpha`/`beta`/`gamma`/`delta`/`epsilon`), `tokens_per_line`, `lexical_baseline`, `first_stage_token_cap`, `default_budget`, `default_k`, `default_rerank`.
100
100
  - **DX corrections from dogfood pass**: `roam --detail <cmd>` is the canonical group-level flag; misleading "use --detail" hints in 7 commands rewritten to point users at `roam --detail <cmd>`. `--top N` aliased on `complexity`/`algo`/`rules` (`--top 0` means unlimited on `rules`). `roam fingerprint` no longer refuses graphs ≥5,000 symbols (new soft-warn threshold 20k, hard cap 100k).
101
- - **155 CLI commands, 123 MCP tools** (`fleet`, `ask`, `workflow`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`), `roam_taint_classify`, `roam_pytest_fixtures`, and `roam_hover` as MCP tools). 35-tool `core` preset is the default for token-budget-conscious clients.
101
+ - **177 CLI commands, 123 MCP tools** (`fleet`, `ask`, `workflow`, `cga`, `eval-retrieve` remain CLI-only; v12 exposes `roam_retrieve`, `roam_critique`, `roam_fleet_plan`, plus 5 v12.1 boolean oracles (`roam_oracle_*`), `roam_taint_classify`, `roam_pytest_fixtures`, and `roam_hover` as MCP tools). 35-tool `core` preset is the default for token-budget-conscious clients.
102
102
 
103
103
  ## What's New in v11
104
104
 
@@ -269,7 +269,7 @@ roam health
269
269
 
270
270
  ## Commands
271
271
 
272
- **Lead with the 5 verbs.** The [5 core commands](#core-commands) cover ~80% of agent workflows: `understand`, `context`, `retrieve`, `preflight`, `critique`. The remaining 167 commands are detail surface for specialised workflows (taint, fleet, cga, oracle, eval, …) — they're called by agents on demand, not memorised. This is intentional design; under the hood the canonical surface is **172 commands organised into 7 categories** (plus 6 aliases for muscle memory: `algo` → `math`, `weather` → `churn`, `digest` / `snapshot` / `trend` → `trends`, `onboard` → `understand`), but you don't need to know that to start.
272
+ **Lead with the 5 verbs.** The [5 core commands](#core-commands) cover ~80% of agent workflows: `understand`, `context`, `retrieve`, `preflight`, `critique`. The remaining 172 commands are detail surface for specialised workflows (taint, fleet, cga, oracle, eval, …) — they're called by agents on demand, not memorised. This is intentional design; under the hood the canonical surface is **177 commands organised into 7 categories** (plus 6 aliases for muscle memory: `algo` → `math`, `weather` → `churn`, `digest` / `snapshot` / `trend` → `trends`, `onboard` → `understand`), but you don't need to know that to start.
273
273
 
274
274
  <details>
275
275
  <summary><strong>Full command reference</strong></summary>
@@ -317,6 +317,11 @@ roam health
317
317
  | `roam api [--scope <dir>]` | List the public API surface (exported public symbols + signatures) |
318
318
  | `roam exit-codes` | List every roam exit code with its meaning |
319
319
  | `roam version [--check]` | Show installed version; with `--check` also queries PyPI for newer releases |
320
+ | `roam disambiguate <name>` | List every symbol matching the name with file/line/kind/signature/docstring snippet to pick the right one |
321
+ | `roam pre-commit [--install\|--print]` | Install or preview a roam-critique git pre-commit hook |
322
+ | `roam mcp-status` | MCP server health: preset, registered tools, backpressure limits, cache entries, watcher state |
323
+ | `roam test-impact [<range>]` | Tests transitively reachable from changed symbols (sharper scope than `affected-tests`) |
324
+ | `roam recipes` | List every `roam ask` recipe with intent + example queries (sugar over `ask --list`) |
320
325
 
321
326
  ### Daily Workflow
322
327
 
@@ -1570,7 +1575,7 @@ roam-code/
1570
1575
  ├── action.yml # Reusable GitHub Action
1571
1576
  ├── src/roam/
1572
1577
  │ ├── __init__.py # Version (from pyproject.toml)
1573
- │ ├── cli.py # Click CLI (155 canonical + 6 aliases)
1578
+ │ ├── cli.py # Click CLI (177 canonical + 7 aliases)
1574
1579
  │ ├── mcp_server.py # MCP server (122 tools, 10 resources, 5 prompts)
1575
1580
  │ ├── db/
1576
1581
  │ │ ├── connection.py # SQLite (WAL, pragmas, batched IN)
@@ -1665,7 +1670,7 @@ Optional: Local semantic ONNX stack (`numpy`, `onnxruntime`, `tokenizers`) via `
1665
1670
  ### Shipped
1666
1671
 
1667
1672
  - [x] MCP v2 agent surface: in-process execution, compound operations, presets, schemas, annotations, and compatibility profiles.
1668
- - [x] Full command and MCP inventory parity in docs: 155 canonical CLI commands and 123 MCP tools.
1673
+ - [x] Full command and MCP inventory parity in docs: 177 canonical CLI commands and 123 MCP tools.
1669
1674
  - [x] CI hardening: composite action, changed-only mode, trend-aware gates, sticky PR updater, and SARIF guardrails.
1670
1675
  - [x] Performance foundation: FTS5/BM25 search, O(changed) incremental indexing, DB/index optimizations.
1671
1676
  - [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 = "12.17"
7
+ version = "12.18"
8
8
  description = "Instant codebase comprehension for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -126,6 +126,11 @@ _COMMANDS = {
126
126
  "api": ("roam.commands.cmd_api", "api"),
127
127
  "exit-codes": ("roam.commands.cmd_exit_codes", "exit_codes"),
128
128
  "version": ("roam.commands.cmd_version", "version"),
129
+ "disambiguate": ("roam.commands.cmd_disambiguate", "disambiguate"),
130
+ "pre-commit": ("roam.commands.cmd_pre_commit", "pre_commit"),
131
+ "mcp-status": ("roam.commands.cmd_mcp_status", "mcp_status"),
132
+ "test-impact": ("roam.commands.cmd_test_impact", "test_impact"),
133
+ "recipes": ("roam.commands.cmd_recipes", "recipes"),
129
134
  "forecast": ("roam.commands.cmd_forecast", "forecast"),
130
135
  "plan": ("roam.commands.cmd_plan", "plan"),
131
136
  "adversarial": ("roam.commands.cmd_adversarial", "adversarial"),
@@ -237,12 +242,15 @@ _CATEGORIES = {
237
242
  "schema",
238
243
  "mcp",
239
244
  "mcp-setup",
245
+ "mcp-status",
240
246
  "ci-setup",
241
247
  "adrs",
242
248
  "changelog",
243
249
  "exit-codes",
244
250
  "help-search",
245
251
  "plugins",
252
+ "pre-commit",
253
+ "recipes",
246
254
  "version",
247
255
  "index-stats",
248
256
  "stats",
@@ -271,10 +279,12 @@ _CATEGORIES = {
271
279
  "critique",
272
280
  "fleet",
273
281
  "affected-tests",
282
+ "test-impact",
274
283
  "diagnose",
275
284
  "why-fail",
276
285
  "recommend",
277
286
  "api",
287
+ "disambiguate",
278
288
  "annotate",
279
289
  "annotations",
280
290
  "plan",
@@ -0,0 +1,98 @@
1
+ """``roam disambiguate <name>`` — list every symbol matching this name.
2
+
3
+ Pass 81 — agents calling ``roam search`` then picking the first result
4
+ sometimes pick the wrong one when several functions share a name.
5
+ This command shows all matches with the disambiguators (file, line,
6
+ kind, signature, first docstring line) plus PageRank as a tiebreaker.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import click
12
+
13
+ from roam.commands.resolve import ensure_index
14
+ from roam.db.connection import open_db
15
+ from roam.output.formatter import json_envelope, to_json
16
+
17
+
18
+ @click.command()
19
+ @click.argument("name")
20
+ @click.option("--limit", type=int, default=20, show_default=True, help="Max matches to display.")
21
+ @click.pass_context
22
+ def disambiguate(ctx, name, limit) -> None:
23
+ """List every symbol matching <name> with disambiguators.
24
+
25
+ Match tiers, in order:
26
+ 1. ``s.name = name`` (exact name match)
27
+ 2. ``s.qualified_name = name`` (exact qname)
28
+ 3. ``s.qualified_name LIKE '%.name'`` (suffix qname)
29
+ """
30
+ json_mode = ctx.obj.get("json") if ctx.obj else False
31
+ ensure_index()
32
+
33
+ with open_db(readonly=True) as conn:
34
+ rows = conn.execute(
35
+ """
36
+ SELECT s.id, s.name, s.qualified_name, s.kind, s.signature,
37
+ s.docstring, s.line_start, f.path,
38
+ COALESCE(gm.pagerank, 0) AS pagerank
39
+ FROM symbols s
40
+ JOIN files f ON f.id = s.file_id
41
+ LEFT JOIN graph_metrics gm ON gm.symbol_id = s.id
42
+ WHERE s.name = ?
43
+ OR s.qualified_name = ?
44
+ OR s.qualified_name LIKE ?
45
+ ORDER BY pagerank DESC, s.name
46
+ LIMIT ?
47
+ """,
48
+ (name, name, f"%.{name}", int(limit)),
49
+ ).fetchall()
50
+
51
+ matches = []
52
+ for r in rows:
53
+ doc_first = ""
54
+ if r["docstring"]:
55
+ stripped = (r["docstring"] or "").strip().splitlines()
56
+ doc_first = stripped[0] if stripped else ""
57
+ matches.append(
58
+ {
59
+ "name": r["name"],
60
+ "qualified_name": r["qualified_name"],
61
+ "kind": r["kind"],
62
+ "signature": (r["signature"] or "").strip(),
63
+ "docstring_summary": doc_first,
64
+ "file": r["path"],
65
+ "line": r["line_start"],
66
+ "pagerank": round(float(r["pagerank"]), 6),
67
+ }
68
+ )
69
+
70
+ verdict = (
71
+ f"no symbol matching '{name}'"
72
+ if not matches
73
+ else f"{len(matches)} symbol(s) matching '{name}' (top: {matches[0]['qualified_name'] or matches[0]['name']})"
74
+ )
75
+
76
+ if json_mode:
77
+ click.echo(
78
+ to_json(
79
+ json_envelope(
80
+ "disambiguate",
81
+ summary={"verdict": verdict, "count": len(matches)},
82
+ matches=matches,
83
+ )
84
+ )
85
+ )
86
+ return
87
+
88
+ click.echo(f"VERDICT: {verdict}")
89
+ if not matches:
90
+ return
91
+ click.echo()
92
+ for m in matches:
93
+ ident = m["qualified_name"] or m["name"]
94
+ click.echo(f" {m['kind']:<10} {ident} ({m['file']}:{m['line']}) PR={m['pagerank']:.5f}")
95
+ if m["signature"]:
96
+ click.echo(f" sig: {m['signature'][:100]}")
97
+ if m["docstring_summary"]:
98
+ click.echo(f" doc: {m['docstring_summary'][:100]}")
@@ -42,8 +42,23 @@ def _build_symbol_entry_text(s, *, for_budget: bool = False) -> str:
42
42
  @click.option("-n", "count", default=20, help="Number of top symbols to show")
43
43
  @click.option("--full", is_flag=True, help="Show all results without truncation")
44
44
  @click.option("--budget", type=int, default=None, help="Approximate token limit for output")
45
+ @click.option(
46
+ "--seed",
47
+ "seed_path",
48
+ type=str,
49
+ default=None,
50
+ help="Pass 90 — restrict the top-symbols list to symbols reachable from this file.",
51
+ )
52
+ @click.option(
53
+ "--depth",
54
+ "seed_depth",
55
+ type=int,
56
+ default=2,
57
+ show_default=True,
58
+ help="Pass 90 — BFS hop limit when --seed is given.",
59
+ )
45
60
  @click.pass_context
46
- def map_cmd(ctx, count, full, budget):
61
+ def map_cmd(ctx, count, full, budget, seed_path, seed_depth):
47
62
  """Show project skeleton with entry points and key symbols.
48
63
 
49
64
  Unlike ``describe`` (which generates a prose project overview), this
@@ -96,6 +111,36 @@ def map_cmd(ctx, count, full, budget):
96
111
  fetch_limit = count if budget is None else 10_000
97
112
  all_ranked = conn.execute(TOP_SYMBOLS_BY_PAGERANK, (fetch_limit,)).fetchall()
98
113
 
114
+ # Pass 90 — if a seed file is given, narrow ``all_ranked`` to
115
+ # symbols reachable from that file within ``seed_depth`` hops.
116
+ if seed_path:
117
+ try:
118
+ import networkx as nx
119
+
120
+ from roam.graph.builder import build_symbol_graph
121
+ except ImportError:
122
+ seed_path = None # graph unavailable, fall through
123
+ if seed_path:
124
+ seed_norm = seed_path.replace("\\", "/")
125
+ seed_rows = conn.execute(
126
+ "SELECT s.id FROM symbols s JOIN files f ON f.id = s.file_id "
127
+ "WHERE REPLACE(f.path, '\\', '/') = ? OR REPLACE(f.path, '\\', '/') LIKE ?",
128
+ (seed_norm, f"{seed_norm}%"),
129
+ ).fetchall()
130
+ seed_ids = [r["id"] for r in seed_rows]
131
+ if seed_ids:
132
+ G = build_symbol_graph(conn)
133
+ reach: set[int] = set(seed_ids)
134
+ for sid in seed_ids:
135
+ if sid not in G:
136
+ continue
137
+ try:
138
+ lengths = nx.single_source_shortest_path_length(G, sid, cutoff=int(seed_depth))
139
+ reach.update(lengths.keys())
140
+ except Exception:
141
+ continue
142
+ all_ranked = [r for r in all_ranked if r["id"] in reach]
143
+
99
144
  # ---- Budget-aware symbol selection ----
100
145
  if budget is not None:
101
146
  # Pre-compute the preamble (stats, dirs, entries) to account
@@ -0,0 +1,89 @@
1
+ """``roam mcp-status`` — health check for the MCP server.
2
+
3
+ Pass 83 — companion to ``roam doctor``. Reports:
4
+
5
+ * preset (core / review / refactor / debug / architecture / full)
6
+ * registered tool count + core tool count
7
+ * backpressure limits (max_concurrent, in_flight, per-tool overrides)
8
+ * MCP-level result cache size + hit-rate (if anything cached this session)
9
+ * recent ``busy_responses_total`` count
10
+ * watcher status (if ROAM_MCP_WATCH=1)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import os
16
+
17
+ import click
18
+
19
+ from roam.output.formatter import json_envelope, to_json
20
+
21
+
22
+ @click.command(name="mcp-status")
23
+ @click.pass_context
24
+ def mcp_status(ctx) -> None:
25
+ """Report MCP server status: preset, tools, backpressure, cache, watcher."""
26
+ json_mode = ctx.obj.get("json") if ctx.obj else False
27
+
28
+ preset = os.environ.get("ROAM_MCP_PRESET", "core")
29
+ watch_enabled = os.environ.get("ROAM_MCP_WATCH", "").strip() in {"1", "true", "yes"}
30
+
31
+ try:
32
+ from roam.mcp_server import _CORE_TOOLS, _REGISTERED_TOOLS, _ROAM_RESULT_CACHE
33
+ except Exception as exc:
34
+ msg = f"MCP server module unavailable: {type(exc).__name__}: {exc}"
35
+ if json_mode:
36
+ click.echo(to_json(json_envelope("mcp-status", summary={"verdict": msg, "ready": False})))
37
+ else:
38
+ click.echo(f"VERDICT: {msg}")
39
+ return
40
+
41
+ try:
42
+ from roam.mcp_extras.concurrency import metrics as concurrency_metrics
43
+
44
+ bp = concurrency_metrics()
45
+ except Exception:
46
+ bp = {"max_concurrent": None, "in_flight": None, "busy_responses_total": None, "per_tool_limits": {}}
47
+
48
+ cache_size = len(_ROAM_RESULT_CACHE)
49
+ registered = len(_REGISTERED_TOOLS)
50
+ core_count = sum(1 for n in _REGISTERED_TOOLS if n in _CORE_TOOLS)
51
+
52
+ verdict = (
53
+ f"MCP ready — preset={preset}, {registered} tools registered "
54
+ f"({core_count} core), max_concurrent={bp.get('max_concurrent')}"
55
+ )
56
+
57
+ if json_mode:
58
+ click.echo(
59
+ to_json(
60
+ json_envelope(
61
+ "mcp-status",
62
+ summary={
63
+ "verdict": verdict,
64
+ "preset": preset,
65
+ "tools_registered": registered,
66
+ "core_tool_count": core_count,
67
+ "max_concurrent": bp.get("max_concurrent"),
68
+ "in_flight": bp.get("in_flight"),
69
+ "busy_responses_total": bp.get("busy_responses_total"),
70
+ "cache_entries": cache_size,
71
+ "watcher_enabled": watch_enabled,
72
+ },
73
+ backpressure=bp,
74
+ )
75
+ )
76
+ )
77
+ return
78
+
79
+ click.echo(f"VERDICT: {verdict}")
80
+ click.echo()
81
+ click.echo(f"Preset: {preset}")
82
+ click.echo(f"Tools registered: {registered}")
83
+ click.echo(f" of which core preset: {core_count}")
84
+ click.echo(f"Max concurrent: {bp.get('max_concurrent')}")
85
+ click.echo(f"In flight (now): {bp.get('in_flight')}")
86
+ click.echo(f"Busy responses total: {bp.get('busy_responses_total')}")
87
+ click.echo(f"Per-tool override count: {len(bp.get('per_tool_limits') or {})}")
88
+ click.echo(f"Result-cache entries: {cache_size}")
89
+ click.echo(f"Watcher enabled: {'yes' if watch_enabled else 'no'}")
@@ -0,0 +1,120 @@
1
+ """``roam pre-commit`` — install or print a git pre-commit hook.
2
+
3
+ Pass 82 — generates a hook that runs ``git diff --cached | roam critique``
4
+ on staged changes, exiting non-zero on high-severity findings. Idempotent:
5
+ installing twice is a no-op (rewrites the same content).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pathlib import Path
11
+
12
+ import click
13
+
14
+ from roam.commands.resolve import ensure_index
15
+ from roam.db.connection import find_project_root
16
+ from roam.output.formatter import json_envelope, to_json
17
+
18
+ _HOOK_NAME = "pre-commit"
19
+ _HOOK_TEMPLATE = """#!/bin/sh
20
+ # Generated by `roam pre-commit --install`. Idempotent.
21
+ # Runs roam critique on staged changes. Exit 5 = high-severity finding.
22
+ # Set ROAM_PRECOMMIT_SKIP=1 to bypass.
23
+
24
+ if [ "${ROAM_PRECOMMIT_SKIP:-0}" = "1" ]; then
25
+ exit 0
26
+ fi
27
+
28
+ if ! command -v roam >/dev/null 2>&1; then
29
+ echo "roam not on PATH; install with `pip install roam-code` or set ROAM_PRECOMMIT_SKIP=1." >&2
30
+ exit 0
31
+ fi
32
+
33
+ DIFF="$(git diff --cached)"
34
+ if [ -z "$DIFF" ]; then
35
+ exit 0
36
+ fi
37
+
38
+ echo "$DIFF" | roam critique
39
+ status=$?
40
+ case "$status" in
41
+ 0) exit 0 ;;
42
+ 5) echo "roam critique flagged a high-severity finding. ROAM_PRECOMMIT_SKIP=1 to bypass." >&2 ; exit 1 ;;
43
+ *) echo "roam critique exited $status — not blocking. ROAM_PRECOMMIT_SKIP=1 to silence." >&2 ; exit 0 ;;
44
+ esac
45
+ """
46
+
47
+
48
+ def _hooks_dir(root: Path) -> Path:
49
+ return root / ".git" / "hooks"
50
+
51
+
52
+ @click.command(name="pre-commit")
53
+ @click.option("--install", is_flag=True, help="Write the hook into .git/hooks/pre-commit (idempotent).")
54
+ @click.option("--print", "print_only", is_flag=True, help="Print the hook script to stdout instead of installing.")
55
+ @click.pass_context
56
+ def pre_commit(ctx, install, print_only) -> None:
57
+ """Install or preview a roam-critique pre-commit git hook."""
58
+ json_mode = ctx.obj.get("json") if ctx.obj else False
59
+ ensure_index()
60
+ root = find_project_root()
61
+ hooks = _hooks_dir(root)
62
+ target = hooks / _HOOK_NAME
63
+
64
+ if print_only or (not install):
65
+ if json_mode:
66
+ click.echo(
67
+ to_json(
68
+ json_envelope(
69
+ "pre-commit",
70
+ summary={
71
+ "verdict": "preview-only — pass --install to write the hook",
72
+ "target": str(target),
73
+ "exists": target.exists(),
74
+ },
75
+ script=_HOOK_TEMPLATE,
76
+ )
77
+ )
78
+ )
79
+ else:
80
+ click.echo(f"# Would write to: {target}")
81
+ click.echo()
82
+ click.echo(_HOOK_TEMPLATE)
83
+ click.echo()
84
+ click.echo("Run `roam pre-commit --install` to write the hook.")
85
+ return
86
+
87
+ if not (root / ".git").exists():
88
+ verdict = f"no .git directory under {root} — run from inside a git repository"
89
+ if json_mode:
90
+ click.echo(to_json(json_envelope("pre-commit", summary={"verdict": verdict, "installed": False})))
91
+ else:
92
+ click.echo(f"VERDICT: {verdict}")
93
+ ctx.exit(2)
94
+ return
95
+
96
+ hooks.mkdir(parents=True, exist_ok=True)
97
+ existing = target.read_text(encoding="utf-8") if target.exists() else None
98
+ if existing == _HOOK_TEMPLATE:
99
+ verdict = f"hook already up to date at {target}"
100
+ else:
101
+ target.write_text(_HOOK_TEMPLATE, encoding="utf-8")
102
+ try:
103
+ # chmod +x on POSIX. On Windows the bit is ignored but harmless.
104
+ target.chmod(0o755)
105
+ except OSError:
106
+ pass
107
+ verdict = f"installed roam pre-commit hook to {target}"
108
+
109
+ if json_mode:
110
+ click.echo(
111
+ to_json(
112
+ json_envelope(
113
+ "pre-commit",
114
+ summary={"verdict": verdict, "installed": True, "target": str(target)},
115
+ )
116
+ )
117
+ )
118
+ return
119
+ click.echo(f"VERDICT: {verdict}")
120
+ click.echo(" ROAM_PRECOMMIT_SKIP=1 to bypass on a single commit.")
@@ -0,0 +1,53 @@
1
+ """``roam recipes`` — list every ask recipe with intent + examples.
2
+
3
+ Pass 88 — sugar over ``roam ask --list`` for discoverability. Useful as
4
+ the first thing an agent runs to see what natural-language tasks
5
+ ``roam ask`` handles.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import click
11
+
12
+ from roam.ask.recipes import RECIPES
13
+ from roam.output.formatter import json_envelope, to_json
14
+
15
+
16
+ @click.command()
17
+ @click.pass_context
18
+ def recipes(ctx) -> None:
19
+ """List every ``roam ask`` recipe with intent + example queries."""
20
+ json_mode = ctx.obj.get("json") if ctx.obj else False
21
+ items = [
22
+ {
23
+ "name": r.name,
24
+ "intent": r.intent,
25
+ "phase": r.phase,
26
+ "examples": list(r.examples),
27
+ "commands": [{"cmd": c[0], "args": list(c[1])} for c in r.commands],
28
+ }
29
+ for r in RECIPES
30
+ ]
31
+ items.sort(key=lambda x: x["name"])
32
+ verdict = f"{len(items)} ask recipe(s) in registry"
33
+
34
+ if json_mode:
35
+ click.echo(
36
+ to_json(
37
+ json_envelope(
38
+ "recipes",
39
+ summary={"verdict": verdict, "count": len(items)},
40
+ recipes=items,
41
+ )
42
+ )
43
+ )
44
+ return
45
+
46
+ click.echo(f"VERDICT: {verdict}")
47
+ click.echo()
48
+ click.echo(f"{'Name':<26} {'Phase':<14} Intent")
49
+ click.echo(f"{'-' * 26} {'-' * 14} {'-' * 50}")
50
+ for it in items:
51
+ click.echo(f"{it['name']:<26} {it['phase'][:14]:<14} {it['intent'][:60]}")
52
+ click.echo()
53
+ click.echo('Run `roam ask "<query>"` to dispatch by intent.')