codegraph-brain 0.7.2__tar.gz → 0.7.4__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 (256) hide show
  1. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/.github/workflows/autodoc.yml +7 -7
  2. codegraph_brain-0.7.4/.github/workflows/ci.yml +46 -0
  3. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/.github/workflows/guardian.yml +4 -4
  4. codegraph_brain-0.7.4/.github/workflows/pr-title.yml +51 -0
  5. codegraph_brain-0.7.4/.github/workflows/release-please.yml +147 -0
  6. codegraph_brain-0.7.4/.release-please-manifest.json +3 -0
  7. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/CHANGELOG.md +20 -0
  8. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/PKG-INFO +1 -1
  9. codegraph_brain-0.7.4/docs/assets/.gitignore +1 -0
  10. codegraph_brain-0.7.4/docs/assets/cgis-app-avatar.png +0 -0
  11. codegraph_brain-0.7.4/docs/assets/cgis-app-avatar.svg +1 -0
  12. codegraph_brain-0.7.4/docs/assets/generate_avatar.py +123 -0
  13. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/how-to/MCP_REFERENCE.md +6 -1
  14. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/pyproject.toml +1 -1
  15. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/api/mcp_server.py +73 -1
  16. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/resolver/engine.py +1 -1
  17. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/resolver/indices.py +41 -22
  18. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_cohesion.py +3 -1
  19. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_chunker.py +3 -1
  20. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_mcp_server.py +151 -0
  21. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_mermaid.py +4 -2
  22. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_ontology_init.py +3 -1
  23. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_resolver_indices.py +57 -0
  24. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/uv.lock +2 -2
  25. codegraph_brain-0.7.2/.github/workflows/ci.yml +0 -38
  26. codegraph_brain-0.7.2/.github/workflows/release-please.yml +0 -76
  27. codegraph_brain-0.7.2/.release-please-manifest.json +0 -3
  28. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/.claude-plugin/marketplace.json +0 -0
  29. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/.gitignore +0 -0
  30. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/.pre-commit-config.yaml +0 -0
  31. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/.python-version +0 -0
  32. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/CLAUDE.md +0 -0
  33. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/CONTRIBUTING.md +0 -0
  34. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/LICENSE +0 -0
  35. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/Makefile +0 -0
  36. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/PRIVACY.md +0 -0
  37. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/README.md +0 -0
  38. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/CURATION.md +0 -0
  39. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/pr-122.yaml +0 -0
  40. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/pr-140.yaml +0 -0
  41. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/pr-141.yaml +0 -0
  42. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/pr-142.yaml +0 -0
  43. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/pr-143.yaml +0 -0
  44. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/pr-144.yaml +0 -0
  45. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/pr-278.yaml +0 -0
  46. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/benchmarks/guardian/results.jsonl +0 -0
  47. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/data/.gitkeep +0 -0
  48. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/AUDIT.md +0 -0
  49. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/CASE_STUDY.md +0 -0
  50. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/architecture/HOW_IT_WORKS.md +0 -0
  51. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/architecture/ONTOLOGY.md +0 -0
  52. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/architecture/PATTERNS_AND_TRIADS.md +0 -0
  53. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/architecture/SELF_PORTRAIT.md +0 -0
  54. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/architecture/diagrams/pipeline_flow.mermaid +0 -0
  55. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/architecture/health_badge.json +0 -0
  56. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/examples/.gitkeep +0 -0
  57. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/how-to/AGENT_ONBOARDING.md +0 -0
  58. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/how-to/CLI_USAGE.md +0 -0
  59. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/lab-notes/2026-06-11-chunked-review-negative-result.md +0 -0
  60. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/ontology/.gitkeep +0 -0
  61. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/ontology/core.yaml +0 -0
  62. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/ontology/domains.yaml +0 -0
  63. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/ontology/patterns.yaml +0 -0
  64. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/ontology/tolerances.lock +0 -0
  65. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-09-domain-pattern-fingerprint-design.md +0 -0
  66. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-09-pattern-alphabet-motif-basis-design.md +0 -0
  67. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-10-guardian-sprint-design.md +0 -0
  68. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-11-fastapi-di-edges-design.md +0 -0
  69. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-11-guardian-chunked-review-design.md +0 -0
  70. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-11-guardian-chunker-design.md +0 -0
  71. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-11-mcp-drift-validate-fqn-design.md +0 -0
  72. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-11-resolver-split-design.md +0 -0
  73. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-11-symbol-import-edges-design.md +0 -0
  74. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-12-drift-empty-domains-design.md +0 -0
  75. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-12-gate-semantics-design.md +0 -0
  76. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-12-init-ontology-design.md +0 -0
  77. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-12-release-please-ci-design.md +0 -0
  78. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-13-suggest-packages-design.md +0 -0
  79. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-06-13-tangle-anti-pattern-design.md +0 -0
  80. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-29-guardian-skeptic-scoring-design.md +0 -0
  81. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-cgis-fractal-design.md +0 -0
  82. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-cgis-fractal-plan.md +0 -0
  83. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-chunk-source-filter-design.md +0 -0
  84. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-chunk-source-filter-plan.md +0 -0
  85. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-genai-client-close-design.md +0 -0
  86. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-genai-client-close-plan.md +0 -0
  87. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-guardian-precision-bench-design.md +0 -0
  88. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-guardian-precision-bench-plan.md +0 -0
  89. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-guardian-timeout-retry-design.md +0 -0
  90. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-30-guardian-timeout-retry-plan.md +0 -0
  91. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/2026-07-31-finder-bug-class-taxonomy.md +0 -0
  92. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/BLUEPRINT.md +0 -0
  93. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/PRD.md +0 -0
  94. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/TDD.md +0 -0
  95. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-09-fingerprint-drift.md +0 -0
  96. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-10-guardian-context-skeptic-inline.md +0 -0
  97. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-10-guardian-structured-findings-bench.md +0 -0
  98. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-10-motif-basis-part-b.md +0 -0
  99. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-10-unified-pattern-alphabet.md +0 -0
  100. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-11-fastapi-di-edges.md +0 -0
  101. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-11-guardian-chunked-review.md +0 -0
  102. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-11-guardian-chunker.md +0 -0
  103. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-11-mcp-drift-validate-fqn.md +0 -0
  104. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-11-resolver-split.md +0 -0
  105. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-12-drift-empty-domains.md +0 -0
  106. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-12-gate-semantics.md +0 -0
  107. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-12-init-ontology.md +0 -0
  108. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-12-release-please-ci.md +0 -0
  109. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-12-symbol-import-edges.md +0 -0
  110. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-06-13-suggest-packages.md +0 -0
  111. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/docs/specs/plans/2026-07-29-guardian-skeptic-scoring.md +0 -0
  112. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/main.py +0 -0
  113. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/plugin/.claude-plugin/plugin.json +0 -0
  114. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/plugin/.mcp.json +0 -0
  115. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/plugin/README.md +0 -0
  116. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/plugin/skills/cgis/SKILL.md +0 -0
  117. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/plugin/skills/ingest/SKILL.md +0 -0
  118. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/release-please-config.json +0 -0
  119. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/gen_ideal_graph.py +0 -0
  120. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/generate_health.py +0 -0
  121. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/generate_mcp_ref.py +0 -0
  122. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/generate_schema_docs.py +0 -0
  123. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/guardian_bench.py +0 -0
  124. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/guardian_review.py +0 -0
  125. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/inject_readme_graph.py +0 -0
  126. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/probe_closure_gap.py +0 -0
  127. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/scripts/probe_tier_ladder.py +0 -0
  128. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/__init__.py +0 -0
  129. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/__main__.py +0 -0
  130. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/api/.gitkeep +0 -0
  131. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/api/__init__.py +0 -0
  132. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/cli.py +0 -0
  133. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/core/.gitkeep +0 -0
  134. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/core/models.py +0 -0
  135. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/.gitkeep +0 -0
  136. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/_python_ast.py +0 -0
  137. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/_python_classes.py +0 -0
  138. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/_python_functions.py +0 -0
  139. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/_python_imports.py +0 -0
  140. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/_python_types.py +0 -0
  141. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/base.py +0 -0
  142. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/python_extractor.py +0 -0
  143. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/extractors/typescript_extractor.py +0 -0
  144. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/__init__.py +0 -0
  145. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/bench.py +0 -0
  146. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/chunked.py +0 -0
  147. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/chunker.py +0 -0
  148. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/collector.py +0 -0
  149. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/core.py +0 -0
  150. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/diff_index.py +0 -0
  151. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/findings.py +0 -0
  152. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/github_poster.py +0 -0
  153. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/metrics.py +0 -0
  154. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/prompts.py +0 -0
  155. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/providers/__init__.py +0 -0
  156. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/providers/base.py +0 -0
  157. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/providers/gemini.py +0 -0
  158. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/providers/mistral.py +0 -0
  159. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/providers/ollama.py +0 -0
  160. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/recording.py +0 -0
  161. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/render.py +0 -0
  162. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/runner.py +0 -0
  163. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/guardian/skeptic.py +0 -0
  164. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/pipeline.py +0 -0
  165. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/py.typed +0 -0
  166. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/analysis/__init__.py +0 -0
  167. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/analysis/analyzer.py +0 -0
  168. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/analysis/anomaly.py +0 -0
  169. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/analysis/cohesion.py +0 -0
  170. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/analysis/health.py +0 -0
  171. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/analysis/suggest_service.py +0 -0
  172. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/context/__init__.py +0 -0
  173. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/context/audit.py +0 -0
  174. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/context/context_service.py +0 -0
  175. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/context/prompt.py +0 -0
  176. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/context/snippet.py +0 -0
  177. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/__init__.py +0 -0
  178. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/_scc.py +0 -0
  179. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/drift.py +0 -0
  180. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/drift_service.py +0 -0
  181. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/fingerprint.py +0 -0
  182. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/fractal.py +0 -0
  183. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/ontology_init.py +0 -0
  184. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/quotient.py +0 -0
  185. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/drift/triads.py +0 -0
  186. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/engine.py +0 -0
  187. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/fqn.py +0 -0
  188. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/render/__init__.py +0 -0
  189. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/render/graph_json.py +0 -0
  190. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/render/mermaid.py +0 -0
  191. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/query/render/metrics.py +0 -0
  192. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/resolver/.gitkeep +0 -0
  193. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/resolver/__init__.py +0 -0
  194. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/resolver/symbols.py +0 -0
  195. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/resolver/uplift.py +0 -0
  196. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/storage/.gitkeep +0 -0
  197. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/src/cgis/storage/sqlite_store.py +0 -0
  198. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/integration/.gitkeep +0 -0
  199. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/.gitkeep +0 -0
  200. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/__init__.py +0 -0
  201. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/conftest.py +0 -0
  202. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/test_architecture.py +0 -0
  203. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/test_drift.py +0 -0
  204. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/test_fractal.py +0 -0
  205. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/test_init_ontology_roundtrip.py +0 -0
  206. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/test_self_parse.py +0 -0
  207. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/test_self_parse_ts.py +0 -0
  208. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/self_parsing/test_suggest.py +0 -0
  209. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/.gitkeep +0 -0
  210. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/conftest.py +0 -0
  211. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/guardian_stubs.py +0 -0
  212. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test___main__.py +0 -0
  213. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_analyzer.py +0 -0
  214. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_audit.py +0 -0
  215. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_cli.py +0 -0
  216. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_context_service.py +0 -0
  217. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_di_acceptance.py +0 -0
  218. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_drift.py +0 -0
  219. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_drift_service.py +0 -0
  220. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_fingerprint.py +0 -0
  221. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_fqn.py +0 -0
  222. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_fractal.py +0 -0
  223. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_gen_ideal_graph.py +0 -0
  224. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_generate_mcp_ref.py +0 -0
  225. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_graph_json.py +0 -0
  226. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_bench.py +0 -0
  227. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_chunked.py +0 -0
  228. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_collector.py +0 -0
  229. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_core.py +0 -0
  230. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_diff_index.py +0 -0
  231. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_findings.py +0 -0
  232. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_metrics.py +0 -0
  233. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_poster.py +0 -0
  234. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_providers.py +0 -0
  235. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_recording.py +0 -0
  236. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_render.py +0 -0
  237. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_runner.py +0 -0
  238. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_guardian_skeptic.py +0 -0
  239. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_health_scorer.py +0 -0
  240. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_import_acceptance.py +0 -0
  241. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_metrics.py +0 -0
  242. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_models.py +0 -0
  243. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_ontology_compliance.py +0 -0
  244. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_patterns_yaml.py +0 -0
  245. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_pipeline.py +0 -0
  246. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_prompt.py +0 -0
  247. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_python_extractor.py +0 -0
  248. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_quotient.py +0 -0
  249. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_resolver.py +0 -0
  250. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_resolver_symbols.py +0 -0
  251. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_snippet.py +0 -0
  252. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_sqlite_store.py +0 -0
  253. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_suggest_service.py +0 -0
  254. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_triads.py +0 -0
  255. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_typescript_extractor.py +0 -0
  256. {codegraph_brain-0.7.2 → codegraph_brain-0.7.4}/tests/unit/test_uplift.py +0 -0
