sql-code-graph 1.4.3__tar.gz → 1.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/PKG-INFO +1 -1
  2. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/docs/cli.md +18 -10
  3. sql_code_graph-1.5.0/plan/version-parity-and-restart.md +390 -0
  4. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/pyproject.toml +1 -1
  5. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/__init__.py +1 -1
  6. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/install.py +56 -43
  7. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/mcp.py +58 -10
  8. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/main.py +34 -3
  9. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/models.py +3 -0
  10. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/server.py +9 -0
  11. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/tools.py +11 -1
  12. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_install.py +80 -0
  13. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_mcp_control.py +130 -0
  14. sql_code_graph-1.5.0/tests/unit/test_version_parity.py +148 -0
  15. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/uv.lock +1 -1
  16. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.claude/agents/api-documenter.md +0 -0
  17. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.claude/agents/architect-planner.md +0 -0
  18. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.claude/agents/architect-reviewer.md +0 -0
  19. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.claude/agents/code-reviewer.md +0 -0
  20. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.claude/agents/developer.md +0 -0
  21. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.claude/agents/plan-reviewer.md +0 -0
  22. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.claude/agents/sprint-planner.md +0 -0
  23. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  24. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  25. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  26. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.github/workflows/benchmark.yml +0 -0
  27. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.github/workflows/e2e-tests.yml +0 -0
  28. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.github/workflows/release.yml +0 -0
  29. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.github/workflows/test.yml +0 -0
  30. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.gitignore +0 -0
  31. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.pre-commit-config.yaml +0 -0
  32. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/.sqlcgignore +0 -0
  33. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/ARCHITECTURE_REVIEW.md +0 -0
  34. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/CHANGELOG.md +0 -0
  35. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/CLAUDE.md +0 -0
  36. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/README.md +0 -0
  37. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/docs/AIRBNB_PARSE_REPORT.md +0 -0
  38. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/e2e_firstuser_report.md +0 -0
  39. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/e2e_run_20260528_101413.output +0 -0
  40. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/main.py +0 -0
  41. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/WORKFLOW.md +0 -0
  42. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/blueprint.md +0 -0
  43. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/bundle_claude_skill.md +0 -0
  44. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/diff-impact-producer-file.md +0 -0
  45. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/feature_34_unused_presentation_segregation.md +0 -0
  46. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/feature_35_external_downstream_injection.md +0 -0
  47. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/feature_F2_bundle_claude_skill.md +0 -0
  48. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/feature_kuzu_to_duckdb_migration.md +0 -0
  49. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/fix_downstream_sink_location.md +0 -0
  50. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/fix_dynamic_table_parsing.md +0 -0
  51. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/fix_expand_qualify_perf.md +0 -0
  52. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/fix_firstuser_findings.md +0 -0
  53. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/fix_issue29_live_test_followups.md +0 -0
  54. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/fix_schema_case_mismatch.md +0 -0
  55. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/hygiene_config_path_and_survivors.md +0 -0
  56. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/investigation_e5_e4.md +0 -0
  57. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/issue-38-backfill-cte-bridge.md +0 -0
  58. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/living_codebase_resync.md +0 -0
  59. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/measurements/schema_comparison_with_schema.json +0 -0
  60. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/measurements/schema_comparison_without_schema.json +0 -0
  61. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/measurements/sprint_08_changelogs_fullindex.json +0 -0
  62. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/measurements/sprint_08_fullcorpus_index.json +0 -0
  63. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/measurements/sprint_pool_300s_plan.json +0 -0
  64. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/parse_diagnostics.md +0 -0
  65. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/parsing_errors_experiment.md +0 -0
  66. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/snowflake_en_test_suite.md +0 -0
  67. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_01.md +0 -0
  68. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_01_deployment_pypi.md +0 -0
  69. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_02.md +0 -0
  70. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_02_v0.3.0_core.md +0 -0
  71. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_03.md +0 -0
  72. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_03_v0.3.1_postmortem.md +0 -0
  73. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_04_column_lineage.md +0 -0
  74. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_04_column_lineage_fix.md +0 -0
  75. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_05_star_resolution.md +0 -0
  76. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_06_lineage_coverage.md +0 -0
  77. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_07_open_ecodes.md +0 -0
  78. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_07_perf_and_live_test.md +0 -0
  79. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_08_perf_upsert.md +0 -0
  80. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_09_lineage_coverage.md +0 -0
  81. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_10_anchor_tools.md +0 -0
  82. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_11_v1.0.2_bugfix.md +0 -0
  83. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_12_v1.1.0.md +0 -0
  84. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_13_v1.1.0_cluster_b.md +0 -0
  85. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sprint_3.1_postmortem.md +0 -0
  86. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/sqlcg.md +0 -0
  87. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/trust_layer.md +0 -0
  88. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/v1.1.0_cluster_b_provenance_trust.md +0 -0
  89. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/v1.1.0_live_graph_freshness.md +0 -0
  90. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/v1.1.1_batch_upsert_perf.md +0 -0
  91. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/v1_1_2_bugfix.md +0 -0
  92. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/v1_1_3_union_cte_star.md +0 -0
  93. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/v1_2_0_read_proxy.md +0 -0
  94. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/plan/v1_2_1_bugfix.md +0 -0
  95. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/profile.html +0 -0
  96. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/pyrightconfig.json +0 -0
  97. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/scripts/collect_parse_errors.py +0 -0
  98. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/scripts/generate_cli_docs.sh +0 -0
  99. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/__main__.py +0 -0
  100. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/__init__.py +0 -0
  101. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/__init__.py +0 -0
  102. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/analyze.py +0 -0
  103. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/db.py +0 -0
  104. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/find.py +0 -0
  105. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/gain.py +0 -0
  106. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/git.py +0 -0
  107. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/index.py +0 -0
  108. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/reindex.py +0 -0
  109. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/report.py +0 -0
  110. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/uninstall.py +0 -0
  111. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/cli/commands/watch.py +0 -0
  112. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/__init__.py +0 -0
  113. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/config.py +0 -0
  114. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/duckdb_backend.py +0 -0
  115. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/freshness.py +0 -0
  116. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/graph_db.py +0 -0
  117. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/jobs.py +0 -0
  118. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/queries.cypher +0 -0
  119. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/queries.py +0 -0
  120. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/queries.sql +0 -0
  121. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/schema.cypher +0 -0
  122. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/core/schema.py +0 -0
  123. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/__init__.py +0 -0
  124. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/dbt_adapter.py +0 -0
  125. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/error_classify.py +0 -0
  126. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/git_delta.py +0 -0
  127. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/indexer.py +0 -0
  128. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/pool.py +0 -0
  129. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/walker.py +0 -0
  130. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/indexer/watcher.py +0 -0
  131. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/lineage/__init__.py +0 -0
  132. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/lineage/aggregator.py +0 -0
  133. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/lineage/schema_resolver.py +0 -0
  134. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/metrics/__init__.py +0 -0
  135. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/metrics/store.py +0 -0
  136. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/__init__.py +0 -0
  137. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/ansi_parser.py +0 -0
  138. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/base.py +0 -0
  139. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/bigquery_parser.py +0 -0
  140. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/postgres_parser.py +0 -0
  141. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/registry.py +0 -0
  142. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/snowflake_parser.py +0 -0
  143. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/parsers/tsql_parser.py +0 -0
  144. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/__init__.py +0 -0
  145. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/control.py +0 -0
  146. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/exceptions.py +0 -0
  147. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/noise_filter.py +0 -0
  148. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/read_client.py +0 -0
  149. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/skill.py +0 -0
  150. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/server/writer.py +0 -0
  151. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/utils/__init__.py +0 -0
  152. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/utils/hashing.py +0 -0
  153. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/utils/ignore.py +0 -0
  154. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/src/sqlcg/utils/logging.py +0 -0
  155. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/__init__.py +0 -0
  156. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/__init__.py +0 -0
  157. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/adversarial/200_join.sql +0 -0
  158. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/adversarial/500_union.sql +0 -0
  159. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/bench_indexer.py +0 -0
  160. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/conftest.py +0 -0
  161. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/case_normalization.sql +0 -0
  162. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/colon_cast.sql +0 -0
  163. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/colon_reserved_word.sql +0 -0
  164. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/copy_into.sql +0 -0
  165. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/create_procedure.sql +0 -0
  166. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/identifier_dynamic.sql +0 -0
  167. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/lateral_flatten.sql +0 -0
  168. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/qualify.sql +0 -0
  169. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/scripting_block.sql +0 -0
  170. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/golden_corpus/snowflake/three_part.sql +0 -0
  171. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q01.sql +0 -0
  172. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q02.sql +0 -0
  173. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q03.sql +0 -0
  174. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q04.sql +0 -0
  175. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/benchmarks/tpch/q05.sql +0 -0
  176. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/__init__.py +0 -0
  177. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/conftest.py +0 -0
  178. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_F2_skill_install_e2e.py +0 -0
  179. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_airbnb_e2e.py +0 -0
  180. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_cli_index.py +0 -0
  181. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_git_hook_install.py +0 -0
  182. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_golden_lineage.py +0 -0
  183. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_mcp_lifecycle.py +0 -0
  184. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_mcp_tools.py +0 -0
  185. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_parse_diagnostics_cli.py +0 -0
  186. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_star_resolution_e2e.py +0 -0
  187. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/e2e/test_watch.py +0 -0
  188. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/dim_hosts_cleansed.sql +0 -0
  189. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/dim_listings_cleansed.sql +0 -0
  190. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/fct_reviews.sql +0 -0
  191. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/mart_fullmoon_reviews.sql +0 -0
  192. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/raw_hosts.sql +0 -0
  193. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/raw_listings.sql +0 -0
  194. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/raw_reviews.sql +0 -0
  195. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/src_hosts.sql +0 -0
  196. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/src_listings.sql +0 -0
  197. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/airbnb/src_reviews.sql +0 -0
  198. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/bigquery/.gitkeep +0 -0
  199. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/duckdb_parity/kuzu_reference.json +0 -0
  200. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/jaffle_shop/customers.sql +0 -0
  201. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/jaffle_shop/orders.sql +0 -0
  202. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/jaffle_shop/raw_orders.sql +0 -0
  203. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/snowflake/base_tables.sql +0 -0
  204. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/snowflake/reports.sql +0 -0
  205. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/snowflake/views.sql +0 -0
  206. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/ddl_src.sql +0 -0
  207. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/ddl_tgt.sql +0 -0
  208. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/etl_alias_star.sql +0 -0
  209. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/star_corpus/etl_star.sql +0 -0
  210. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/synthetic/base_tables.sql +0 -0
  211. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/synthetic/reports.sql +0 -0
  212. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/fixtures/synthetic/views.sql +0 -0
  213. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/__init__.py +0 -0
  214. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/snowflake/__init__.py +0 -0
  215. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/snowflake/test_insert_select.py +0 -0
  216. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_T34_presentation_segregation.py +0 -0
  217. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_T35_external_consumers.py +0 -0
  218. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_analyze_case_fold.py +0 -0
  219. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_anchor_tools.py +0 -0
  220. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_backfill_impact_consistency.py +0 -0
  221. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_bare_column_cte_lineage.py +0 -0
  222. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_bulk_upsert.py +0 -0
  223. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_case_split_seed_regression.py +0 -0
  224. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_column_lineage_e2e.py +0 -0
  225. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_cross_file_lineage.py +0 -0
  226. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_cte_recall_guard.py +0 -0
  227. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_cte_schema_alias_guard.py +0 -0
  228. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_cte_source_node_invariant.py +0 -0
  229. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_dialect_auto_resolution.py +0 -0
  230. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_dialect_matrix.py +0 -0
  231. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_duckdb_parity.py +0 -0
  232. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_e36_xfile_regression_guard.py +0 -0
  233. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_freshness_mcp.py +0 -0
  234. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_hygiene_config_root_reconciliation.py +0 -0
  235. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_indexer_batching.py +0 -0
  236. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_indexer_commits.py +0 -0
  237. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_indexer_to_graph.py +0 -0
  238. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_live_anchors.py +0 -0
  239. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_mvcc_rebuild.py +0 -0
  240. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_parse_diagnostics.py +0 -0
  241. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_pr1_confidence_reason.py +0 -0
  242. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_pr2_source_location.py +0 -0
  243. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_pr3_kind_tagging.py +0 -0
  244. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_read_via_server.py +0 -0
  245. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_readonly_under_lock.py +0 -0
  246. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_reindex_via_server.py +0 -0
  247. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_resync.py +0 -0
  248. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_single_writer_queue.py +0 -0
  249. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_star_resolution.py +0 -0
  250. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_temp_table_lineage.py +0 -0
  251. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_union_cte_star_recall_guard.py +0 -0
  252. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_user_surface_recall_guard.py +0 -0
  253. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/integration/test_v141_surface_guards.py +0 -0
  254. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/perf/__init__.py +0 -0
  255. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/perf/test_perf.py +0 -0
  256. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E10/__init__.py +0 -0
  257. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E11/__init__.py +0 -0
  258. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E12/__init__.py +0 -0
  259. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E12/e12_json_path.sql +0 -0
  260. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E12/e12_lateral_flatten.sql +0 -0
  261. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E12/test_e12.py +0 -0
  262. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E13/__init__.py +0 -0
  263. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E14/__init__.py +0 -0
  264. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E15/__init__.py +0 -0
  265. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E16/__init__.py +0 -0
  266. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E16/e16_merge.sql +0 -0
  267. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E16/e16_merge_delete.sql +0 -0
  268. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E16/test_e16.py +0 -0
  269. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E17/__init__.py +0 -0
  270. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E18/__init__.py +0 -0
  271. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E18/e18_decode.sql +0 -0
  272. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E18/e18_iff_decode.sql +0 -0
  273. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E18/e18_nvl2.sql +0 -0
  274. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E18/test_e18.py +0 -0
  275. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E19/__init__.py +0 -0
  276. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E2/__init__.py +0 -0
  277. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E2/e2_expr_alias.sql +0 -0
  278. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E2/e2_function_alias.sql +0 -0
  279. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E2/e2_multiply_alias.sql +0 -0
  280. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E2/test_e2.py +0 -0
  281. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E20/__init__.py +0 -0
  282. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E21/__init__.py +0 -0
  283. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E21/e21_alias_forward_ref.sql +0 -0
  284. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E21/e21_three_level_chain.sql +0 -0
  285. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E21/test_e21.py +0 -0
  286. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E22/__init__.py +0 -0
  287. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E23/__init__.py +0 -0
  288. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E23/e23_stored_proc.sql +0 -0
  289. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E23/e23_stored_proc_multi.sql +0 -0
  290. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E23/test_e23.py +0 -0
  291. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E24/__init__.py +0 -0
  292. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E25/__init__.py +0 -0
  293. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E25/e25_cross_db.sql +0 -0
  294. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E25/e25_two_part.sql +0 -0
  295. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E25/test_e25.py +0 -0
  296. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E25/test_e25_full_id.py +0 -0
  297. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E26/__init__.py +0 -0
  298. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E27/__init__.py +0 -0
  299. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E27/e27_nested_udf.sql +0 -0
  300. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E27/e27_udf.sql +0 -0
  301. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E27/test_e27.py +0 -0
  302. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E28/__init__.py +0 -0
  303. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E29/__init__.py +0 -0
  304. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E3/__init__.py +0 -0
  305. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E3/e3_alter_table.sql +0 -0
  306. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E3/e3_create_sequence.sql +0 -0
  307. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E3/e3_ddl_only.sql +0 -0
  308. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E3/test_e3.py +0 -0
  309. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E30/__init__.py +0 -0
  310. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E31/__init__.py +0 -0
  311. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E32/__init__.py +0 -0
  312. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E33/__init__.py +0 -0
  313. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E34/__init__.py +0 -0
  314. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E35/__init__.py +0 -0
  315. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E36/__init__.py +0 -0
  316. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E36/e36_temp_multi_use.sql +0 -0
  317. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E36/e36_temp_table.sql +0 -0
  318. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E36/test_e36.py +0 -0
  319. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E36/test_e36_xfile.py +0 -0
  320. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E37/__init__.py +0 -0
  321. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E38/__init__.py +0 -0
  322. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E4/__init__.py +0 -0
  323. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_execute_immediate.sql +0 -0
  324. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_if_not_exists.sql +0 -0
  325. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_unexpected_token.sql +0 -0
  326. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E4/e4_unpivot.sql +0 -0
  327. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E4/test_e4.py +0 -0
  328. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E5/__init__.py +0 -0
  329. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E5/e5_cte_missing_source.sql +0 -0
  330. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E5/e5_multi_cte.sql +0 -0
  331. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E5/e5_nested_cte.sql +0 -0
  332. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E5/test_e5.py +0 -0
  333. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E5/test_e5_cte_projection.py +0 -0
  334. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E8/__init__.py +0 -0
  335. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E8/e8_dynamic_sources.sql +0 -0
  336. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E8/e8_seq_nextval.sql +0 -0
  337. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E8/e8_uuid.sql +0 -0
  338. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E8/test_e8.py +0 -0
  339. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E9/__init__.py +0 -0
  340. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/__init__.py +0 -0
  341. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/fixture_sum_absent_cross_schema.sql +0 -0
  342. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/fixture_sum_case_when.sql +0 -0
  343. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/fixture_sum_present_source.sql +0 -0
  344. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_aggregates/test_e_aggregates.py +0 -0
  345. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/__init__.py +0 -0
  346. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_date_aliased.sql +0 -0
  347. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_date_unaliased.sql +0 -0
  348. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_datediff_unaliased.sql +0 -0
  349. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/fixture_year_unaliased.sql +0 -0
  350. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/E_date_functions/test_e_date_functions.py +0 -0
  351. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/README.md +0 -0
  352. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/__init__.py +0 -0
  353. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/anchors/__init__.py +0 -0
  354. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_etl.sql +0 -0
  355. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_omloopsnelheid.sql +0 -0
  356. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_semantic.sql +0 -0
  357. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/anchors/fixture_source.sql +0 -0
  358. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/anchors/test_anchor_ma_aantal_op_order.py +0 -0
  359. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/anchors/test_anchor_omloopsnelheid.py +0 -0
  360. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/conftest.py +0 -0
  361. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/snowflake/test_plan_review_gates.py +0 -0
  362. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/__init__.py +0 -0
  363. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/snowflake/__init__.py +0 -0
  364. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/snowflake/test_scripting_noise.py +0 -0
  365. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_BugB_escalation_uses_init_path.py +0 -0
  366. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_BugC_hook_upgrade.py +0 -0
  367. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_F2_install_skill.py +0 -0
  368. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_F2_skill_render.py +0 -0
  369. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_F2_uninstall_skill.py +0 -0
  370. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_T09_01_qualify_once.py +0 -0
  371. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_T09_02_ddl_skip.py +0 -0
  372. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_T09_04_subprocess_isolate.py +0 -0
  373. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_T09_06_log_verbosity.py +0 -0
  374. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_T35_config_external_consumers.py +0 -0
  375. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_aggregator.py +0 -0
  376. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_aggregator_skip.py +0 -0
  377. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_analyze_case_fold.py +0 -0
  378. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_base_parser.py +0 -0
  379. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_branch_monitor.py +0 -0
  380. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_bulk_upsert_invariant.py +0 -0
  381. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_canonical_target_resolution.py +0 -0
  382. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_cli.py +0 -0
  383. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_cli_help.py +0 -0
  384. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_closure_depth.py +0 -0
  385. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_column_lineage_wiring.py +0 -0
  386. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_config.py +0 -0
  387. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_data_models.py +0 -0
  388. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_db_info.py +0 -0
  389. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_dominant_cause.py +0 -0
  390. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_duckdb_backend.py +0 -0
  391. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_duckdb_backend_shared.py +0 -0
  392. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_find_cmd.py +0 -0
  393. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_firstuser_findings.py +0 -0
  394. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_freshness_helper.py +0 -0
  395. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_gain_ratio.py +0 -0
  396. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_git_delta.py +0 -0
  397. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_git_hooks.py +0 -0
  398. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_git_hooks_notify.py +0 -0
  399. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_graph_backend.py +0 -0
  400. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_graph_completeness_invariant.py +0 -0
  401. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_hard_kill_pool.py +0 -0
  402. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_hygiene_config_warning.py +0 -0
  403. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_include_working_tree.py +0 -0
  404. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_index_cmd.py +0 -0
  405. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_index_flags.py +0 -0
  406. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_index_progress.py +0 -0
  407. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_indexer_progress.py +0 -0
  408. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_indexer_quality.py +0 -0
  409. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_install_message.py +0 -0
  410. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_jobs.py +0 -0
  411. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_judgement.py +0 -0
  412. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_lineage_conversion.py +0 -0
  413. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_literal_column_skip.py +0 -0
  414. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_mcp_best_practices.py +0 -0
  415. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_mcp_stdio_smoke.py +0 -0
  416. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_metrics.py +0 -0
  417. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_noise_filter.py +0 -0
  418. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_parse_file_dependency_filter.py +0 -0
  419. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_parse_quality.py +0 -0
  420. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_parser.py +0 -0
  421. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_perf_scaling_guard.py +0 -0
  422. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_pr07_observability.py +0 -0
  423. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_queries_loader.py +0 -0
  424. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_read_client.py +0 -0
  425. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_resolve_pass2_passes_dependency_filter.py +0 -0
  426. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_schema_resolver.py +0 -0
  427. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_server.py +0 -0
  428. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_snowflake_strip_alter_set_tag.py +0 -0
  429. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_sprint_06_t04_t05.py +0 -0
  430. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_star_resolution_unit.py +0 -0
  431. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_star_schema_unit.py +0 -0
  432. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_submit_feedback.py +0 -0
  433. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_subprocess_isolate.py +0 -0
  434. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_t02_expression_name_extraction.py +0 -0
  435. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_t03_ddl_skip.py +0 -0
  436. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_timeout_cancel.py +0 -0
  437. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_tools_hints.py +0 -0
  438. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_tools_warnings.py +0 -0
  439. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_uninstall.py +0 -0
  440. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_unqualified_fallback.py +0 -0
  441. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_upsert_batch_invariant.py +0 -0
  442. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_walker.py +0 -0
  443. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_watcher.py +0 -0
  444. {sql_code_graph-1.4.3 → sql_code_graph-1.5.0}/tests/unit/test_writer_queue.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql-code-graph
