semantic-code-review 0.24.2__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 (131) hide show
  1. semantic_code_review-0.24.2/LICENSE +21 -0
  2. semantic_code_review-0.24.2/PKG-INFO +348 -0
  3. semantic_code_review-0.24.2/README.md +310 -0
  4. semantic_code_review-0.24.2/pyproject.toml +159 -0
  5. semantic_code_review-0.24.2/semantic_code_review/__init__.py +5 -0
  6. semantic_code_review-0.24.2/semantic_code_review/augment/__init__.py +3 -0
  7. semantic_code_review-0.24.2/semantic_code_review/augment/agents.py +95 -0
  8. semantic_code_review-0.24.2/semantic_code_review/augment/console.py +440 -0
  9. semantic_code_review-0.24.2/semantic_code_review/augment/extra_review.py +237 -0
  10. semantic_code_review-0.24.2/semantic_code_review/augment/fold_summary.py +447 -0
  11. semantic_code_review-0.24.2/semantic_code_review/augment/hunks.py +264 -0
  12. semantic_code_review-0.24.2/semantic_code_review/augment/mcp_server.py +156 -0
  13. semantic_code_review-0.24.2/semantic_code_review/augment/overview.py +233 -0
  14. semantic_code_review-0.24.2/semantic_code_review/augment/pass_.py +171 -0
  15. semantic_code_review-0.24.2/semantic_code_review/augment/pipeline.py +571 -0
  16. semantic_code_review-0.24.2/semantic_code_review/augment/progress.py +223 -0
  17. semantic_code_review-0.24.2/semantic_code_review/augment/prompts.py +93 -0
  18. semantic_code_review-0.24.2/semantic_code_review/augment/schemas.py +408 -0
  19. semantic_code_review-0.24.2/semantic_code_review/augment/tools.py +475 -0
  20. semantic_code_review-0.24.2/semantic_code_review/augment/trace_adapter.py +369 -0
  21. semantic_code_review-0.24.2/semantic_code_review/backends/__init__.py +95 -0
  22. semantic_code_review-0.24.2/semantic_code_review/backends/_cli_driver.py +571 -0
  23. semantic_code_review-0.24.2/semantic_code_review/backends/anthropic_sdk.py +56 -0
  24. semantic_code_review-0.24.2/semantic_code_review/backends/base.py +104 -0
  25. semantic_code_review-0.24.2/semantic_code_review/backends/claude_cli.py +421 -0
  26. semantic_code_review-0.24.2/semantic_code_review/backends/google_sdk.py +73 -0
  27. semantic_code_review-0.24.2/semantic_code_review/backends/openai_compat.py +42 -0
  28. semantic_code_review-0.24.2/semantic_code_review/cache/__init__.py +3 -0
  29. semantic_code_review-0.24.2/semantic_code_review/cache/store.py +87 -0
  30. semantic_code_review-0.24.2/semantic_code_review/cli/__init__.py +70 -0
  31. semantic_code_review-0.24.2/semantic_code_review/cli/_shared.py +157 -0
  32. semantic_code_review-0.24.2/semantic_code_review/cli/augment.py +74 -0
  33. semantic_code_review-0.24.2/semantic_code_review/cli/config_cmd.py +266 -0
  34. semantic_code_review-0.24.2/semantic_code_review/cli/fetch.py +33 -0
  35. semantic_code_review-0.24.2/semantic_code_review/cli/lint.py +27 -0
  36. semantic_code_review-0.24.2/semantic_code_review/cli/pr.py +98 -0
  37. semantic_code_review-0.24.2/semantic_code_review/cli/review.py +104 -0
  38. semantic_code_review-0.24.2/semantic_code_review/cli/runs_cmd.py +17 -0
  39. semantic_code_review-0.24.2/semantic_code_review/cli/show.py +19 -0
  40. semantic_code_review-0.24.2/semantic_code_review/cli/strip.py +20 -0
  41. semantic_code_review-0.24.2/semantic_code_review/config.py +563 -0
  42. semantic_code_review-0.24.2/semantic_code_review/config_template.py +154 -0
  43. semantic_code_review-0.24.2/semantic_code_review/fetch/__init__.py +61 -0
  44. semantic_code_review-0.24.2/semantic_code_review/fetch/anchor.py +244 -0
  45. semantic_code_review-0.24.2/semantic_code_review/fetch/github.py +229 -0
  46. semantic_code_review-0.24.2/semantic_code_review/fetch/github_comments.py +404 -0
  47. semantic_code_review-0.24.2/semantic_code_review/fetch/local.py +443 -0
  48. semantic_code_review-0.24.2/semantic_code_review/fetch/run_source.py +70 -0
  49. semantic_code_review-0.24.2/semantic_code_review/format/__init__.py +3 -0
  50. semantic_code_review-0.24.2/semantic_code_review/format/emit.py +163 -0
  51. semantic_code_review-0.24.2/semantic_code_review/format/lint.py +74 -0
  52. semantic_code_review-0.24.2/semantic_code_review/format/parse.py +574 -0
  53. semantic_code_review-0.24.2/semantic_code_review/format/sidecar.py +19 -0
  54. semantic_code_review-0.24.2/semantic_code_review/format/strip.py +20 -0
  55. semantic_code_review-0.24.2/semantic_code_review/git_ops.py +252 -0
  56. semantic_code_review-0.24.2/semantic_code_review/paths.py +61 -0
  57. semantic_code_review-0.24.2/semantic_code_review/review/__init__.py +3 -0
  58. semantic_code_review-0.24.2/semantic_code_review/review/comments.py +176 -0
  59. semantic_code_review-0.24.2/semantic_code_review/review/github.py +284 -0
  60. semantic_code_review-0.24.2/semantic_code_review/review/github_graphql.py +433 -0
  61. semantic_code_review-0.24.2/semantic_code_review/review/pr_flow.py +299 -0
  62. semantic_code_review-0.24.2/semantic_code_review/review/runner.py +407 -0
  63. semantic_code_review-0.24.2/semantic_code_review/review/server.py +1043 -0
  64. semantic_code_review-0.24.2/semantic_code_review/structural/__init__.py +41 -0
  65. semantic_code_review-0.24.2/semantic_code_review/structural/diff.py +102 -0
  66. semantic_code_review-0.24.2/semantic_code_review/structural/parse.py +330 -0
  67. semantic_code_review-0.24.2/semantic_code_review/structural/symbols.py +43 -0
  68. semantic_code_review-0.24.2/semantic_code_review/viewer/__init__.py +3 -0
  69. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/annotations.ts +547 -0
  70. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/boot.ts +273 -0
  71. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/comment_store.ts +121 -0
  72. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/comments.ts +624 -0
  73. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/console.ts +426 -0
  74. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/console_render.ts +213 -0
  75. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/console_selection.ts +102 -0
  76. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/data_store.ts +156 -0
  77. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/file_rows.ts +49 -0
  78. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/folds.ts +560 -0
  79. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/index.html +62 -0
  80. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/post_modal.ts +383 -0
  81. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/progress.ts +138 -0
  82. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/render.ts +937 -0
  83. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/sidebar.ts +429 -0
  84. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/sse.ts +78 -0
  85. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/text_highlight.ts +215 -0
  86. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/types.d.ts +388 -0
  87. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/LICENSE +29 -0
  88. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/VENDOR.md +55 -0
  89. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/github-dark.min.css +10 -0
  90. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/github.min.css +10 -0
  91. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/highlight.min.js +1244 -0
  92. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/mermaid.LICENSE +21 -0
  93. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/mermaid.min.js +3587 -0
  94. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/refresh.sh +65 -0
  95. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/viewer.css +1202 -0
  96. semantic_code_review-0.24.2/semantic_code_review/viewer/assets/viewer.js +10588 -0
  97. semantic_code_review-0.24.2/semantic_code_review/viewer/build_json.py +546 -0
  98. semantic_code_review-0.24.2/semantic_code_review/viewer/hunk_layout.py +471 -0
  99. semantic_code_review-0.24.2/semantic_code_review.egg-info/PKG-INFO +348 -0
  100. semantic_code_review-0.24.2/semantic_code_review.egg-info/SOURCES.txt +129 -0
  101. semantic_code_review-0.24.2/semantic_code_review.egg-info/dependency_links.txt +1 -0
  102. semantic_code_review-0.24.2/semantic_code_review.egg-info/entry_points.txt +2 -0
  103. semantic_code_review-0.24.2/semantic_code_review.egg-info/requires.txt +16 -0
  104. semantic_code_review-0.24.2/semantic_code_review.egg-info/top_level.txt +1 -0
  105. semantic_code_review-0.24.2/setup.cfg +4 -0
  106. semantic_code_review-0.24.2/tests/test_augment_pipeline.py +497 -0
  107. semantic_code_review-0.24.2/tests/test_backend_select.py +173 -0
  108. semantic_code_review-0.24.2/tests/test_cache_keys.py +65 -0
  109. semantic_code_review-0.24.2/tests/test_cli_smoke.py +139 -0
  110. semantic_code_review-0.24.2/tests/test_config.py +623 -0
  111. semantic_code_review-0.24.2/tests/test_config_template.py +94 -0
  112. semantic_code_review-0.24.2/tests/test_console.py +459 -0
  113. semantic_code_review-0.24.2/tests/test_fold_summary_apply.py +227 -0
  114. semantic_code_review-0.24.2/tests/test_format_roundtrip.py +184 -0
  115. semantic_code_review-0.24.2/tests/test_github_graphql_post.py +468 -0
  116. semantic_code_review-0.24.2/tests/test_github_pr_review.py +252 -0
  117. semantic_code_review-0.24.2/tests/test_hunk_layout.py +297 -0
  118. semantic_code_review-0.24.2/tests/test_mcp_server.py +123 -0
  119. semantic_code_review-0.24.2/tests/test_overview_groups.py +152 -0
  120. semantic_code_review-0.24.2/tests/test_overview_seed.py +105 -0
  121. semantic_code_review-0.24.2/tests/test_parse.py +105 -0
  122. semantic_code_review-0.24.2/tests/test_progress_meter.py +102 -0
  123. semantic_code_review-0.24.2/tests/test_pydantic_ai_agents.py +129 -0
  124. semantic_code_review-0.24.2/tests/test_repo_tool_fns.py +257 -0
  125. semantic_code_review-0.24.2/tests/test_review_server.py +1059 -0
  126. semantic_code_review-0.24.2/tests/test_schema_unification.py +77 -0
  127. semantic_code_review-0.24.2/tests/test_segments.py +175 -0
  128. semantic_code_review-0.24.2/tests/test_structural.py +331 -0
  129. semantic_code_review-0.24.2/tests/test_tools.py +121 -0
  130. semantic_code_review-0.24.2/tests/test_trace_adapter.py +331 -0
  131. semantic_code_review-0.24.2/tests/test_viewer_json.py +425 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Centre for Population Genomics
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,348 @@
1
+ Metadata-Version: 2.4
2
+ Name: semantic-code-review
3
+ Version: 0.24.2
4
+ Summary: LLM-augmented GitHub PR viewer with foldable semantic diffs.
5
+ Author-email: Toby Sargeant <toby.sargeant@populationgenomics.org.au>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/populationgenomics/semantic-code-review
8
+ Project-URL: Repository, https://github.com/populationgenomics/semantic-code-review
9
+ Project-URL: Issues, https://github.com/populationgenomics/semantic-code-review/issues
10
+ Keywords: code-review,diff,llm,claude,tree-sitter,pull-request
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Version Control :: Git
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Classifier: Environment :: Console
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: anthropic==0.97.0
23
+ Requires-Dist: google-genai==1.75.0
24
+ Requires-Dist: jinja2==3.1.6
25
+ Requires-Dist: openai==2.34.0
26
+ Requires-Dist: pydantic==2.13.3
27
+ Requires-Dist: pydantic-ai==1.90.0
28
+ Requires-Dist: tree-sitter==0.25.2
29
+ Requires-Dist: tree-sitter-python==0.25.0
30
+ Requires-Dist: tree-sitter-javascript==0.25.0
31
+ Requires-Dist: tree-sitter-typescript==0.23.2
32
+ Requires-Dist: typer==0.24.2
33
+ Requires-Dist: unidiff==0.7.5
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest==9.0.3; extra == "dev"
36
+ Requires-Dist: pytest-asyncio==1.3.0; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # scr — semantic code review
40
+
41
+ LLM-augmented local-diff reviewer. Opens an interactive side-by-side
42
+ diff in the browser with semantic-group navigation, fold-level "what
43
+ did this block change" annotations, and inline comments. When invoked
44
+ as a Claude Code plugin, it round-trips those comments back into the
45
+ session so the agent can walk through them with you.
46
+
47
+ ## Usage as a Claude Code plugin
48
+
49
+ Prerequisites on the user's machine:
50
+
51
+ - Python 3.11 or newer on `PATH`
52
+ - `git` on `PATH`
53
+ - Either `ANTHROPIC_API_KEY` in the environment (or a `.env` in the
54
+ repo you run `/scr:review` from), **or** a logged-in `claude` CLI
55
+ on `PATH` for OAuth-based fallback (no API key required)
56
+
57
+ Optional:
58
+
59
+ - `gh` — only needed if you ever run `scr fetch` / `scr run` against
60
+ a GitHub PR URL
61
+ - `ripgrep` (`rg`) — speeds up the LLM's code-search tool; `git grep`
62
+ is used as a fallback
63
+
64
+ Install:
65
+
66
+ ```
67
+ /plugin marketplace add populationgenomics/semantic-code-review
68
+ /plugin install scr
69
+ ```
70
+
71
+ The first time you run `/scr:review`, the plugin's `bin/scr` wrapper
72
+ creates a Python virtualenv under `$CLAUDE_PLUGIN_DATA/venv`, installs
73
+ the dependency closure with `pip install --require-hashes` (so any
74
+ tampered tarball fails the install instead of silently landing), then
75
+ installs `semantic-code-review` from PyPI at the version pinned in the
76
+ plugin's `pyproject.toml`. That published wheel carries the prebuilt
77
+ `viewer.js` bundle as package data, so the wrapper needs no Node, npm, or
78
+ build step — the git checkout is a thin launcher over a PyPI release. The
79
+ install is stamped (lockfile hash + version) and only re-runs when one
80
+ changes; subsequent invocations exec the cached venv and start
81
+ immediately.
82
+
83
+ ### The `/scr:review` slash command
84
+
85
+ ```
86
+ /scr:review HEAD~1 # diff working tree vs one commit back
87
+ /scr:review main..HEAD # committed-only diff of the current branch
88
+ /scr:review HEAD --spec SPEC.md # with a spec markdown as LLM ground truth
89
+ ```
90
+
91
+ The command opens a browser viewer. The left sidebar lists semantic
92
+ groups (LLM-curated clusters of related hunks); click one to filter
93
+ the visible hunks to that group, click "Show all" to clear. Hunks
94
+ that no group claimed get a subtle dotted-border tell so you can
95
+ spot them at a glance.
96
+
97
+ Leave inline comments by clicking a line number on either side of
98
+ the diff. When you click **Done**, the viewer closes, the command
99
+ returns the comments as structured markdown, and Claude Code walks
100
+ through them with you one at a time.
101
+
102
+ See `commands/review.md` for the full slash-command prompt.
103
+
104
+ ### LLM backend selection
105
+
106
+ `scr` picks a backend automatically:
107
+
108
+ - `ANTHROPIC_API_KEY` set → uses the Anthropic SDK directly (best
109
+ performance: prompt caching, native concurrency, structured tool
110
+ use).
111
+ - Otherwise, `claude` on `PATH` → falls back to a `claude -p`
112
+ subprocess with a stdio MCP server exposing the same repo-tools
113
+ the SDK path uses. No API key needed; works with any logged-in
114
+ Claude Code installation.
115
+ - Neither available → fails fast with a clear error.
116
+
117
+ Force a backend with `--backend <name>`. Run `scr config show` for
118
+ the registered names — builtins plus anything you've added under
119
+ `[backends.<name>]` in your config.
120
+
121
+ Both Gemini backends are opt-in only — never picked by `auto`.
122
+
123
+ - `--backend=gemini-api` uses Google's official `google-genai` SDK
124
+ directly. Auth ladder: `GOOGLE_CLOUD_PROJECT` set → Vertex AI
125
+ via Application Default Credentials; else `GEMINI_API_KEY` /
126
+ `GOOGLE_API_KEY` → AI Studio. Native concurrency, full structured
127
+ tool use, Gemini's implicit prompt caching surfaces as
128
+ `cache_read_input_tokens` in our usage stats. Best Gemini path
129
+ for production work.
130
+
131
+ ### Trying it without paid API access
132
+
133
+ `scr` ships builtin profiles for several free-tier providers. None
134
+ require an Anthropic or Google paid plan. Pick one, set the listed
135
+ env var, pass `--backend <name>`:
136
+
137
+ | `--backend` | Auth | Notes |
138
+ |---|---|---|
139
+ | `gemini-api` | `GEMINI_API_KEY` from [aistudio.google.com](https://aistudio.google.com) | Free tier with rate limits; hits the Google SDK directly. |
140
+ | `groq` | `GROQ_API_KEY` from [console.groq.com](https://console.groq.com) | Free tier, very fast inference, Llama 3.3 70B by default. |
141
+ | `github` | `GITHUB_TOKEN` (any GitHub account) | Free quota across multiple model families; default is `openai/gpt-4o-mini`. |
142
+ | `cerebras` | `CEREBRAS_API_KEY` from [cloud.cerebras.ai](https://cloud.cerebras.ai) | Free tier; pass `--model` (catalogue rotates). |
143
+ | `openrouter` | `OPENROUTER_API_KEY` from [openrouter.ai](https://openrouter.ai) | Mixed paid + free models; pass `--model` (e.g. `meta-llama/llama-3.3-70b-instruct:free`). |
144
+ | `mistral` | `MISTRAL_API_KEY` from [console.mistral.ai](https://console.mistral.ai) | La Plateforme free tier; default is `codestral-latest`. |
145
+ | `ollama` | none — runs against `localhost:11434` | Local llama.cpp/Ollama; pass `--model` to name something you've pulled (e.g. `qwen2.5-coder:14b`). |
146
+
147
+ The non-Anthropic / non-Google entries all reach the provider via
148
+ the OpenAI Chat Completions wire format (`type = "openai-compat"`).
149
+ Override any builtin's model — or add a new provider — with a
150
+ `[backends.<name>]` block in your config; see `scr config edit`.
151
+
152
+ If your bearer lives in a secret store rather than a long-lived env
153
+ var, use `api_key_command`: it runs a shell-free argv command and
154
+ reads the bearer from stdout. Built-in example: `--backend=github`
155
+ falls back to `gh auth token` when `GITHUB_TOKEN` isn't set. Custom
156
+ example, Anthropic key in a GCP Secret Manager entry:
157
+
158
+ ```toml
159
+ [backends.claude-api]
160
+ api_key_command = ["gcloud", "secrets", "versions", "access",
161
+ "latest", "--secret=anthropic-api-key"]
162
+ ```
163
+
164
+ The same hook works on `claude-api`, `gemini-api`, and any
165
+ `openai-compat` backend. For `gemini-api`, `GOOGLE_CLOUD_PROJECT`
166
+ takes precedence: when set, the Vertex/ADC path wins and
167
+ `api_key_command` is skipped.
168
+
169
+ Quality caveat: any non-frontier backend produces shallower hunk
170
+ intents and more spurious `refs[]`. The output is still useful as a
171
+ draft you skim, especially for small PRs, but it isn't a Claude /
172
+ Gemini Pro replacement.
173
+
174
+ ## Usage as a standalone CLI
175
+
176
+ Install from PyPI. The published wheel already contains the compiled
177
+ viewer bundle, so no Node is needed at runtime:
178
+
179
+ ```
180
+ uv tool install semantic-code-review
181
+ # or: pipx install semantic-code-review / pip install semantic-code-review
182
+ scr review HEAD~1..HEAD --spec SPEC.md
183
+ ```
184
+
185
+ From a source checkout (for development, or to pin the exact hashed
186
+ dependency set), build the viewer bundle yourself:
187
+
188
+ ```
189
+ pip install --require-hashes -r requirements.lock
190
+ pip install --no-deps --no-build-isolation .
191
+ npm ci --ignore-scripts && npm run build
192
+ scr review HEAD~1..HEAD --spec SPEC.md
193
+ ```
194
+
195
+ Subcommands:
196
+
197
+ - `scr review <ref-or-range> [--spec SPEC.md]` — local git diff,
198
+ runs LLM augment, opens viewer, prints reviewer comments as
199
+ markdown when you click Done.
200
+ - `scr pr <owner/repo> [<number>]` — same flow against a GitHub PR.
201
+ Omit the number to enumerate open PRs requesting your review;
202
+ on Done, posts the inline comments back to GitHub as a single
203
+ COMMENT-event review. Confirms before posting unless `--yes`.
204
+ - `scr fetch <pr-url>` — fetch a GitHub PR into a run directory.
205
+ - `scr augment <run-dir>` — run the LLM augmentation pass on a run
206
+ directory.
207
+ - `scr render <run-dir>` — render the HTML viewer from an augmented
208
+ run.
209
+ - `scr run <pr-url>` — fetch + augment + render (no viewer server).
210
+ - `scr show <run-dir>` — print the augmented diff to stdout.
211
+ - `scr strip <augmented.diff>` — write a plain unified diff to stdout.
212
+ - `scr lint <augmented.diff>` — validate the augmented-diff format.
213
+ - `scr runs path` — print the runs root resolved for the current cwd.
214
+
215
+ `scr pr` reuses everything `scr review` does (same fetch, augment,
216
+ viewer, server, comment store) plus a thin GitHub-side helper that
217
+ groups the inline comments into one review object via `gh api`. The
218
+ `gh` CLI must be on `PATH` and authenticated.
219
+
220
+ ### Where run artefacts live
221
+
222
+ `scr` writes per-review state — a `meta.json`, the raw and augmented
223
+ diffs, and `base/` / `head/` worktrees so the LLM (and the viewer)
224
+ can read pre- and post-change files — to a per-repo directory under
225
+ your XDG cache:
226
+
227
+ ```
228
+ ~/.cache/scr/runs/<sha256-of-git-common-dir>/<run-slug>/
229
+ ```
230
+
231
+ Worktrees of the same repo share the directory; different repos get
232
+ different ones. Runs live outside the repo on purpose — a `.scr/` at
233
+ the repo root is a deploy-tool footgun (gcloud, docker, tar tend to
234
+ upload it unless every project remembers to ignore it), and the
235
+ worktrees inside contain real git history that no one wants to
236
+ upload by accident.
237
+
238
+ Override with `--runs-root <path>` on any command that creates runs
239
+ (`review`, `pr`, `fetch`, `run`).
240
+
241
+ ## Development
242
+
243
+ ```
244
+ python3 -m venv .venv
245
+ .venv/bin/pip install --require-hashes -r build-requirements.lock
246
+ .venv/bin/pip install --require-hashes -r requirements-dev.lock
247
+ .venv/bin/pip install --no-deps --no-build-isolation -e .
248
+
249
+ npm ci --ignore-scripts
250
+ npm run build # tsc --noEmit typecheck, then esbuild bundle → semantic_code_review/viewer/assets/viewer.js
251
+ npm run test:js # vitest
252
+ .venv/bin/python -m pytest
253
+ ```
254
+
255
+ `tests/conftest.py` autobuilds the TypeScript module if it's missing
256
+ when pytest starts, so `python -m pytest` Just Works on a fresh
257
+ checkout (provided Node is available).
258
+
259
+ ## Releasing
260
+
261
+ Releases publish to [PyPI](https://pypi.org/project/semantic-code-review/)
262
+ from GitHub Actions via Trusted Publishing (OIDC) — no API tokens, no
263
+ cloud credentials. To cut a release:
264
+
265
+ 1. Bump `version` in `pyproject.toml` (and `.claude-plugin/plugin.json`
266
+ to match).
267
+ 2. Commit, then publish a GitHub Release whose tag is `vX.Y.Z` matching
268
+ that version. `.github/workflows/release.yml` fires on the published
269
+ release: it compiles the viewer bundle, builds the wheel + sdist with
270
+ `uv build`, and uploads to PyPI. A guard fails the run loudly if the
271
+ tag and `pyproject.toml` version disagree.
272
+
273
+ The plugin installs `semantic-code-review==<pyproject version>` from
274
+ PyPI, so the version on the default branch must always be one that is
275
+ published (or being published) there — bump it only as part of cutting a
276
+ release. A plugin update that lands a version PyPI doesn't yet carry will
277
+ fail its first-run install until the release finishes.
278
+
279
+ One-time setup (recorded here for a fresh fork): register a
280
+ [Trusted Publisher](https://docs.pypi.org/trusted-publishers/) on the
281
+ PyPI project pointing at this repository, workflow filename
282
+ `release.yml`, and environment `pypi`; and create a `pypi` environment
283
+ in the repo's GitHub settings.
284
+
285
+ ## What's where
286
+
287
+ - `semantic_code_review/augment/` — overview + per-hunk LLM pipeline,
288
+ prompts, schemas, MCP tool wrapper.
289
+ - `semantic_code_review/viewer/` — Python side: `build_json.py`,
290
+ `hunk_layout.py`. Frontend assets in `viewer/assets/`: eight
291
+ TypeScript modules (boot/render/sidebar/annotations/comments/
292
+ folds/progress/sse) bundled by esbuild into a single
293
+ `viewer.js`, `viewer.css`, the static `index.html` served by
294
+ the review server, and vendored `highlight.js` under
295
+ `assets/vendor/`.
296
+ - `semantic_code_review/review/` — local HTTP server that
297
+ back-channels reviewer comments to the calling process, the
298
+ shared `serve_review` helper used by both `scr review` and
299
+ `scr pr`, and `github.py` for the GitHub-PR round-trip via
300
+ `gh api`.
301
+ - `commands/review.md` — the Claude Code slash-command prompt.
302
+ - `bin/scr` — bootstrap wrapper; preflights deps, maintains the
303
+ Python venv, installs `scr` from PyPI at the pinned version, execs
304
+ the real `scr`.
305
+ - `TREE_SITTER.md` — design notes on a possible future structural
306
+ pass (symbol grouping, AST-driven fold regions, semantic hunk
307
+ splitting). Speculative; nothing in tree depends on it.
308
+
309
+ ## Supply-chain hygiene
310
+
311
+ Every external dependency is pinned by exact version and SHA-256
312
+ hash. The `bin/scr` bootstrap installs with
313
+ `pip install --require-hashes` and `npm ci`, so any on-disk artifact
314
+ whose hash doesn't match the lockfile fails the install rather than
315
+ silently landing.
316
+
317
+ Lockfiles (all committed):
318
+
319
+ - `build-requirements.lock` — PEP 517 build backend (`setuptools`,
320
+ `wheel`).
321
+ - `requirements.lock` — runtime Python deps (`anthropic`,
322
+ `pydantic`, `typer`, …).
323
+ - `requirements-dev.lock` — runtime + `pytest` + `pytest-asyncio`.
324
+ - `package-lock.json` — Node toolchain (`typescript`, `vitest`,
325
+ `@playwright/test`, `jsdom`, `@types/node`).
326
+
327
+ Frontend assets (`highlight.js` + light/dark stylesheets) are
328
+ vendored under `semantic_code_review/viewer/assets/vendor/` at a
329
+ pinned upstream version with the BSD-3-Clause LICENSE file alongside
330
+ them. The viewer HTML inlines those bytes — never loads anything
331
+ from a CDN at runtime. See `vendor/VENDOR.md` for provenance and
332
+ hashes; `vendor/refresh.sh` re-downloads at the pinned version and
333
+ fails loudly if any SHA-256 doesn't match.
334
+
335
+ Refreshing:
336
+
337
+ ```
338
+ # Python
339
+ uv pip compile pyproject.toml -o requirements.lock --generate-hashes
340
+ uv pip compile pyproject.toml --extra dev -o requirements-dev.lock --generate-hashes
341
+ printf 'setuptools>=68\nwheel\n' | uv pip compile - --generate-hashes -o build-requirements.lock
342
+
343
+ # Node toolchain
344
+ npm install # commits an updated package-lock.json with new integrity hashes
345
+
346
+ # Frontend (edit version constants in refresh.sh first if bumping)
347
+ ./semantic_code_review/viewer/assets/vendor/refresh.sh
348
+ ```
@@ -0,0 +1,310 @@
1
+ # scr — semantic code review
2
+
3
+ LLM-augmented local-diff reviewer. Opens an interactive side-by-side
4
+ diff in the browser with semantic-group navigation, fold-level "what
5
+ did this block change" annotations, and inline comments. When invoked
6
+ as a Claude Code plugin, it round-trips those comments back into the
7
+ session so the agent can walk through them with you.
8
+
9
+ ## Usage as a Claude Code plugin
10
+
11
+ Prerequisites on the user's machine:
12
+
13
+ - Python 3.11 or newer on `PATH`
14
+ - `git` on `PATH`
15
+ - Either `ANTHROPIC_API_KEY` in the environment (or a `.env` in the
16
+ repo you run `/scr:review` from), **or** a logged-in `claude` CLI
17
+ on `PATH` for OAuth-based fallback (no API key required)
18
+
19
+ Optional:
20
+
21
+ - `gh` — only needed if you ever run `scr fetch` / `scr run` against
22
+ a GitHub PR URL
23
+ - `ripgrep` (`rg`) — speeds up the LLM's code-search tool; `git grep`
24
+ is used as a fallback
25
+
26
+ Install:
27
+
28
+ ```
29
+ /plugin marketplace add populationgenomics/semantic-code-review
30
+ /plugin install scr
31
+ ```
32
+
33
+ The first time you run `/scr:review`, the plugin's `bin/scr` wrapper
34
+ creates a Python virtualenv under `$CLAUDE_PLUGIN_DATA/venv`, installs
35
+ the dependency closure with `pip install --require-hashes` (so any
36
+ tampered tarball fails the install instead of silently landing), then
37
+ installs `semantic-code-review` from PyPI at the version pinned in the
38
+ plugin's `pyproject.toml`. That published wheel carries the prebuilt
39
+ `viewer.js` bundle as package data, so the wrapper needs no Node, npm, or
40
+ build step — the git checkout is a thin launcher over a PyPI release. The
41
+ install is stamped (lockfile hash + version) and only re-runs when one
42
+ changes; subsequent invocations exec the cached venv and start
43
+ immediately.
44
+
45
+ ### The `/scr:review` slash command
46
+
47
+ ```
48
+ /scr:review HEAD~1 # diff working tree vs one commit back
49
+ /scr:review main..HEAD # committed-only diff of the current branch
50
+ /scr:review HEAD --spec SPEC.md # with a spec markdown as LLM ground truth
51
+ ```
52
+
53
+ The command opens a browser viewer. The left sidebar lists semantic
54
+ groups (LLM-curated clusters of related hunks); click one to filter
55
+ the visible hunks to that group, click "Show all" to clear. Hunks
56
+ that no group claimed get a subtle dotted-border tell so you can
57
+ spot them at a glance.
58
+
59
+ Leave inline comments by clicking a line number on either side of
60
+ the diff. When you click **Done**, the viewer closes, the command
61
+ returns the comments as structured markdown, and Claude Code walks
62
+ through them with you one at a time.
63
+
64
+ See `commands/review.md` for the full slash-command prompt.
65
+
66
+ ### LLM backend selection
67
+
68
+ `scr` picks a backend automatically:
69
+
70
+ - `ANTHROPIC_API_KEY` set → uses the Anthropic SDK directly (best
71
+ performance: prompt caching, native concurrency, structured tool
72
+ use).
73
+ - Otherwise, `claude` on `PATH` → falls back to a `claude -p`
74
+ subprocess with a stdio MCP server exposing the same repo-tools
75
+ the SDK path uses. No API key needed; works with any logged-in
76
+ Claude Code installation.
77
+ - Neither available → fails fast with a clear error.
78
+
79
+ Force a backend with `--backend <name>`. Run `scr config show` for
80
+ the registered names — builtins plus anything you've added under
81
+ `[backends.<name>]` in your config.
82
+
83
+ Both Gemini backends are opt-in only — never picked by `auto`.
84
+
85
+ - `--backend=gemini-api` uses Google's official `google-genai` SDK
86
+ directly. Auth ladder: `GOOGLE_CLOUD_PROJECT` set → Vertex AI
87
+ via Application Default Credentials; else `GEMINI_API_KEY` /
88
+ `GOOGLE_API_KEY` → AI Studio. Native concurrency, full structured
89
+ tool use, Gemini's implicit prompt caching surfaces as
90
+ `cache_read_input_tokens` in our usage stats. Best Gemini path
91
+ for production work.
92
+
93
+ ### Trying it without paid API access
94
+
95
+ `scr` ships builtin profiles for several free-tier providers. None
96
+ require an Anthropic or Google paid plan. Pick one, set the listed
97
+ env var, pass `--backend <name>`:
98
+
99
+ | `--backend` | Auth | Notes |
100
+ |---|---|---|
101
+ | `gemini-api` | `GEMINI_API_KEY` from [aistudio.google.com](https://aistudio.google.com) | Free tier with rate limits; hits the Google SDK directly. |
102
+ | `groq` | `GROQ_API_KEY` from [console.groq.com](https://console.groq.com) | Free tier, very fast inference, Llama 3.3 70B by default. |
103
+ | `github` | `GITHUB_TOKEN` (any GitHub account) | Free quota across multiple model families; default is `openai/gpt-4o-mini`. |
104
+ | `cerebras` | `CEREBRAS_API_KEY` from [cloud.cerebras.ai](https://cloud.cerebras.ai) | Free tier; pass `--model` (catalogue rotates). |
105
+ | `openrouter` | `OPENROUTER_API_KEY` from [openrouter.ai](https://openrouter.ai) | Mixed paid + free models; pass `--model` (e.g. `meta-llama/llama-3.3-70b-instruct:free`). |
106
+ | `mistral` | `MISTRAL_API_KEY` from [console.mistral.ai](https://console.mistral.ai) | La Plateforme free tier; default is `codestral-latest`. |
107
+ | `ollama` | none — runs against `localhost:11434` | Local llama.cpp/Ollama; pass `--model` to name something you've pulled (e.g. `qwen2.5-coder:14b`). |
108
+
109
+ The non-Anthropic / non-Google entries all reach the provider via
110
+ the OpenAI Chat Completions wire format (`type = "openai-compat"`).
111
+ Override any builtin's model — or add a new provider — with a
112
+ `[backends.<name>]` block in your config; see `scr config edit`.
113
+
114
+ If your bearer lives in a secret store rather than a long-lived env
115
+ var, use `api_key_command`: it runs a shell-free argv command and
116
+ reads the bearer from stdout. Built-in example: `--backend=github`
117
+ falls back to `gh auth token` when `GITHUB_TOKEN` isn't set. Custom
118
+ example, Anthropic key in a GCP Secret Manager entry:
119
+
120
+ ```toml
121
+ [backends.claude-api]
122
+ api_key_command = ["gcloud", "secrets", "versions", "access",
123
+ "latest", "--secret=anthropic-api-key"]
124
+ ```
125
+
126
+ The same hook works on `claude-api`, `gemini-api`, and any
127
+ `openai-compat` backend. For `gemini-api`, `GOOGLE_CLOUD_PROJECT`
128
+ takes precedence: when set, the Vertex/ADC path wins and
129
+ `api_key_command` is skipped.
130
+
131
+ Quality caveat: any non-frontier backend produces shallower hunk
132
+ intents and more spurious `refs[]`. The output is still useful as a
133
+ draft you skim, especially for small PRs, but it isn't a Claude /
134
+ Gemini Pro replacement.
135
+
136
+ ## Usage as a standalone CLI
137
+
138
+ Install from PyPI. The published wheel already contains the compiled
139
+ viewer bundle, so no Node is needed at runtime:
140
+
141
+ ```
142
+ uv tool install semantic-code-review
143
+ # or: pipx install semantic-code-review / pip install semantic-code-review
144
+ scr review HEAD~1..HEAD --spec SPEC.md
145
+ ```
146
+
147
+ From a source checkout (for development, or to pin the exact hashed
148
+ dependency set), build the viewer bundle yourself:
149
+
150
+ ```
151
+ pip install --require-hashes -r requirements.lock
152
+ pip install --no-deps --no-build-isolation .
153
+ npm ci --ignore-scripts && npm run build
154
+ scr review HEAD~1..HEAD --spec SPEC.md
155
+ ```
156
+
157
+ Subcommands:
158
+
159
+ - `scr review <ref-or-range> [--spec SPEC.md]` — local git diff,
160
+ runs LLM augment, opens viewer, prints reviewer comments as
161
+ markdown when you click Done.
162
+ - `scr pr <owner/repo> [<number>]` — same flow against a GitHub PR.
163
+ Omit the number to enumerate open PRs requesting your review;
164
+ on Done, posts the inline comments back to GitHub as a single
165
+ COMMENT-event review. Confirms before posting unless `--yes`.
166
+ - `scr fetch <pr-url>` — fetch a GitHub PR into a run directory.
167
+ - `scr augment <run-dir>` — run the LLM augmentation pass on a run
168
+ directory.
169
+ - `scr render <run-dir>` — render the HTML viewer from an augmented
170
+ run.
171
+ - `scr run <pr-url>` — fetch + augment + render (no viewer server).
172
+ - `scr show <run-dir>` — print the augmented diff to stdout.
173
+ - `scr strip <augmented.diff>` — write a plain unified diff to stdout.
174
+ - `scr lint <augmented.diff>` — validate the augmented-diff format.
175
+ - `scr runs path` — print the runs root resolved for the current cwd.
176
+
177
+ `scr pr` reuses everything `scr review` does (same fetch, augment,
178
+ viewer, server, comment store) plus a thin GitHub-side helper that
179
+ groups the inline comments into one review object via `gh api`. The
180
+ `gh` CLI must be on `PATH` and authenticated.
181
+
182
+ ### Where run artefacts live
183
+
184
+ `scr` writes per-review state — a `meta.json`, the raw and augmented
185
+ diffs, and `base/` / `head/` worktrees so the LLM (and the viewer)
186
+ can read pre- and post-change files — to a per-repo directory under
187
+ your XDG cache:
188
+
189
+ ```
190
+ ~/.cache/scr/runs/<sha256-of-git-common-dir>/<run-slug>/
191
+ ```
192
+
193
+ Worktrees of the same repo share the directory; different repos get
194
+ different ones. Runs live outside the repo on purpose — a `.scr/` at
195
+ the repo root is a deploy-tool footgun (gcloud, docker, tar tend to
196
+ upload it unless every project remembers to ignore it), and the
197
+ worktrees inside contain real git history that no one wants to
198
+ upload by accident.
199
+
200
+ Override with `--runs-root <path>` on any command that creates runs
201
+ (`review`, `pr`, `fetch`, `run`).
202
+
203
+ ## Development
204
+
205
+ ```
206
+ python3 -m venv .venv
207
+ .venv/bin/pip install --require-hashes -r build-requirements.lock
208
+ .venv/bin/pip install --require-hashes -r requirements-dev.lock
209
+ .venv/bin/pip install --no-deps --no-build-isolation -e .
210
+
211
+ npm ci --ignore-scripts
212
+ npm run build # tsc --noEmit typecheck, then esbuild bundle → semantic_code_review/viewer/assets/viewer.js
213
+ npm run test:js # vitest
214
+ .venv/bin/python -m pytest
215
+ ```
216
+
217
+ `tests/conftest.py` autobuilds the TypeScript module if it's missing
218
+ when pytest starts, so `python -m pytest` Just Works on a fresh
219
+ checkout (provided Node is available).
220
+
221
+ ## Releasing
222
+
223
+ Releases publish to [PyPI](https://pypi.org/project/semantic-code-review/)
224
+ from GitHub Actions via Trusted Publishing (OIDC) — no API tokens, no
225
+ cloud credentials. To cut a release:
226
+
227
+ 1. Bump `version` in `pyproject.toml` (and `.claude-plugin/plugin.json`
228
+ to match).
229
+ 2. Commit, then publish a GitHub Release whose tag is `vX.Y.Z` matching
230
+ that version. `.github/workflows/release.yml` fires on the published
231
+ release: it compiles the viewer bundle, builds the wheel + sdist with
232
+ `uv build`, and uploads to PyPI. A guard fails the run loudly if the
233
+ tag and `pyproject.toml` version disagree.
234
+
235
+ The plugin installs `semantic-code-review==<pyproject version>` from
236
+ PyPI, so the version on the default branch must always be one that is
237
+ published (or being published) there — bump it only as part of cutting a
238
+ release. A plugin update that lands a version PyPI doesn't yet carry will
239
+ fail its first-run install until the release finishes.
240
+
241
+ One-time setup (recorded here for a fresh fork): register a
242
+ [Trusted Publisher](https://docs.pypi.org/trusted-publishers/) on the
243
+ PyPI project pointing at this repository, workflow filename
244
+ `release.yml`, and environment `pypi`; and create a `pypi` environment
245
+ in the repo's GitHub settings.
246
+
247
+ ## What's where
248
+
249
+ - `semantic_code_review/augment/` — overview + per-hunk LLM pipeline,
250
+ prompts, schemas, MCP tool wrapper.
251
+ - `semantic_code_review/viewer/` — Python side: `build_json.py`,
252
+ `hunk_layout.py`. Frontend assets in `viewer/assets/`: eight
253
+ TypeScript modules (boot/render/sidebar/annotations/comments/
254
+ folds/progress/sse) bundled by esbuild into a single
255
+ `viewer.js`, `viewer.css`, the static `index.html` served by
256
+ the review server, and vendored `highlight.js` under
257
+ `assets/vendor/`.
258
+ - `semantic_code_review/review/` — local HTTP server that
259
+ back-channels reviewer comments to the calling process, the
260
+ shared `serve_review` helper used by both `scr review` and
261
+ `scr pr`, and `github.py` for the GitHub-PR round-trip via
262
+ `gh api`.
263
+ - `commands/review.md` — the Claude Code slash-command prompt.
264
+ - `bin/scr` — bootstrap wrapper; preflights deps, maintains the
265
+ Python venv, installs `scr` from PyPI at the pinned version, execs
266
+ the real `scr`.
267
+ - `TREE_SITTER.md` — design notes on a possible future structural
268
+ pass (symbol grouping, AST-driven fold regions, semantic hunk
269
+ splitting). Speculative; nothing in tree depends on it.
270
+
271
+ ## Supply-chain hygiene
272
+
273
+ Every external dependency is pinned by exact version and SHA-256
274
+ hash. The `bin/scr` bootstrap installs with
275
+ `pip install --require-hashes` and `npm ci`, so any on-disk artifact
276
+ whose hash doesn't match the lockfile fails the install rather than
277
+ silently landing.
278
+
279
+ Lockfiles (all committed):
280
+
281
+ - `build-requirements.lock` — PEP 517 build backend (`setuptools`,
282
+ `wheel`).
283
+ - `requirements.lock` — runtime Python deps (`anthropic`,
284
+ `pydantic`, `typer`, …).
285
+ - `requirements-dev.lock` — runtime + `pytest` + `pytest-asyncio`.
286
+ - `package-lock.json` — Node toolchain (`typescript`, `vitest`,
287
+ `@playwright/test`, `jsdom`, `@types/node`).
288
+
289
+ Frontend assets (`highlight.js` + light/dark stylesheets) are
290
+ vendored under `semantic_code_review/viewer/assets/vendor/` at a
291
+ pinned upstream version with the BSD-3-Clause LICENSE file alongside
292
+ them. The viewer HTML inlines those bytes — never loads anything
293
+ from a CDN at runtime. See `vendor/VENDOR.md` for provenance and
294
+ hashes; `vendor/refresh.sh` re-downloads at the pinned version and
295
+ fails loudly if any SHA-256 doesn't match.
296
+
297
+ Refreshing:
298
+
299
+ ```
300
+ # Python
301
+ uv pip compile pyproject.toml -o requirements.lock --generate-hashes
302
+ uv pip compile pyproject.toml --extra dev -o requirements-dev.lock --generate-hashes
303
+ printf 'setuptools>=68\nwheel\n' | uv pip compile - --generate-hashes -o build-requirements.lock
304
+
305
+ # Node toolchain
306
+ npm install # commits an updated package-lock.json with new integrity hashes
307
+
308
+ # Frontend (edit version constants in refresh.sh first if bumping)
309
+ ./semantic_code_review/viewer/assets/vendor/refresh.sh
310
+ ```