@@ -28,15 +28,15 @@ jobs:
28
28
  enable-cache: true
29
29
 
30
30
  - name: Install CGIS
31
- run: uv sync
31
+ run: uv sync --frozen
32
32
 
33
33
  - name: Self-ingest core engine
34
- run: uv run cgis ingest ./src --output /tmp/self_graph.db
34
+ run: uv run --frozen cgis ingest ./src --output /tmp/self_graph.db
35
35
 
36
36
  - name: Generate pipeline flow diagram
37
37
  run: |
38
38
  mkdir -p docs/architecture/diagrams
39
- uv run cgis trace "cgis.pipeline.IngestionPipeline.run" \
39
+ uv run --frozen cgis trace "cgis.pipeline.IngestionPipeline.run" \
40
40
  --db /tmp/self_graph.db \
41
41
  --depth 1 \
42
42
  --format mermaid \
@@ -44,21 +44,21 @@ jobs:
44
44
  > docs/architecture/diagrams/pipeline_flow.mermaid
45
45
 
46
46
  - name: Compute graph health badge
47
- run: uv run python scripts/generate_health.py --db /tmp/self_graph.db
47
+ run: uv run --frozen python scripts/generate_health.py --db /tmp/self_graph.db
48
48
 
49
49
  - name: Inject graph into README.md