3
- Version: 1.4.3
3
+ Version: 1.5.0
4
4
  Summary: SQL code graph analyzer and lineage tracer
5
5
  Project-URL: Homepage, https://github.com/Warhorze/sql-code-graph
6
6
  Project-URL: Repository, https://github.com/Warhorze/sql-code-graph
@@ -51,6 +51,7 @@ Note: Binary is `sqlcg`; PyPI package is `sql-code-graph`.
51
51
 
52
52
  | Option | Type | Required | Repeatable | Default | Description |
53
53
  | --- | --- | --- | --- | --- | --- |
54
+ | --version | BOOLEAN | No | No | False | Show version and exit. |
54
55
  | --install-completion | BOOLEAN | No | No | | Install completion for the current shell. |
55
56
  | --show-completion | BOOLEAN | No | No | | Show completion for the current shell, to copy it or customize the installation. |
56
57
 
@@ -547,9 +548,19 @@ sqlcg mcp status [OPTIONS]
547
548
 
548
549
  Print server status JSON (connects to control socket).
549
550
 
550
- Returns JSON with fields: running, pid, db_path, indexed_sha, head_sha,
551
- stale_by_commits, connected_clients, uptime, writer_queue when a server
552
- is live.
551
+ Returns JSON with fields: running, version, pid, db_path, indexed_sha,
552
+ head_sha, stale_by_commits, connected_clients, uptime, writer_queue,
553
+ stale_by_version when a server is live.
554
+
555
+ `version` is the *running* server's reported sqlcg.__version__ (read live
556
+ over the control socket — the build the editor is currently talking to).
557
+ `stale_by_version` compares it against the *installed* sqlcg.__version__
558
+ (the CLI process you just invoked): true when they differ, false when they
559
+ match, null when the running version cannot be determined (degraded mode).
560
+ When stale, a warning is printed telling you to restart the MCP server via
561
+ your editor or run `sqlcg install` (which stops the stale server for you).
562
+ This is distinct from `stale_by_commits` (graph-vs-repo freshness, not
563
+ package-vs-binary drift).
553
564
 
