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.
- semantic_code_review-0.24.2/LICENSE +21 -0
- semantic_code_review-0.24.2/PKG-INFO +348 -0
- semantic_code_review-0.24.2/README.md +310 -0
- semantic_code_review-0.24.2/pyproject.toml +159 -0
- semantic_code_review-0.24.2/semantic_code_review/__init__.py +5 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/__init__.py +3 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/agents.py +95 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/console.py +440 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/extra_review.py +237 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/fold_summary.py +447 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/hunks.py +264 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/mcp_server.py +156 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/overview.py +233 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/pass_.py +171 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/pipeline.py +571 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/progress.py +223 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/prompts.py +93 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/schemas.py +408 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/tools.py +475 -0
- semantic_code_review-0.24.2/semantic_code_review/augment/trace_adapter.py +369 -0
- semantic_code_review-0.24.2/semantic_code_review/backends/__init__.py +95 -0
- semantic_code_review-0.24.2/semantic_code_review/backends/_cli_driver.py +571 -0
- semantic_code_review-0.24.2/semantic_code_review/backends/anthropic_sdk.py +56 -0
- semantic_code_review-0.24.2/semantic_code_review/backends/base.py +104 -0
- semantic_code_review-0.24.2/semantic_code_review/backends/claude_cli.py +421 -0
- semantic_code_review-0.24.2/semantic_code_review/backends/google_sdk.py +73 -0
- semantic_code_review-0.24.2/semantic_code_review/backends/openai_compat.py +42 -0
- semantic_code_review-0.24.2/semantic_code_review/cache/__init__.py +3 -0
- semantic_code_review-0.24.2/semantic_code_review/cache/store.py +87 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/__init__.py +70 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/_shared.py +157 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/augment.py +74 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/config_cmd.py +266 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/fetch.py +33 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/lint.py +27 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/pr.py +98 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/review.py +104 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/runs_cmd.py +17 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/show.py +19 -0
- semantic_code_review-0.24.2/semantic_code_review/cli/strip.py +20 -0
- semantic_code_review-0.24.2/semantic_code_review/config.py +563 -0
- semantic_code_review-0.24.2/semantic_code_review/config_template.py +154 -0
- semantic_code_review-0.24.2/semantic_code_review/fetch/__init__.py +61 -0
- semantic_code_review-0.24.2/semantic_code_review/fetch/anchor.py +244 -0
- semantic_code_review-0.24.2/semantic_code_review/fetch/github.py +229 -0
- semantic_code_review-0.24.2/semantic_code_review/fetch/github_comments.py +404 -0
- semantic_code_review-0.24.2/semantic_code_review/fetch/local.py +443 -0
- semantic_code_review-0.24.2/semantic_code_review/fetch/run_source.py +70 -0
- semantic_code_review-0.24.2/semantic_code_review/format/__init__.py +3 -0
- semantic_code_review-0.24.2/semantic_code_review/format/emit.py +163 -0
- semantic_code_review-0.24.2/semantic_code_review/format/lint.py +74 -0
- semantic_code_review-0.24.2/semantic_code_review/format/parse.py +574 -0
- semantic_code_review-0.24.2/semantic_code_review/format/sidecar.py +19 -0
- semantic_code_review-0.24.2/semantic_code_review/format/strip.py +20 -0
- semantic_code_review-0.24.2/semantic_code_review/git_ops.py +252 -0
- semantic_code_review-0.24.2/semantic_code_review/paths.py +61 -0
- semantic_code_review-0.24.2/semantic_code_review/review/__init__.py +3 -0
- semantic_code_review-0.24.2/semantic_code_review/review/comments.py +176 -0
- semantic_code_review-0.24.2/semantic_code_review/review/github.py +284 -0
- semantic_code_review-0.24.2/semantic_code_review/review/github_graphql.py +433 -0
- semantic_code_review-0.24.2/semantic_code_review/review/pr_flow.py +299 -0
- semantic_code_review-0.24.2/semantic_code_review/review/runner.py +407 -0
- semantic_code_review-0.24.2/semantic_code_review/review/server.py +1043 -0
- semantic_code_review-0.24.2/semantic_code_review/structural/__init__.py +41 -0
- semantic_code_review-0.24.2/semantic_code_review/structural/diff.py +102 -0
- semantic_code_review-0.24.2/semantic_code_review/structural/parse.py +330 -0
- semantic_code_review-0.24.2/semantic_code_review/structural/symbols.py +43 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/__init__.py +3 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/annotations.ts +547 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/boot.ts +273 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/comment_store.ts +121 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/comments.ts +624 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/console.ts +426 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/console_render.ts +213 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/console_selection.ts +102 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/data_store.ts +156 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/file_rows.ts +49 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/folds.ts +560 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/index.html +62 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/post_modal.ts +383 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/progress.ts +138 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/render.ts +937 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/sidebar.ts +429 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/sse.ts +78 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/text_highlight.ts +215 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/types.d.ts +388 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/LICENSE +29 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/VENDOR.md +55 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/github-dark.min.css +10 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/github.min.css +10 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/highlight.min.js +1244 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/mermaid.LICENSE +21 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/mermaid.min.js +3587 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/vendor/refresh.sh +65 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/viewer.css +1202 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/assets/viewer.js +10588 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/build_json.py +546 -0
- semantic_code_review-0.24.2/semantic_code_review/viewer/hunk_layout.py +471 -0
- semantic_code_review-0.24.2/semantic_code_review.egg-info/PKG-INFO +348 -0
- semantic_code_review-0.24.2/semantic_code_review.egg-info/SOURCES.txt +129 -0
- semantic_code_review-0.24.2/semantic_code_review.egg-info/dependency_links.txt +1 -0
- semantic_code_review-0.24.2/semantic_code_review.egg-info/entry_points.txt +2 -0
- semantic_code_review-0.24.2/semantic_code_review.egg-info/requires.txt +16 -0
- semantic_code_review-0.24.2/semantic_code_review.egg-info/top_level.txt +1 -0
- semantic_code_review-0.24.2/setup.cfg +4 -0
- semantic_code_review-0.24.2/tests/test_augment_pipeline.py +497 -0
- semantic_code_review-0.24.2/tests/test_backend_select.py +173 -0
- semantic_code_review-0.24.2/tests/test_cache_keys.py +65 -0
- semantic_code_review-0.24.2/tests/test_cli_smoke.py +139 -0
- semantic_code_review-0.24.2/tests/test_config.py +623 -0
- semantic_code_review-0.24.2/tests/test_config_template.py +94 -0
- semantic_code_review-0.24.2/tests/test_console.py +459 -0
- semantic_code_review-0.24.2/tests/test_fold_summary_apply.py +227 -0
- semantic_code_review-0.24.2/tests/test_format_roundtrip.py +184 -0
- semantic_code_review-0.24.2/tests/test_github_graphql_post.py +468 -0
- semantic_code_review-0.24.2/tests/test_github_pr_review.py +252 -0
- semantic_code_review-0.24.2/tests/test_hunk_layout.py +297 -0
- semantic_code_review-0.24.2/tests/test_mcp_server.py +123 -0
- semantic_code_review-0.24.2/tests/test_overview_groups.py +152 -0
- semantic_code_review-0.24.2/tests/test_overview_seed.py +105 -0
- semantic_code_review-0.24.2/tests/test_parse.py +105 -0
- semantic_code_review-0.24.2/tests/test_progress_meter.py +102 -0
- semantic_code_review-0.24.2/tests/test_pydantic_ai_agents.py +129 -0
- semantic_code_review-0.24.2/tests/test_repo_tool_fns.py +257 -0
- semantic_code_review-0.24.2/tests/test_review_server.py +1059 -0
- semantic_code_review-0.24.2/tests/test_schema_unification.py +77 -0
- semantic_code_review-0.24.2/tests/test_segments.py +175 -0
- semantic_code_review-0.24.2/tests/test_structural.py +331 -0
- semantic_code_review-0.24.2/tests/test_tools.py +121 -0
- semantic_code_review-0.24.2/tests/test_trace_adapter.py +331 -0
- 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
|
+
```
|