50
50
  run: |
51
- uv run python scripts/inject_readme_graph.py \
51
+ uv run --frozen python scripts/inject_readme_graph.py \
52
52
  --db /tmp/self_graph.db \
53
53
  --fqn "cgis.pipeline.IngestionPipeline.run" \
54
54
  --depth 1 \
55
55
  --path-prefix "src/"
56
56
 
57
57
  - name: Generate MCP reference manual
58
- run: uv run python scripts/generate_mcp_ref.py
58
+ run: uv run --frozen python scripts/generate_mcp_ref.py
59
59
 
60
60
  - name: Sync schema docs from source
61
- run: uv run python scripts/generate_schema_docs.py
61
+ run: uv run --frozen python scripts/generate_schema_docs.py
62
62
 
63
63
  - name: Open PR with generated docs
64
64
  uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
@@ -0,0 +1,46 @@
1
+ name: Continuous Integration
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, dev, "feat/**", "fix/**", "docs/**" ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ python-ci:
11
+ name: Python Verification
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Checkout Code
15
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
16
+
17
+ - name: Setup uv
18
+ uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
19
+ with:
20
+ enable-cache: true
21
+
22
+ - name: Lockfile in step with pyproject
23
+ # This is the only step that validates the lockfile. `--frozen` below stops
24
+ # uv rewriting uv.lock, but it does not check that the lock is current —
25
+ # that is `--locked`. Keeping the check explicit gives a clearer failure
26
+ # than a sync error, and it still runs first so an unfrozen uv could never
27
+ # repair the lock ahead of it.
28
+ run: uv lock --check
29
+
30
+ - name: Install Dependencies
31
+ run: uv sync --frozen --group dev
32
+
33
+ - name: Ruff Format Check
34
+ run: uv run --frozen ruff format --check .
35
+
36
+ - name: Ruff Lint
37
+ run: uv run --frozen ruff check .
38
+
39
+ - name: Interrogate (≥90% docstring coverage)
40
+ run: uv run --frozen interrogate -v --fail-under 90 src/cgis
41
+
42
+ - name: Mypy (strict)
43
+ run: uv run --frozen mypy src
44
+
45
+ - name: Pytest
46
+ run: uv run --frozen pytest --cov=cgis --cov-report=term-missing
@@ -67,10 +67,10 @@ jobs:
67
67
  uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