554
565
  The status response is length-prefixed framed (v1.3.0, B3) so large
555
566
  writer_queue payloads are received in full — the client uses the
@@ -557,7 +568,8 @@ recv-exactly makefile+readline+read(n) pattern, NOT a single recv(4096).
557
568
 
558
569
  When no server is found: {"running": false}.
559
570
  When the PID file exists with a live process but the socket is unavailable:
560
- {"running": true, "degraded": "socket unavailable", ...}.
571
+ {"running": true, "degraded": "socket unavailable", "stale_by_version": null, ...}
572
+ (the running version cannot be read without a live socket).
561
573
 
562
574
  R3 (stale socket): if the socket file exists but the server is not
563
575
  responding (ConnectionRefusedError / FileNotFoundError), falls through
@@ -577,12 +589,8 @@ sqlcg mcp stop [OPTIONS]
577
589
 
578
590
  Stop the running MCP server gracefully.
579
591
 
580
- Sends a ``stop`` op via the control socket; waits up to 5 s for the
581
- socket file to disappear (confirming clean exit). Falls back to SIGTERM
582
- on the PID-file PID if the socket is unavailable.
583
-
584
- R3 (stale socket): ``ConnectionRefusedError`` / ``FileNotFoundError`` are
585
- caught — never hangs on a dead socket.
592
+ Delegates to ``stop_server()`` (shared with ``sqlcg install``) and prints
593
+ a final message based on whether a server was found.
586
594
 
587
595
  ### Options
588
596
 
@@ -0,0 +1,390 @@
1
+ # Feature Plan: Version Parity + Auto-Restart of Stale MCP on Reinstall
2
+
3
+ ## Summary
4
+ Make the package version, CLI `--version`, and the running MCP server's reported
5
+ version a single source of truth that is always identical, and make `sqlcg install`
6
+ stop a stale running MCP server so the editor respawns a fresh process. This closes
7
+ the "we debugged against the wrong (stale) MCP server" failure class.
8
+
9
+ ## Motivation / Background
10
+ After a package upgrade the editor kept the old stdio MCP process alive, so debugging
11
+ happened against stale code. There was also no way to ask the *running* MCP server its
12
+ version. This is the follow-up to issue #29 (closed — lifecycle commands) and the
13
+ documented backlog items:
14
+ - ARCHITECTURE_REVIEW.md "minor ui changes": *add version flag to cli `--version`*.
15
+ - ARCHITECTURE_REVIEW.md §11.3 (HIGH): `sqlcg install` leaves stale entries / does not
16
+ refresh the running server.
17
+ - ARCHITECTURE_REVIEW.md §17.4/§17.5: `restart` is `stop` + editor-respawn guidance; a
18
+ true re-parent needs a launcher (out of scope here). We rely on the editor's respawn,
19
+ which is exactly the mechanism this plan leans on.
20
+
21
+ ## Scope
22
+
23
+ ### In Scope
24
+ - An eager `--version` callback on the root [`sqlcg`](src/sqlcg/cli/main.py) Typer app
25
+ (the `version` subcommand stays; both share one helper — no duplicated logic).
26
+ - Set `mcp._mcp_server.version = __version__` in [`server.py`](src/sqlcg/server/server.py)
27
+ so the MCP `initialize` handshake reports `serverInfo.version`.
28
+ - Add a `version` field to the control-socket `status` response and to
29
+ [`mcp status`](src/sqlcg/cli/commands/mcp.py) output, plus a `stale_by_version`
30
+ boolean comparing running version to installed `__version__`.
31
+ - Add a `sqlcg_version` field to the `db_info` MCP tool result so an agent can
32
+ self-check which build it is talking to (the protocol `serverInfo.version` is not
33
+ reliably visible to the agent persona).
34
+ - Make `sqlcg install` stop a running MCP server (best-effort, via the existing control
35
+ socket) on **every** non-dry-run success path — including "already configured" — so the
36
+ editor respawns a fresh process on the new version. The stop fires exactly once, at a
37
+ single shared tail all success branches converge on (see Step 5.1).
38
+ - A test asserting CLI `--version`, MCP `serverInfo.version`, control-socket `status.version`,
39
+ and `db_info.sqlcg_version` all equal `sqlcg.__version__`, and that `__version__`
40
+ equals `importlib.metadata.version("sql-code-graph")`.
41
+ - Version bump (additive surface → minor: `1.4.3` → `1.5.0`), `uv lock`.
42
+
43
+ ### Non-Goals
44
+ - A true re-parenting launcher / true graceful `restart` (deferred per §17.5 — the
45
+ editor owns the stdio process lifecycle; we cannot re-spawn it ourselves).
46
+ - Post-install hooks for `uv tool install` / `pip install` (unreliable across installers
47
+ — explicitly rejected as the trigger; see Design Decision 1).
48
+ - Changing the graph **schema** version concept (`get_schema_version` / `SCHEMA_VERSION`
49
+ in [`tools.py`](src/sqlcg/server/tools.py)). That is a different axis (graph schema, not
50
+ package version) and must not be conflated.
51
+ - Touching any perf-hot path in [`base.py`](src/sqlcg/parsers/base.py) or
52
+ [`indexer.py`](src/sqlcg/indexer/indexer.py).
53
+ - Auto-fixing the §11.3 uvx/sqlcg priority inversion (separate finding; out of scope here).
54
+
55
+ ## Design
56
+
57
+ ### Single source of truth
58
+ Every surface reads `from sqlcg import __version__` (defined at
59
+ [`src/sqlcg/__init__.py:3`](src/sqlcg/__init__.py), kept in lockstep with
60
+ `pyproject.toml` by commitizen `version_files`). No surface hardcodes a version string.
61
+
62
+ Two version axes exist and must stay distinct:
63
+ - **Package version** — `sqlcg.__version__` (this feature). The "are we on the right build?" axis.
64
+ - **Graph schema version** — `get_schema_version()` / `SCHEMA_VERSION` (unchanged). The
65
+ "does the DB match the code's schema?" axis.
66
+
67
+ ### Version surfaces (the four readouts)
68
+ | Surface | How version is exposed | Reads from |
69
+ |---------|------------------------|-----------|
70
+ | CLI flag | `sqlcg --version` eager callback | `sqlcg.__version__` |
71
+ | CLI subcommand (existing) | `sqlcg version` | `sqlcg.__version__` (shared helper) |
72
+ | MCP protocol | `serverInfo.version` in `initialize` handshake | `mcp._mcp_server.version` set to `sqlcg.__version__` |
73
+ | Control socket | `status` JSON `version` field + `mcp status` output | `sqlcg.__version__` in the server process |
74
+ | MCP tool (agent-visible) | `db_info().sqlcg_version` | `sqlcg.__version__` |
75
+
76
+ ### Drift detection
77
+ `mcp status` compares the **running server's** reported `version` (from the live process,
78
+ read over the socket) against the **installed** `sqlcg.__version__` (the version of the
79
+ CLI process you just invoked). If they differ, it emits `stale_by_version: true` and a
80
+ human-readable warning telling the user to restart the MCP server in their editor (or run
81
+ `sqlcg install`, which now stops the stale server for them).
82
+
83
+ ### `mcp._mcp_server.version` — deliberate private access
84
+ `FastMCP.__init__` does **not** accept a `version` kwarg (verified signature); the
85
+ underlying `mcp.server.lowlevel.Server.__init__(self, name, version=None, ...)` does.
86
+ We set it post-construction:
87
+ ```python
88
+ mcp = FastMCP("SQL Code Graph")
89
+ mcp._mcp_server.version = __version__ # deliberate: FastMCP has no version kwarg
90
+ ```
91
+ This is a documented, deliberate private-attribute write. A unit test pins it (so an
92
+ upstream API change that breaks it fails loudly rather than silently shipping
93
+ `serverInfo.version = None` again).
94
+
95
+ ### Data Models
96
+ - [`DbInfoResult`](src/sqlcg/server/models.py) gains:
97
+ ```python
98
+ sqlcg_version: str = Field(..., description="Installed sqlcg package version (sqlcg.__version__)")
99
+ ```
100
+ - Control-socket `status` response dict gains `"version": __version__`.
101
+ - `mcp status` output dict gains `version` (running) and `stale_by_version` (computed).
102
+
103
+ ### Dependencies
104
+ No new runtime dependencies. `importlib.metadata` is stdlib.
105
+
106
+ ## Implementation Steps
107
+
108
+ ### Phase 1: Single source of truth helper
109
+ **Step 1.1**: Add a tiny shared version-string helper.
110
+ - Decision: keep it trivial — both the CLI flag and the `version` subcommand call one
111
+ function so the format string is defined once.
112
+ - File: [`src/sqlcg/cli/main.py`](src/sqlcg/cli/main.py) — add a module-level
113
+ `def _version_string() -> str: from sqlcg import __version__; return f"sqlcg version {__version__}"`.
114
+ - Acceptance: `version` subcommand echoes `_version_string()`; no behaviour change to it.
115
+
116
+ **Step 1.2**: Add an eager `--version` callback on the root app.
117
+ - File: [`src/sqlcg/cli/main.py`](src/sqlcg/cli/main.py).
118
+ - This is the **first `@app.callback()` on the root app** — confirmed none exists today
119
+ (main.py has only `@app.command()` registrations and the `version` subcommand). Use the
120
+ full eager-option-on-a-root-callback pattern below.
121
+ - The callback **must** use `invoke_without_command=True`. Without it, bare `sqlcg --version`
122
+ can error "Missing command" before the eager option's callback gets a chance to run —
123
+ the eager callback fires during parameter processing, but Typer still wants a command
124
+ unless the root callback opts out of requiring one.
125
+ - Exact pattern (state this verbatim in the implementation):
126
+ ```python
127
+ def _version_callback(value: bool) -> None:
128
+ if value:
129
+ typer.echo(_version_string())
130
+ raise typer.Exit()
131
+
132
+ @app.callback(invoke_without_command=True)
133
+ def _root(
134
+ version: bool = typer.Option(
135
+ False, "--version", help="Show version and exit.",
136
+ is_eager=True, callback=_version_callback,
137
+ ),
138
+ ) -> None:
139
+ """SQL code graph analyzer."""
140
+ # No body needed: the eager --version callback exits before we get here.
141
+ # When no subcommand is given and --version is absent, Typer shows help
142
+ # because no_args_is_help is the app default for a group with subcommands.
143
+ ```
144
+ Callback function signature is explicit above: `_root(version: bool = typer.Option(...))`
145
+ returning `None`, and `_version_callback(value: bool) -> None`.
146
+ - Must not break existing subcommand dispatch: the eager callback returns immediately when
147
+ `--version` is not passed, so `_root` runs as a no-op and Typer dispatches the subcommand.
148
+ - Files affected: `main.py`.
149
+ - Acceptance (each is an observable check):
150
+ - (a) `sqlcg --version` prints `sqlcg version 1.5.0` and exits 0.
151
+ - (b) `sqlcg` with no args still shows the help text (not an error).
152
+ - (c) `sqlcg index --help` (and other subcommands, e.g. `sqlcg mcp status`) still dispatch.
153
+ - (d) `sqlcg --help` still renders the root help correctly after the callback is added.
154
+ - (e) `sqlcg version` (the subcommand) still works and echoes `_version_string()`.
155
+
156
+ ### Phase 2: MCP protocol serverInfo.version
157
+ **Step 2.1**: Set `mcp._mcp_server.version` at module scope.
158
+ - File: [`src/sqlcg/server/server.py`](src/sqlcg/server/server.py) — immediately after
159
+ `mcp = FastMCP("SQL Code Graph")` (line 36). Import `__version__` at module top.
160
+ - Add an inline comment documenting why the private attr is used (no `version` kwarg on FastMCP).
161
+ - This must not disturb the fd-1 capture ordering invariant documented at the top of the
162
+ module (the assignment is a pure attribute write, no I/O — safe after line 36).
163
+ - Acceptance: `mcp._mcp_server.version == sqlcg.__version__` (was `None`); the
164
+ `create_initialization_options()` handshake reports `serverInfo.version`.
165
+
166
+ ### Phase 3: Control-socket status version + drift
167
+ **Step 3.1**: Add `version` to the `status` response.
168
+ - File: [`src/sqlcg/server/server.py`](src/sqlcg/server/server.py) — in the `op == "status"`
169
+ branch (the `resp` dict around line 220), add `"version": __version__`.
170
+ - Acceptance: a `{"op":"status"}` request returns a `version` field equal to the running
171
+ server process's `__version__`.
172
+
173
+ **Step 3.2**: Surface running version + drift in `mcp status`.
174
+ - File: [`src/sqlcg/cli/commands/mcp.py`](src/sqlcg/cli/commands/mcp.py) — in `mcp_status`,
175
+ after parsing the framed `status` payload:
176
+ - read `running_version = status.get("version")`.
177
+ - compute `from sqlcg import __version__; stale = running_version is not None and running_version != __version__`.
178
+ - include both in the printed JSON (`version`, `stale_by_version`).
179
+ - if `stale`, print a yellow warning: running vX vs installed vY → restart via editor or run `sqlcg install`.
180
+ - The degraded (PID-only) branch cannot read a version → omit `version`, set
181
+ `stale_by_version` to Python `None` (unknown). Do not guess.
182
+ - **Typing note**: the `mcp status` output is a plain `dict` serialized by
183
+ `console.print_json` / `json.dumps`, NOT a Pydantic model. So the degraded branch simply
184
+ puts Python `None` in the dict, which serializes to JSON `null`. There is no
185
+ `Optional[bool]` Pydantic field to add and no model change for this — it is a dict value.
186
+ - Acceptance: when running and installed versions differ, `mcp status` JSON shows
187
+ `stale_by_version: true` and the warning text; when equal, `stale_by_version: false`
188
+ and no warning.
189
+
190
+ ### Phase 4: Agent-visible version via db_info
191
+ **Step 4.1**: Add `sqlcg_version` to `DbInfoResult`.
192
+ - File: [`src/sqlcg/server/models.py`](src/sqlcg/server/models.py) — add the field (see Data Models).
193
+ - Required field (`...`) — no default — so it cannot silently be omitted.
194
+
195
+ **Step 4.2**: Populate it in the `db_info` tool.
196
+ - File: [`src/sqlcg/server/tools.py`](src/sqlcg/server/tools.py) `db_info` (line 1662) —
197
+ `from sqlcg import __version__` and pass `sqlcg_version=__version__` into the
198
+ `DbInfoResult(...)` return. Keep `schema_version` exactly as-is (do not conflate).
199
+ - Update the `db_info` docstring with one line explaining `sqlcg_version` is the package
200
+ build (distinct from `schema_version`).
201
+ - Acceptance: `db_info()` result carries `sqlcg_version == sqlcg.__version__`; existing
202
+ `schema_version` field unchanged.
203
+
204
+ ### Phase 5: install stops the stale server
205
+ **Step 5.1**: Make `install_cmd` stop a running MCP server on every non-dry-run success path.
206
+
207
+ **5.1a — extract `stop_server()` in `mcp.py` (no install-local wrapper).**
208
+ - File: [`src/sqlcg/cli/commands/mcp.py`](src/sqlcg/cli/commands/mcp.py).
209
+ - Extract the socket-stop body of [`mcp_stop`](src/sqlcg/cli/commands/mcp.py) into a
210
+ reusable module-level function `stop_server() -> bool` in `mcp.py`. It performs the
211
+ existing connect → send `{"op":"stop"}` → `recv(128)` → wait-for-socket-gone → SIGTERM
212
+ fallback logic and returns `True` if a server was stopped, `False` if none was found.
213
+ - `mcp_stop` then calls `stop_server()` and prints its existing messages based on the bool.
214
+ - `install_cmd` imports `stop_server` from `mcp.py` and **calls it directly** — there is
215
+ **no** `_stop_running_server()` install-local wrapper. (The previous draft's
216
+ `_stop_running_server()` wrapper is dead and is removed from this plan.)
217
+ - Grep-confirmed call sites for the new method: `stop_server` is called from `mcp_stop`
218
+ **and** from `install_cmd` — two real call sites, satisfying the "every new method has a
219
+ grep-confirmed call site" rule.
220
+
221
+ **5.1b — single funnel point in `install_cmd` (`install.py`).**
222
+ - File: [`src/sqlcg/cli/commands/install.py`](src/sqlcg/cli/commands/install.py).
223
+ - `install_cmd` today has **FOUR** return/exit shapes; three are non-dry-run success paths
224
+ that must trigger the stop, and dry-run must NOT:
225
+ 1. line 88 — `claude mcp add` succeeds → currently `_provision_skill` + `return`.
226
+ 2. line 115 — "Already configured" (`existing == entry`) → currently `_provision_skill` +
227
+ `return`. **This is exactly the reinstall case**: the config didn't change but the
228
+ binary on disk did, so the stale running server still must be stopped. Do NOT skip it.
229
+ 3. line ~137 — the fallback `~/.claude.json` write path → falls through to
230
+ `_provision_skill` at the function tail.
231
+ 4. dry-run (line 64–74) → `_provision_skill(dry_run=True)` + `return`; must NOT stop,
232
+ prints "would stop running MCP server" instead.
233
+ - **Restructure so all three non-dry-run branches converge on one tail** rather than
234
+ returning early. Concretely: replace the early `return`s at lines 88 and 115 so that,
235
+ after each branch prints its own "Configured" / "Already configured" line, control falls
236
+ through to a single shared tail that runs **once**:
237
+ ```python
238
+ # single non-dry-run tail (reached by all three success branches):
239
+ stopped = stop_server()
240
+ if stopped:
241
+ console.print(
242
+ "Stopped running MCP server; your editor will respawn it on the new build."
243
+ )
244
+ else:
245
+ console.print("No running MCP server to refresh.")
246
+ _provision_skill(resolved_scope, repo, dry_run=False)
247
+ ```
248
+ Use a structure such as: set the per-branch "Configured" message, then `break`/fall into
249
+ the shared tail (e.g. wrap the three branches so they assign and then jump past to the
250
+ tail, or invert the early-returns into `if/elif/else` so the tail is unconditionally
251
+ reached on the non-dry-run path). The dry-run block keeps its own early `return` and
252
+ prints "would stop running MCP server" before returning.
253
+ - `stop_server()` is called **exactly once** on the non-dry-run path — do NOT duplicate
254
+ the call in all three branches, and do NOT miss the "Already configured" branch.
255
+ - The stop is best-effort: `stop_server()` returning `False` (no server) is a no-op with
256
+ the "No running MCP server to refresh." message; a socket error inside `stop_server()` is
257
+ already swallowed by its own except clause and must not abort install.
258
+
259
+ **Message (resolves the `(vX)` inconsistency):** the install stop line **drops the `(vX)`
260
+ version suffix**. `stop_server() -> bool` returns only a bool, not the stopped server's
261
+ version, and querying `status` first just to render `(vX)` would add an extra socket
262
+ round-trip for no real benefit. So the message is exactly:
263
+ "Stopped running MCP server; your editor will respawn it on the new build."
264
+
265
+ - Acceptance: with a running server, `sqlcg install` (non-dry-run) sends a `stop` op and
266
+ the server exits, for **all three** success branches including "Already configured";
267
+ `stop_server()` is invoked exactly once per install; with no server, install completes
268
+ with the no-op message; `--dry-run` never stops anything and prints "would stop running
269
+ MCP server".
270
+
271
+ ### Phase 6: Single-source-of-truth test
272
+ **Step 6.1**: Add a parity test.
273
+ - File: `tests/unit/test_version_parity.py`.
274
+ - Assert:
275
+ 1. `sqlcg.__version__ == importlib.metadata.version("sql-code-graph")`.
276
+ 2. CLI `--version` output (via Typer `CliRunner`) contains `sqlcg.__version__`.
277
+ 3. `mcp._mcp_server.version == sqlcg.__version__` (import
278
+ [`server.py`](src/sqlcg/server/server.py); pins the private-attr set survives upstream changes).
279
+ 4. `db_info().sqlcg_version == sqlcg.__version__` (integration-level, with a backend) —
280
+ OR a focused unit asserting `DbInfoResult` carries the field and the tool passes
281
+ `__version__` (use whichever matches existing `db_info` test infra; prefer the
282
+ integration path if one already exists).
283
+ 5. Control-socket `status` includes `version == sqlcg.__version__`. Home this assertion
284
+ in [`tests/unit/test_mcp_control.py`](tests/unit/test_mcp_control.py) (the existing
285
+ control-socket test module). The assertion must inspect **observable output**, NOT
286
+ source-grep the `resp` dict construction. Only these two forms are acceptable:
287
+ (a) drive the real control socket end-to-end and parse the framed `status` response,
288
+ asserting the parsed `version` equals `sqlcg.__version__`; or
289
+ (b) call the `status` handler directly and inspect the returned dict's `version` value.
290
+ Do not assert by reading the server source for the literal `"version": __version__`.
291
+ - Acceptance: all five assertions pass; the test fails if any surface diverges or
292
+ hardcodes a version.
293
+
294
+ ### Phase 7: Version bump + lock
295
+ **Step 7.1**: Bump version to `1.5.0`.
296
+ - [`pyproject.toml`](pyproject.toml) `version = "1.5.0"`.
297
+ - [`src/sqlcg/__init__.py`](src/sqlcg/__init__.py) `__version__ = "1.5.0"`.
298
+ - Run `uv lock`.
299
+ - Acceptance: `uv run sqlcg --version` prints `sqlcg version 1.5.0`; the parity test passes
300
+ against `1.5.0`; `git diff` shows the lockfile's own version entry refreshed.
301
+ - NOTE: the agent does NOT tag or close issues — the user tags after merge (per CLAUDE.md
302
+ "Releasing" + project memory "never close; verify before tag").
303
+
304
+ ## Design Decisions (resolved)
305
+
306
+ ### Decision 1 — Restart-on-reinstall trigger: `sqlcg install` stops the running server (option a), plus a drift *warning* in `mcp status` (option b as detection, not auto-stop)
307
+ **Recommendation: a + b (detection only).**
308
+ - uv-tool/pip installs do not reliably run post-install hooks, so an installer hook is
309
+ rejected. The trigger that the user already performs after an upgrade is `sqlcg install`
310
+ (it is in the QUICK START). Making `install` stop the stale server (Phase 5) is the
311
+ reliable, explicit trigger: stop → editor respawns the freshly-installed build.
312
+ - `mcp status` (Phase 3) is a *detector*, not an auto-killer. Auto-stopping a server from a
313
+ read-only `status` call would be a surprising side effect. It instead reports
314
+ `stale_by_version` and tells the user the fix. This respects "no TODO in happy path"
315
+ (the stop path is fully implemented in install; status just reports).
316
+ - We rely on the editor respawning the stdio process — consistent with §17.4/§17.5 (we
317
+ cannot re-parent it ourselves; the editor owns it). This is honest, not faked.
318
+
319
+ ### Decision 2 — `--version` for the MCP: implement all three readouts
320
+ **Recommendation: implement the protocol field AND the operator/agent readouts.**
321
+ - (i) Protocol `serverInfo.version` (Phase 2) is the canonical answer to "what version is
322
+ the running server?" but is not reliably visible to the agent persona or to a human at
323
+ the CLI.
324
+ - (ii) `mcp status` `version` field (Phase 3) is the human/operator readout and the place
325
+ drift is flagged.
326
+ - (iii) `db_info().sqlcg_version` (Phase 4) is the agent-callable readout so an agent can
327
+ self-check it is on the right build before trusting results.
328
+ All three are needed to actually let someone confirm which version is running.
329
+
330
+ ### Decision 3 — Single source of truth + parity test
331
+ **Recommendation: every surface reads `from sqlcg import __version__`; one test pins parity.**
332
+ - No surface hardcodes a version. Phase 6 asserts the four runtime surfaces agree with
333
+ `__version__` and that `__version__` equals the installed distribution metadata
334
+ (`importlib.metadata.version("sql-code-graph")`) — verified resolvable in this env
335
+ (returns `1.4.3` today). This catches a future `pyproject.toml`/`__init__.py` drift even
336
+ if commitizen is bypassed.
337
+
338
+ ## Test Strategy
339
+ - **Unit**:
340
+ - `tests/unit/test_version_parity.py` (Phase 6) — the five parity assertions.
341
+ - CLI `--version` via Typer `CliRunner` — observable stdout asserted (not "no exception").
342
+ - `mcp status` drift: mock the socket `status` payload with a mismatched `version`,
343
+ assert `stale_by_version: true` + warning text in output; matching version → false + no warning.
344
+ - `install` stop-on-reinstall: mock `stop_server()`, assert it is called **exactly once**
345
+ on the non-dry-run path — including the "Already configured" branch — and NOT called on
346
+ `--dry-run`; assert the no-op message when it returns False; assert the stop message has
347
+ no `(vX)` suffix.
348
+ - Private-attr guard: `mcp._mcp_server.version == __version__` (fails loudly if FastMCP
349
+ upstream changes).
350
+ - **Integration** (real backend, in-memory): `db_info().sqlcg_version == __version__`
351
+ alongside an existing `db_info` integration test if one exists; otherwise add a focused one.
352
+ - **Observable-output rule**: every test asserts a concrete value (version string, boolean,
353
+ warning substring), never merely that a call did not raise.
354
+ - Run full gate before handoff: `uv run pytest`, `uv run pyright`, `uv run ruff check src tests`.
355
+
356
+ ## Acceptance Criteria
357
+ - [ ] `sqlcg --version` prints `sqlcg version <__version__>` and exits 0; `sqlcg` with no
358
+ args still shows help; `sqlcg --help` renders correctly after the callback is added;
359
+ `sqlcg version` still works; all other subcommands (e.g. `sqlcg index --help`,
360
+ `sqlcg mcp status`) dispatch unchanged.
361
+ - [ ] `mcp._mcp_server.version == sqlcg.__version__` (no longer `None`); the MCP
362
+ `initialize` handshake reports `serverInfo.version`.
363
+ - [ ] Control-socket `status` response includes `version == <running __version__>`.
364
+ - [ ] `sqlcg mcp status` shows `version` and `stale_by_version`, and warns when the running
365
+ server version differs from the installed `__version__`.
366
+ - [ ] `db_info().sqlcg_version == sqlcg.__version__`; `schema_version` unchanged and distinct.
367
+ - [ ] `sqlcg install` (non-dry-run) stops a running MCP server so the editor respawns it,
368
+ on all three success branches including "Already configured"; `stop_server()` is
369
+ invoked exactly once per install; no-op message when none running; `--dry-run` stops
370
+ nothing. Stop message drops the `(vX)` suffix.
371
+ - [ ] `stop_server()` lives in `mcp.py` (no install-local wrapper) and has grep-confirmed
372
+ call sites in both `mcp_stop` and `install_cmd`.
373
+ - [ ] Parity test asserts all four runtime surfaces equal `__version__` and
374
+ `__version__ == importlib.metadata.version("sql-code-graph")`.
375
+ - [ ] Version bumped to `1.5.0` in `pyproject.toml` + `__init__.py`; `uv lock` run.
376
+ - [ ] No TODO in any happy path; no changes to `base.py`/`indexer.py`.
377
+
378
+ ## Risks and Mitigations
379
+ | Risk | Mitigation |
380
+ |------|-----------|
381
+ | FastMCP upstream removes/renames `_mcp_server` (private attr) | Unit test pins `mcp._mcp_server.version == __version__`; a break fails the suite loudly instead of silently shipping `None`. |
382
+ | `install` stopping a server the user did not want stopped | Stop is best-effort + clearly messaged; install's whole purpose post-upgrade is to refresh the server; `--dry-run` never stops. |
383
+ | `importlib.metadata.version("sql-code-graph")` differs in an editable/uv dev tree | Verified it returns the correct value in this env. If a future dev layout breaks it, the parity test surfaces it immediately (intended). |
384
+ | Conflating package version with graph schema version | Distinct fields (`sqlcg_version` vs `schema_version`), distinct docstrings, called out in Non-Goals. |
385
+ | Editor does not auto-respawn after stop | Documented limitation (§17.4/§17.5); `mcp status` warning + install message tell the user to restart via the editor. |
386
+
387
+ ## Rollout / Rollback
388
+ - Additive surface only; no schema change → no re-index required. Rollback = revert the PR.
389
+ - Ships as one feature PR that bumps `1.4.3 → 1.5.0` (SemVer minor: additive, nothing
390
+ breaks). User tags `v1.5.0` on the master merge commit after merge (agent does not tag).
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sql-code-graph"
7
- version = "1.4.3"
7
+ version = "1.5.0"
8
8
  description = "SQL code graph analyzer and lineage tracer"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1,5 +1,5 @@