68
68
 
69
69
  - name: Install dependencies
70
- run: uv sync --extra guardian
70
+ run: uv sync --frozen --extra guardian
71
71
 
72
72
  - name: Build code graph
73
- run: uv run cgis ingest ./src --output graph.db
73
+ run: uv run --frozen cgis ingest ./src --output graph.db
74
74
 
75
75
  - name: Restore metrics from data branch
76
76
  run: |
@@ -91,7 +91,7 @@ jobs:
91
91
  GUARDIAN_SKEPTIC: ${{ vars.GUARDIAN_SKEPTIC }}
92
92
  GUARDIAN_SKEPTIC_MODEL: ${{ vars.GUARDIAN_SKEPTIC_MODEL }}
93
93
  run: |
94
- uv run python scripts/guardian_review.py \
94
+ uv run --frozen python scripts/guardian_review.py \
95
95
  --output guardian_report.md \
96
96
  --db graph.db \
97
97
  --pr "$PR_NUMBER" \
@@ -219,7 +219,7 @@ jobs:
219
219
  git show origin/data/guardian-metrics:guardian_metrics.jsonl \
220
220
  > guardian_metrics.jsonl
221
221
 
222
- uv run cgis guardian-rate "$PR_NUMBER" "$APPLIED" \
222
+ uv run --frozen cgis guardian-rate "$PR_NUMBER" "$APPLIED" \
223
223
  --metrics guardian_metrics.jsonl
224
224
 
225
225
  if git ls-remote --exit-code origin data/guardian-metrics > /dev/null 2>&1; then