1
1
  """SQL Code Graph - SQL lineage and dependency analysis tool."""
2
2
 
3
- __version__ = "1.4.3"
3
+ __version__ = "1.5.0"
4
4
 
5
5
  __all__ = ["__version__"]
@@ -20,6 +20,8 @@ from pathlib import Path
20
20
  import typer
21
21
  from rich.console import Console
22
22
 
23
+ from sqlcg.cli.commands.mcp import stop_server
24
+
23
25
  console = Console()
24
26
 
25
27
  _SERVER_KEY = "sql-code-graph"
@@ -70,10 +72,12 @@ def install_cmd(
70
72
  claude_json = Path.home() / ".claude.json"
71
73
  console.print("[dim]--dry-run: would write to ~/.claude.json:[/dim]")
72
74
  _preview_claude_json(claude_json, entry)
75
+ console.print("[dim]--dry-run: would stop running MCP server[/dim]")
73
76
  _provision_skill(resolved_scope, repo, dry_run=True)
74
77
  return
75
78
 
76
79
  # --- Try official claude CLI first ---
80
+ configured_via_claude_cli = False
77
81
  claude_bin = shutil.which("claude")
78
82
  if claude_bin:
79
83
  proc = subprocess.run(
@@ -84,56 +88,65 @@ def install_cmd(
84
88
  if proc.returncode == 0:
85
89
  console.print(f"[green]Configured:[/green] {_SERVER_KEY} via `claude mcp add`")
86
90
  console.print("\nRestart Claude Code to pick up the new MCP server.")
87
- _provision_skill(resolved_scope, repo, dry_run=False)
88
- return
89
- # Non-zero: log and fall through to ~/.claude.json fallback
90
- console.print(
91
- f"[yellow]Warning:[/yellow] `claude mcp add` returned rc={proc.returncode}; "
92
- "falling back to ~/.claude.json write."
93
- )
94
- if proc.stderr:
95
- console.print(f"[dim]{proc.stderr.strip()}[/dim]")
96
-
97
- # --- Fallback: write ~/.claude.json directly ---
98
- claude_json = Path.home() / ".claude.json"
99
- if claude_json.exists():
100
- try:
101
- data: dict = json.loads(claude_json.read_text())
102
- except (json.JSONDecodeError, OSError, TypeError):
91
+ configured_via_claude_cli = True
92
+ else:
93
+ # Non-zero: log and fall through to ~/.claude.json fallback
103
94
  console.print(
104
- f"[yellow]Warning:[/yellow] {claude_json} contains invalid JSON "
105
- "mcpServers key will be added"
95
+ f"[yellow]Warning:[/yellow] `claude mcp add` returned rc={proc.returncode}; "
96
+ "falling back to ~/.claude.json write."
106
97
  )
98
+ if proc.stderr:
99
+ console.print(f"[dim]{proc.stderr.strip()}[/dim]")
100
+
101
+ if not configured_via_claude_cli:
102
+ # --- Fallback: write ~/.claude.json directly ---
103
+ claude_json = Path.home() / ".claude.json"
104
+ if claude_json.exists():
105
+ try:
106
+ data: dict = json.loads(claude_json.read_text())
107
+ except (json.JSONDecodeError, OSError, TypeError):
108
+ console.print(
109
+ f"[yellow]Warning:[/yellow] {claude_json} contains invalid JSON — "
110
+ "mcpServers key will be added"
111
+ )
112
+ data = {}
113
+ else:
107
114
  data = {}
108
- else:
109
- data = {}
110
115
 
111
- existing = data.get("mcpServers", {}).get("user", {}).get(_SERVER_KEY)
112
- if existing == entry:
113
- console.print(f"[green]Already configured:[/green] {_SERVER_KEY} (in ~/.claude.json)")
114
- _provision_skill(resolved_scope, repo, dry_run=False)
115
- return
116
+ existing = data.get("mcpServers", {}).get("user", {}).get(_SERVER_KEY)
117
+ if existing == entry:
118
+ console.print(f"[green]Already configured:[/green] {_SERVER_KEY} (in ~/.claude.json)")
119
+ else:
120
+ data.setdefault("mcpServers", {}).setdefault("user", {})[_SERVER_KEY] = entry
116
121
 
117
- data.setdefault("mcpServers", {}).setdefault("user", {})[_SERVER_KEY] = entry
122
+ try:
123
+ tmp = claude_json.with_suffix(".tmp")
124
+ tmp.write_text(json.dumps(data, indent=2) + "\n")
125
+ os.replace(tmp, claude_json)
126
+ except (OSError, TypeError, AttributeError):
127
+ pass # Ignore file I/O errors in testing
118
128
 
119
- try:
120
- tmp = claude_json.with_suffix(".tmp")
121
- tmp.write_text(json.dumps(data, indent=2) + "\n")
122
- os.replace(tmp, claude_json)
123
- except (OSError, TypeError, AttributeError):
124
- pass # Ignore file I/O errors in testing
125
-
126
- cmd_str = " ".join(cmd_parts)
127
- console.print(f"[green]Configured:[/green] {_SERVER_KEY} → {cmd_str}")
128
- console.print(f"[dim]Written to {claude_json}[/dim]")
129
-
130
- if entry.get("command") == "uvx":
131
- console.print(
132
- "[yellow]Note:[/yellow] First startup downloads dependencies (~30s). "
133
- "Subsequent restarts use cache (~1s)."
134
- )
129
+ cmd_str = " ".join(cmd_parts)
130
+ console.print(f"[green]Configured:[/green] {_SERVER_KEY} → {cmd_str}")
131
+ console.print(f"[dim]Written to {claude_json}[/dim]")
132
+
133
+ if entry.get("command") == "uvx":
134
+ console.print(
135
+ "[yellow]Note:[/yellow] First startup downloads dependencies (~30s). "
136
+ "Subsequent restarts use cache (~1s)."
137
+ )
135
138
 
136
- console.print("\nRestart Claude Code to pick up the new MCP server.")
139
+ console.print("\nRestart Claude Code to pick up the new MCP server.")
140
+
141
+ # --- Single non-dry-run tail: all three success branches converge here. ---
142
+ # The config may not have changed (e.g. "Already configured"), but the
143
+ # binary on disk did — so the stale running server still must be stopped
144
+ # so the editor respawns the freshly-installed build.
145
+ stopped = stop_server()
146
+ if stopped:
147
+ console.print("Stopped running MCP server; your editor will respawn it on the new build.")
148
+ else:
149
+ console.print("No running MCP server to refresh.")
137
150
  _provision_skill(resolved_scope, repo, dry_run=False)
138
151
 
139
152