@@ -0,0 +1,51 @@
1
+ name: PR Title
2
+
3
+ # The repository squash-merges, so the PR title becomes the commit subject that
4
+ # release-please parses. A title it does not recognise is dropped from the
5
+ # changelog silently — no warning, no failure. That has now happened twice:
6
+ # #297 ("drift trust batch: …", a descriptive title) and #313
7
+ # ("security(mcp): …", a type that does not exist), the second of which would
8
+ # have shipped a security fix invisibly.
9
+ on:
10
+ pull_request:
11
+ branches: [ main ]
12
+ # `edited` matters: without it, fixing a rejected title would not re-run
13
+ # the check. Kept in a separate workflow from ci.yml so retitling does not
14
+ # replay the whole test suite.
15
+ types: [ opened, edited, reopened, synchronize ]
16
+
17
+ permissions: {}
18
+
19
+ jobs:
20
+ conventional-title:
21
+ name: Conventional commit title
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - name: Check the title release-please will parse
25
+ env:
26
+ # Never interpolate an untrusted title straight into `run:` — it is
27
+ # attacker-controlled text. Through the environment it is just data.
28
+ PR_TITLE: ${{ github.event.pull_request.title }}
29
+ run: |
30
+ set -euo pipefail
31
+ # Types release-please understands. Anything else is dropped from the
32
+ # changelog without complaint, which is the failure being prevented.
33
+ TYPES='feat|fix|docs|chore|style|refactor|perf|test|build|ci|revert'
34
+ if printf '%s' "$PR_TITLE" | grep -qE "^($TYPES)(\([a-z0-9._/-]+\))?!?: .+"; then
35
+ printf '::notice::PR title is a conventional commit.\n'
36
+ exit 0
37
+ fi
38
+ printf '::error::PR title is not a conventional commit: %s\n' "$PR_TITLE"
39
+ cat >&2 <<'MSG'
40
+
41
+ This repository squash-merges, so the PR title becomes the commit
42
+ subject release-please reads. An unrecognised type is dropped from the
43
+ CHANGELOG silently.
44
+
45
+ Expected: <type>(<optional scope>): <description>
46
+ Types: feat fix docs chore style refactor perf test build ci revert
47
+
48
+ Note there is no `security` type — use `fix` with a scope:
49
+ fix(mcp): validate db_path before cgis_ingest creates a database
50
+ MSG
51
+ exit 1
@@ -0,0 +1,147 @@
1
+ name: Release Please
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ release-please:
10
+ name: Release Please
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ # Scoped to this job only: the publish job below must never inherit
14
+ # write access to the repository.
15
+ contents: write
16
+ pull-requests: write
17
+ outputs:
18
+ release_created: ${{ steps.release.outputs.release_created }}
19
+ tag_name: ${{ steps.release.outputs.tag_name }}
20
+ release_pr: ${{ steps.release.outputs.pr }}
21
+ steps:
22
+ - name: Mint a GitHub App token
23
+ id: app-token
24
+ # A GITHUB_TOKEN-authored PR leaves its checks parked in
25
+ # `action_required` forever, so release-please needs an identity of its
26
+ # own. App tokens beat a PAT: one hour of life, auto-rotated, scoped to
27
+ # this repo, and not tied to anyone's personal account.
28
+ # continue-on-error: an unconfigured App must degrade, not break the release.
29
+ continue-on-error: true
30
+ uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
31
+ with:
32
+ # Accepted from either store: the App ID is not sensitive, so a repo
33
+ # variable is conventional, but it is commonly filed as a secret.
34
+ app-id: ${{ vars.CGIS_APP_ID || secrets.CGIS_APP_ID }}
35
+ private-key: ${{ secrets.CGIS_APP_PRIVATE_KEY }}
36
+
37
+ - name: Run release-please
38
+ id: release
39
+ uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4.4.1
40
+ with:
41
+ # Falls back to GITHUB_TOKEN when the App is not configured — the
42
+ # release still opens, its checks just need a manual nudge.
43
+ token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
44
+ config-file: release-please-config.json
45
+ manifest-file: .release-please-manifest.json
46
+
47
+ relock:
48
+ name: Re-lock the release PR
49
+ needs: release-please
50
+ # Only when release-please actually has an open release PR to amend.
51
+ if: needs.release-please.outputs.release_pr != ''
52
+ runs-on: ubuntu-latest
53
+ permissions:
54
+ # Narrower than the release job: this one only pushes a lockfile.
55
+ contents: write
56
+ steps:
57
+ - name: Mint a GitHub App token
58
+ id: app-token
59
+ # A GITHUB_TOKEN-authored PR leaves its checks parked in
60
+ # `action_required` forever, so release-please needs an identity of its
61
+ # own. App tokens beat a PAT: one hour of life, auto-rotated, scoped to
62
+ # this repo, and not tied to anyone's personal account.
63
+ # continue-on-error: an unconfigured App must degrade, not break the release.
64
+ continue-on-error: true
65
+ uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
66
+ with:
67
+ # Accepted from either store: the App ID is not sensitive, so a repo
68
+ # variable is conventional, but it is commonly filed as a secret.
69
+ app-id: ${{ vars.CGIS_APP_ID || secrets.CGIS_APP_ID }}
70
+ private-key: ${{ secrets.CGIS_APP_PRIVATE_KEY }}
71
+
72
+ - name: Checkout the release branch
73
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
74
+ with:
75
+ ref: ${{ fromJSON(needs.release-please.outputs.release_pr).headBranchName }}
76
+ token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
77
+
78
+ - name: Setup uv
79
+ uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
80
+ with:
81
+ enable-cache: true
82
+
83
+ - name: Re-lock and push if the version moved
84
+ run: |
85
+ set -euo pipefail
86
+ # release-please bumps pyproject.toml but never re-resolves uv.lock, so
87
+ # the lockfile's own version entry falls a release behind and the CI
88
+ # `uv lock --check` gate fails on every release PR (#303).
89
+ uv lock
90
+ if git diff --quiet -- uv.lock; then
91
+ echo "uv.lock already in step with pyproject.toml"
92
+ exit 0
93
+ fi
94
+ git config user.name "github-actions[bot]"
95
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
96
+ git add uv.lock
97
+ git commit -m "chore: re-lock uv.lock for the release"
98
+ git push
99
+
100
+ publish:
101
+ name: Publish to PyPI
102
+ needs: release-please
103
+ if: needs.release-please.outputs.release_created == 'true'
104
+ runs-on: ubuntu-latest
105
+ environment:
106
+ name: pypi
107
+ url: https://pypi.org/p/codegraph-brain
108
+ permissions:
109
+ # Mints the short-lived OIDC token PyPI exchanges for an upload token.
110
+ # This is the whole point of trusted publishing: no API token in secrets.
111
+ id-token: write
112
+ # Lets the publish action attach PEP 740 provenance attestations.
113
+ attestations: write
114
+ contents: read
115
+ steps:
116
+ - name: Checkout Code
117
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
118
+ with:
119
+ ref: ${{ needs.release-please.outputs.tag_name }}
120
+
121
+ - name: Setup uv
122
+ uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
123
+ with:
124
+ enable-cache: true
125
+
126
+ - name: Build sdist and wheel
127
+ run: uv build
128
+
129
+ - name: Verify metadata
130
+ # Pinned and wheel-only: this job holds publish rights, so the tooling
131
+ # it pulls in must not be a floating version that can run setup scripts.
132
+ run: uvx --no-build --from "twine==7.0.0" twine check dist/*
133
+
134
+ - name: Verify version matches the tag
135
+ env:
136
+ TAG_NAME: ${{ needs.release-please.outputs.tag_name }}
137
+ run: |
138
+ set -euo pipefail
139
+ built=$(ls dist/*.whl | sed -E 's/.*-([0-9][^-]*)-py3.*/\1/')
140
+ echo "tag=$TAG_NAME built=$built"
141
+ case "$TAG_NAME" in
142
+ *"$built") ;;
143
+ *) echo "::error::tag $TAG_NAME does not match built version $built"; exit 1 ;;
144
+ esac
145
+
146
+ - name: Publish
147
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.7.4"
3
+ }
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.4](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.7.3...codegraph-brain-v0.7.4) (2026-08-01)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **mcp:** validate db_path before cgis_ingest creates a database ([#313](https://github.com/zaebee/codegraph-brain/issues/313)) ([2c5499b](https://github.com/zaebee/codegraph-brain/commit/2c5499b8fb7f0d40a03144417c3210900371d499)), closes [#312](https://github.com/zaebee/codegraph-brain/issues/312)
9
+
10
+
11
+ ### Documentation
12
+
13
+ * auto-sync architecture graph and MCP reference ([#314](https://github.com/zaebee/codegraph-brain/issues/314)) ([7d5b666](https://github.com/zaebee/codegraph-brain/commit/7d5b66669f9dfa40e2fc86dd59a4baf492a9342e))
14
+
15
+ ## [0.7.3](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.7.2...codegraph-brain-v0.7.3) (2026-07-31)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **assets:** drop the argv-driven output path from the avatar generator ([#308](https://github.com/zaebee/codegraph-brain/issues/308)) ([d118074](https://github.com/zaebee/codegraph-brain/commit/d118074a6b2137f789b4978f870f5496ee1135b5))
21
+ * **ci:** read the App ID from a secret as well as a variable ([#306](https://github.com/zaebee/codegraph-brain/issues/306)) ([90513bc](https://github.com/zaebee/codegraph-brain/commit/90513bc3f588241848fd7404f9be5b6479a72293))
22
+
3
23
  ## [0.7.2](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.7.1...codegraph-brain-v0.7.2) (2026-07-31)
4
24
 
5
25
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codegraph-brain
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: Semantic code graph for AI agents — deterministic FQN resolution, impact analysis and architectural drift gates, exposed over MCP.
5
5
  Project-URL: Homepage, https://github.com/zaebee/codegraph-brain
6
6
  Project-URL: Repository, https://github.com/zaebee/codegraph-brain
@@ -0,0 +1 @@
1
+ _variants/
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200"><rect width="200" height="200" rx="44" fill="#0d1526"/><line x1="113.2" y1="55.7" x2="142.8" y2="86.3" stroke="#64748b" stroke-width="8" stroke-linecap="round"/><line x1="142.8" y1="113.7" x2="113.2" y2="144.3" stroke="#64748b" stroke-width="8" stroke-linecap="round"/><line x1="86.8" y1="55.7" x2="57.2" y2="86.3" stroke="#fbbf24" stroke-width="9" stroke-linecap="round"/><line x1="57.2" y1="113.7" x2="86.8" y2="144.3" stroke="#fbbf24" stroke-width="9" stroke-linecap="round"/><circle cx="100" cy="42" r="18" fill="#22d3ee"/><circle cx="44" cy="100" r="18" fill="#fbbf24"/><circle cx="156" cy="100" r="18" fill="#a78bfa"/><circle cx="100" cy="158" r="18" fill="#22d3ee"/></svg>
@@ -0,0 +1,123 @@
1
+ """Generate the cgis GitHub App avatar.
2
+
3
+ Ships `v3-lit-path` as `cgis-app-avatar.png`; the other two are kept so the
4
+ alternatives are on the record rather than lost in a chat log.
5
+
6
+ The motif comes from the domain rather than decoration: cgis's drift alphabet is
7
+ built on directed triads (`_TRICODES` / `TRIAD_ORDER`), so the glyphs are actual
8
+ triad shapes — 021D (diverging) and the layered_dag ideal.
9
+
10
+ No arrowheads. SVG markers scale by stroke-width by default (a 4.5-unit head at
11
+ stroke 9 renders as a 40-unit blob), and even sized correctly an arrowhead is
12
+ mush at the 40px a bot avatar occupies in a PR thread. Hierarchy is carried by
13
+ node size and colour instead.
14
+
15
+ Rendered at 400px for upload and 40px to check legibility at comment size.
16
+ """
17
+
18
+ import pathlib
19
+
20
+ import cairosvg
21
+
22
+ BG = "#0d1526"
23
+ EDGE = "#64748b"
24
+ CYAN = "#22d3ee"
25
+ VIOLET = "#a78bfa"
26
+ AMBER = "#fbbf24"
27
+
28
+ HEAD = (
29
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200">'
30
+ f'<rect width="200" height="200" rx="44" fill="{BG}"/>'
31
+ )
32
+ TAIL = "</svg>"
33
+
34
+
35
+ def edge(
36
+ p1: tuple[float, float], p2: tuple[float, float], *, colour: str = EDGE, w: float = 8
37
+ ) -> str:
38
+ """A graph edge, trimmed at both ends so it meets the node rims cleanly."""
39
+ (x1, y1), (x2, y2) = p1, p2
40
+ dx, dy = x2 - x1, y2 - y1
41
+ length = (dx * dx + dy * dy) ** 0.5
42
+ ux, uy = dx / length, dy / length
43
+ pad = 19
44
+ return (
45
+ f'<line x1="{x1 + ux * pad:.1f}" y1="{y1 + uy * pad:.1f}" '
46
+ f'x2="{x2 - ux * pad:.1f}" y2="{y2 - uy * pad:.1f}" '
47
+ f'stroke="{colour}" stroke-width="{w}" stroke-linecap="round"/>'
48
+ )
49
+
50
+
51
+ def node(p: tuple[float, float], colour: str, r: float = 18) -> str:
52
+ """A graph node."""
53
+ return f'<circle cx="{p[0]}" cy="{p[1]}" r="{r}" fill="{colour}"/>'
54
+
55
+
56
+ TOP, LEFT, RIGHT, BOTTOM = (100, 42), (44, 100), (156, 100), (100, 158)
57
+
58
+ # 1. layered_dag — diverge at the top, converge at the bottom.
59
+ v1 = (
60
+ HEAD
61
+ + edge(TOP, LEFT)
62
+ + edge(TOP, RIGHT)
63
+ + edge(LEFT, BOTTOM)
64
+ + edge(RIGHT, BOTTOM)
65
+ + node(TOP, CYAN)
66
+ + node(LEFT, VIOLET)
67
+ + node(RIGHT, VIOLET)
68
+ + node(BOTTOM, CYAN)
69
+ + TAIL
70
+ )
71
+
72
+ # 2. 021D on its own — fewest strokes, best legibility at 40px.
73
+ T2, BL2, BR2 = (100, 54), (48, 144), (152, 144)
74
+ v2 = (
75
+ HEAD
76
+ + edge(T2, BL2, w=9)
77
+ + edge(T2, BR2, w=9)
78
+ + node(T2, CYAN, 21)
79
+ + node(BL2, VIOLET, 21)
80
+ + node(BR2, VIOLET, 21)
81
+ + TAIL
82
+ )
83
+
84
+ # 3. layered_dag with one path lit — structure, plus the analysis laid over it.
85
+ v3 = (
86
+ HEAD
87
+ + edge(TOP, RIGHT)
88
+ + edge(RIGHT, BOTTOM)
89
+ + edge(TOP, LEFT, colour=AMBER, w=9)
90
+ + edge(LEFT, BOTTOM, colour=AMBER, w=9)
91
+ + node(TOP, CYAN)
92
+ + node(LEFT, AMBER)
93
+ + node(RIGHT, VIOLET)
94
+ + node(BOTTOM, CYAN)
95
+ + TAIL
96
+ )
97
+
98
+ HERE = pathlib.Path(__file__).parent
99
+ # Variants land in a gitignored scratch dir; only the chosen one is versioned,
100
+ # so re-running this never litters docs/assets.
101
+ VARIANTS = HERE / "_variants"
102
+ VARIANTS.mkdir(parents=True, exist_ok=True)
103
+
104
+ CHOSEN = "v3-lit-path"
105
+
106
+ for name, svg in (("v1-layered-dag", v1), ("v2-fanout", v2), ("v3-lit-path", v3)):
107
+ (VARIANTS / f"{name}.svg").write_text(svg)
108
+ for px in (400, 40):
109
+ cairosvg.svg2png(
110
+ bytestring=svg.encode(),
111
+ write_to=str(VARIANTS / f"{name}-{px}.png"),
112
+ output_width=px,
113
+ output_height=px,
114
+ )
115
+ if name == CHOSEN:
116
+ (HERE / "cgis-app-avatar.svg").write_text(svg)
117
+ cairosvg.svg2png(
118
+ bytestring=svg.encode(),
119
+ write_to=str(HERE / "cgis-app-avatar.png"),
120
+ output_width=400,
121
+ output_height=400,
122
+ )
123
+ print(f"rendered {name}" + (" <- shipped as cgis-app-avatar.*" if name == CHOSEN else ""))
@@ -176,9 +176,14 @@ Show the structural layout (CONTAINS/DECLARES) of a module or class.
176
176
  Scan a local directory, extract all symbols, resolve links, and build the graph DB.
177
177
 
178
178
  Use this to initialise or refresh the code knowledge graph for a project.
179
- Paths are normalised relative to the workspace root so the database is
179
+ Node FQNs are normalised relative to the workspace root so the graph is
180
180
  portable across machines.
181
181
 
182
+ ``db_path`` must name a database — it has to end in ``.db``, ``.sqlite`` or
183
+ ``.sqlite3``, live in a directory that already exists, and not point at an
184
+ existing file that is not a SQLite database. cgis will not create parent
185
+ directories.
186
+
182
187
  By default the ingest is **incremental**: only changed/new files are
183
188
  re-scanned, and the summary reports both what changed this run and the
184
189
  whole-graph total. Set ``full_rebuild=True`` to re-scan every file and
@@ -7,7 +7,7 @@ packages = ["src/cgis"]
7
7
 
8
8
  [project]
9
9
  name = "codegraph-brain"
10
- version = "0.7.2"
10
+ version = "0.7.4"
11
11
  description = "Semantic code graph for AI agents — deterministic FQN resolution, impact analysis and architectural drift gates, exposed over MCP."
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.12"
@@ -85,20 +85,92 @@ def _render_subgraph(
85
85
  return f"❌ Unknown format '{output_format}'. Use 'mermaid' or 'json'."
86
86
 
87
87
 
88
+ #: Names cgis will create a database under. Everything else is refused, so an
89
+ #: agent cannot be talked into materialising `~/.ssh/authorized_keys` (#312).
90
+ _DB_SUFFIXES = frozenset({".db", ".sqlite", ".sqlite3"})
91
+
92
+ #: First 16 bytes of any SQLite file.
93
+ _SQLITE_MAGIC = b"SQLite format 3\x00"
94
+
95
+
96
+ def _reject_db_path(db_path: str) -> str | None:
97
+ """Return a refusal message for an unusable ``db_path``, or None if it is fine.
98
+
99
+ ``cgis_ingest`` is the only MCP tool that creates its database — the other
100
+ twelve refuse a path that does not already exist, which is guard enough for
101
+ them. It needs a different one: it reads untrusted repository content and is
102
+ then told by the same agent where to write, so ``db_path`` is attacker-
103
+ reachable in a way the read-only tools' paths are not.
104
+
105
+ Refuses an unexpected suffix, a missing parent directory (creating a tree is
106
+ never wanted), a directory target, and an existing file that is not a
107
+ database. The last is belt-and-braces — SQLite already declines to open a
108
+ non-database — but it fails with a message that says why.
109
+
110
+ Everything is judged on the **resolved** path. A dangling symlink is the
111
+ bypass this guard exists to stop: ``attack.db`` pointing at a target that
112
+ does not exist yet makes ``is_file()`` return False, every check passes, and
113
+ SQLite creates the target. Resolving first means the suffix rule applies to
114
+ where the write actually lands. (A symlink to an *existing* non-database was
115
+ already refused by the magic-byte check.)
116
+
117
+ The filesystem probes are wrapped: this runs *before* ``cgis_ingest``'s own
118
+ try/except, and ``Path.resolve()``, ``Path.is_dir()`` and friends propagate
119
+ ``OSError`` (a ``PermissionError`` on the parent, or a symlink loop), which
120
+ would escape the tool as a crash instead of a message the agent can act on.
121
+ """
122
+ try:
123
+ path = Path(db_path).resolve()
124
+ except OSError as exc:
125
+ return f"❌ Refusing db_path '{db_path}': path is inaccessible ({exc})."
126
+ # Case-insensitive: `.DB` carries the same intent, and on a case-insensitive
127
+ # filesystem it is literally the same file.
128
+ if path.suffix.lower() not in _DB_SUFFIXES:
129
+ allowed = ", ".join(sorted(_DB_SUFFIXES))
130
+ return f"❌ Refusing db_path '{db_path}': name must end in one of {allowed}."
131
+ try:
132
+ if path.is_dir():
133
+ return f"❌ Refusing db_path '{db_path}': it is a directory."
134
+ if not path.parent.is_dir():
135
+ return (
136
+ f"❌ Refusing db_path '{db_path}': parent directory does not exist. "
137
+ "cgis will not create one."
138
+ )
139
+ if path.is_file() and path.stat().st_size > 0:
140
+ with path.open("rb") as fh:
141
+ if fh.read(len(_SQLITE_MAGIC)) != _SQLITE_MAGIC:
142
+ return (
143
+ f"❌ Refusing db_path '{db_path}': existing file is not a SQLite database."
144
+ )
145
+ except OSError as exc:
146
+ return f"❌ Refusing db_path '{db_path}': path is inaccessible ({exc})."
147
+ return None
148
+
149
+
88
150
  @mcp.tool()
89
151
  def cgis_ingest(project_path: str, db_path: str = _DEFAULT_DB, full_rebuild: bool = False) -> str:
90
152
  """Scan a local directory, extract all symbols, resolve links, and build the graph DB.
91
153
 
92
154
  Use this to initialise or refresh the code knowledge graph for a project.
93
- Paths are normalised relative to the workspace root so the database is
155
+ Node FQNs are normalised relative to the workspace root so the graph is
94
156
  portable across machines.
95
157
 
158
+ ``db_path`` must name a database — it has to end in ``.db``, ``.sqlite`` or
159
+ ``.sqlite3``, live in a directory that already exists, and not point at an
160
+ existing file that is not a SQLite database. cgis will not create parent
161
+ directories.
162
+
96
163
  By default the ingest is **incremental**: only changed/new files are
97
164
  re-scanned, and the summary reports both what changed this run and the
98
165
  whole-graph total. Set ``full_rebuild=True`` to re-scan every file and
99
166
  overwrite the database from scratch — use this to drop nodes for files that
100
167
  were deleted or renamed, which an incremental run leaves behind.
101
168
  """
169
+ refusal = _reject_db_path(db_path)
170
+ if refusal is not None:
171
+ logger.warning("MCP ingest refused db_path", db=db_path)
172
+ return refusal
173
+
102
174
  pipeline = IngestionPipeline(_EXTRACTORS)
103
175
  try:
104
176
  with SQLiteStore(db_path) as store:
@@ -126,7 +126,7 @@ class ResolverEngine:
126
126
 
127
127
  def _ensure_virtual_node(self, target: str, virtual_nodes: dict[str, Node]) -> None:
128
128
  """Create a virtual boundary node for target if it is not already in the graph."""
129
- if target not in self._index.nodes and target not in virtual_nodes:
129
+ if not self._index.has_node(target) and target not in virtual_nodes:
130
130
  virtual_nodes[target] = self._make_virtual_node(
131
131
  target, self._index.classify_fqn(target)
132
132
  )