saga-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- saga_cli-0.1.0/.github/workflows/ci.yml +38 -0
- saga_cli-0.1.0/.gitignore +16 -0
- saga_cli-0.1.0/CONTRIBUTING.md +46 -0
- saga_cli-0.1.0/LICENSE +21 -0
- saga_cli-0.1.0/PKG-INFO +158 -0
- saga_cli-0.1.0/README.md +131 -0
- saga_cli-0.1.0/RELEASING.md +34 -0
- saga_cli-0.1.0/docs/example.html +956 -0
- saga_cli-0.1.0/pyproject.toml +71 -0
- saga_cli-0.1.0/saga/__init__.py +0 -0
- saga_cli-0.1.0/saga/__main__.py +4 -0
- saga_cli-0.1.0/saga/assets/base.css +41 -0
- saga_cli-0.1.0/saga/assets/saga.css +224 -0
- saga_cli-0.1.0/saga/assets/saga.js +459 -0
- saga_cli-0.1.0/saga/assets/tokens.css +141 -0
- saga_cli-0.1.0/saga/cli.py +100 -0
- saga_cli-0.1.0/saga/comments.py +258 -0
- saga_cli-0.1.0/saga/diff.py +79 -0
- saga_cli-0.1.0/saga/generate.py +182 -0
- saga_cli-0.1.0/saga/model.py +253 -0
- saga_cli-0.1.0/saga/prompts/saga.md +50 -0
- saga_cli-0.1.0/saga/render.py +144 -0
- saga_cli-0.1.0/skills/generate_saga/SKILL.md +50 -0
- saga_cli-0.1.0/skills/read_saga_comments/SKILL.md +62 -0
- saga_cli-0.1.0/tests/cassettes/generate_anthropic.yaml +168 -0
- saga_cli-0.1.0/tests/conftest.py +138 -0
- saga_cli-0.1.0/tests/test_cli.py +161 -0
- saga_cli-0.1.0/tests/test_comments.py +145 -0
- saga_cli-0.1.0/tests/test_diff.py +95 -0
- saga_cli-0.1.0/tests/test_generate.py +153 -0
- saga_cli-0.1.0/tests/test_model.py +186 -0
- saga_cli-0.1.0/tests/test_render.py +143 -0
- saga_cli-0.1.0/uv.lock +1537 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- name: Install uv
|
|
14
|
+
uses: astral-sh/setup-uv@v5
|
|
15
|
+
- name: Install dev tools
|
|
16
|
+
run: uv sync --group dev
|
|
17
|
+
- name: Ruff lint
|
|
18
|
+
run: uv run ruff check .
|
|
19
|
+
- name: Ruff format
|
|
20
|
+
run: uv run ruff format --check .
|
|
21
|
+
- name: Type check
|
|
22
|
+
run: uv run ty check .
|
|
23
|
+
|
|
24
|
+
test:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
strategy:
|
|
27
|
+
matrix:
|
|
28
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- name: Install uv
|
|
32
|
+
uses: astral-sh/setup-uv@v5
|
|
33
|
+
with:
|
|
34
|
+
python-version: ${{ matrix.python-version }}
|
|
35
|
+
- name: Install
|
|
36
|
+
run: uv sync --group dev
|
|
37
|
+
- name: Run tests
|
|
38
|
+
run: uv run python -m pytest -q
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in Saga.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
git clone https://github.com/JakeBeresford/saga
|
|
9
|
+
cd saga
|
|
10
|
+
uv pip install -e . pytest # or: pip install -e . pytest
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run the tests:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
python -m pytest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Lint, format, and type-check (install the dev tools with `uv sync --group dev`):
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
uv run ruff check . # lint
|
|
23
|
+
uv run ruff format . # auto-format
|
|
24
|
+
uv run ty check . # type check
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
To try the CLI against a real repo while developing, install it as an editable
|
|
28
|
+
tool and run it from inside any git checkout:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
uv tool install --editable .
|
|
32
|
+
saga --base main --head my-feature
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Pull requests
|
|
36
|
+
|
|
37
|
+
- Keep changes focused and match the existing style.
|
|
38
|
+
- Add or update tests for any behavior change — the core model logic in
|
|
39
|
+
`saga/model.py` is unit-tested in `tests/test_model.py`.
|
|
40
|
+
- Make sure `python -m pytest` passes and `ruff`/`ty` are clean before opening a
|
|
41
|
+
PR. CI runs the suite on Python 3.11–3.13 plus a lint/format/type-check job.
|
|
42
|
+
|
|
43
|
+
## Reporting issues
|
|
44
|
+
|
|
45
|
+
Open an issue at https://github.com/JakeBeresford/saga/issues with steps to
|
|
46
|
+
reproduce, the command you ran, and what you expected to happen.
|
saga_cli-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jake Beresford
|
|
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.
|
saga_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: saga-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate a self-contained static HTML saga of a git diff — a chapter-by-chapter guided tour of a change.
|
|
5
|
+
Project-URL: Homepage, https://github.com/JakeBeresford/saga
|
|
6
|
+
Project-URL: Repository, https://github.com/JakeBeresford/saga
|
|
7
|
+
Project-URL: Issues, https://github.com/JakeBeresford/saga/issues
|
|
8
|
+
Author: Jake Beresford
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: code-review,diff,documentation,git,html,llm
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
20
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: anthropic
|
|
23
|
+
Requires-Dist: instructor
|
|
24
|
+
Requires-Dist: openai
|
|
25
|
+
Requires-Dist: typer>=0.26.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Saga
|
|
29
|
+
|
|
30
|
+
Generate a **chapter-by-chapter guided tour** of a code change as a single,
|
|
31
|
+
self-contained static HTML page, a _saga_ of your diff. It partitions a diff into
|
|
32
|
+
ordered chapters that tell one coherent story, each with a plain-language narration
|
|
33
|
+
and just the hunks that belong to it. Large PRs become easy to review without
|
|
34
|
+
losing the thread.
|
|
35
|
+
|
|
36
|
+
The output is one HTML file with everything inlined (diff2html, syntax highlighting,
|
|
37
|
+
the data). Open it offline, email it, commit it, or drop it on any static host.
|
|
38
|
+
|
|
39
|
+
[**See an example saga**](https://jakeberesford.github.io/saga/example.html).
|
|
40
|
+
|
|
41
|
+
## Requirements
|
|
42
|
+
|
|
43
|
+
- Python 3.11+
|
|
44
|
+
- `git`
|
|
45
|
+
- An API key for your chosen provider, in the standard environment variable:
|
|
46
|
+
`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or `OPENROUTER_API_KEY`
|
|
47
|
+
|
|
48
|
+
Generation is one structured LLM call made through [`instructor`](https://python.useinstructor.com).
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
Install once and the `saga` command is available from any repo:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
uv tool install saga-cli # recommended
|
|
56
|
+
# or
|
|
57
|
+
pipx install saga-cli
|
|
58
|
+
# or, into the current environment
|
|
59
|
+
pip install saga-cli
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Installing from a local checkout instead? Point the installer at this directory,
|
|
63
|
+
e.g. `uv tool install /path/to/saga`. To upgrade: `uv tool install --force saga-cli`.
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
From inside the repo you want to review:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
saga --base main --head my-feature -o saga.html --open
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Run it from anywhere with `--repo`:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
saga --repo ~/src/some-project --base main --head my-feature -o out.html
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Flag | Default | Meaning |
|
|
80
|
+
| ---------------------- | --------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
81
|
+
| `--base` | `main` | Base ref to diff against |
|
|
82
|
+
| `--head` | current branch | Head ref to walk through |
|
|
83
|
+
| `--intent PATH` | — | Optional plan/spec describing the change's intent, for plan-aware narration and deviation flagging |
|
|
84
|
+
| `--model` | `anthropic/claude-opus-4-8` | `provider/model` string (see [Providers](#providers)); also `$SAGA_MODEL` |
|
|
85
|
+
| `-o, --output` | `saga.html` | Output file |
|
|
86
|
+
| `--repo` | cwd | A path inside the target git repo |
|
|
87
|
+
| `--open` / `--no-open` | on | Open the result in a browser (on by default; `--no-open` to disable) |
|
|
88
|
+
|
|
89
|
+
## Providers
|
|
90
|
+
|
|
91
|
+
The model is a single `provider/model` string, dispatched through `instructor`.
|
|
92
|
+
Choose it with `--model` or the `SAGA_MODEL` environment variable, and set
|
|
93
|
+
the matching API key:
|
|
94
|
+
|
|
95
|
+
| Provider | `--model` example | API key env var |
|
|
96
|
+
| ---------- | ---------------------------------------- | -------------------- |
|
|
97
|
+
| Anthropic | `anthropic/claude-opus-4-8` | `ANTHROPIC_API_KEY` |
|
|
98
|
+
| OpenAI | `openai/gpt-4o` | `OPENAI_API_KEY` |
|
|
99
|
+
| OpenRouter | `openrouter/anthropic/claude-3.5-sonnet` | `OPENROUTER_API_KEY` |
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
export SAGA_MODEL=openai/gpt-4o
|
|
103
|
+
export OPENAI_API_KEY=sk-…
|
|
104
|
+
saga --base main --head my-feature -o saga.html
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## As a Claude Code skill
|
|
108
|
+
|
|
109
|
+
The `skills/` directory contains two Claude Code skills. To install both:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
cp -R "$(pwd)/skills" ~/.claude/skills/saga
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
- **`saga`** — say **"/saga"** (or "give me a walkthrough of this branch") to generate a
|
|
116
|
+
saga. It resolves the base/head refs and runs the tool for you.
|
|
117
|
+
- **`saga-comments`** — say **"/saga-comments"** (or "address the saga comments") to read an
|
|
118
|
+
exported `saga.comments.json` and act on the reviewer's feedback in code.
|
|
119
|
+
|
|
120
|
+
## Reviewing: comments
|
|
121
|
+
|
|
122
|
+
The saga page is also a lightweight review surface. Open `saga.html` and leave three
|
|
123
|
+
kinds of comments — **inline** (click a line's number in any chapter's diff), **per-file**
|
|
124
|
+
(the "💬 File comment" control in each file header), and one **overall** review comment
|
|
125
|
+
(the box at the top of the Chapters list). Comments are drafted in your browser's
|
|
126
|
+
`localStorage`, so they survive a reload.
|
|
127
|
+
|
|
128
|
+
When you're done, click **Export comments** to download a `saga.comments.json` sidecar next
|
|
129
|
+
to the HTML. (Export is disabled in the [hosted example](https://jakeberesford.github.io/saga/example.html)
|
|
130
|
+
so it never writes a file — every other part of the review UX works.) Two commands consume it:
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
# Post everything as a single PENDING review on the PR (you submit it on GitHub).
|
|
134
|
+
saga comments push --comments saga.comments.json
|
|
135
|
+
|
|
136
|
+
# Emit the comments as JSON on stdout — for a coding agent to act on.
|
|
137
|
+
saga comments read --comments saga.comments.json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`push` uses the `gh` CLI: it finds the open PR for the sidecar's branch and creates one
|
|
141
|
+
pending review (inline → line comments, per-file → a note anchored to the file's first
|
|
142
|
+
changed line, overall → the review body). Nothing is submitted until you review and submit
|
|
143
|
+
it on GitHub. Requires the [`gh`](https://cli.github.com) CLI, authenticated.
|
|
144
|
+
|
|
145
|
+
## How it works
|
|
146
|
+
|
|
147
|
+
1. `diff.py` computes `git diff base...head` (no checkout) and the commit list.
|
|
148
|
+
2. `model.py` splits the diff into stable-id hunks (`h0, h1, …`).
|
|
149
|
+
3. `generate.py` sends the labeled diff + commits (+ optional intent) to the chosen
|
|
150
|
+
model via `instructor`, which returns chapters as schema-validated JSON. Coverage
|
|
151
|
+
is **re-validated in code** — every hunk must belong to a chapter or generation fails.
|
|
152
|
+
4. `render.py` reconstructs each chapter's diff and inlines everything into one
|
|
153
|
+
self-contained HTML file.
|
|
154
|
+
|
|
155
|
+
## Not included (yet)
|
|
156
|
+
|
|
157
|
+
- Support for Local LLMs via ollama / LM Studio
|
|
158
|
+
- A GitHub Action to auto-generate saga on PRs.
|
saga_cli-0.1.0/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Saga
|
|
2
|
+
|
|
3
|
+
Generate a **chapter-by-chapter guided tour** of a code change as a single,
|
|
4
|
+
self-contained static HTML page, a _saga_ of your diff. It partitions a diff into
|
|
5
|
+
ordered chapters that tell one coherent story, each with a plain-language narration
|
|
6
|
+
and just the hunks that belong to it. Large PRs become easy to review without
|
|
7
|
+
losing the thread.
|
|
8
|
+
|
|
9
|
+
The output is one HTML file with everything inlined (diff2html, syntax highlighting,
|
|
10
|
+
the data). Open it offline, email it, commit it, or drop it on any static host.
|
|
11
|
+
|
|
12
|
+
[**See an example saga**](https://jakeberesford.github.io/saga/example.html).
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Python 3.11+
|
|
17
|
+
- `git`
|
|
18
|
+
- An API key for your chosen provider, in the standard environment variable:
|
|
19
|
+
`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or `OPENROUTER_API_KEY`
|
|
20
|
+
|
|
21
|
+
Generation is one structured LLM call made through [`instructor`](https://python.useinstructor.com).
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Install once and the `saga` command is available from any repo:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
uv tool install saga-cli # recommended
|
|
29
|
+
# or
|
|
30
|
+
pipx install saga-cli
|
|
31
|
+
# or, into the current environment
|
|
32
|
+
pip install saga-cli
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Installing from a local checkout instead? Point the installer at this directory,
|
|
36
|
+
e.g. `uv tool install /path/to/saga`. To upgrade: `uv tool install --force saga-cli`.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
From inside the repo you want to review:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
saga --base main --head my-feature -o saga.html --open
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Run it from anywhere with `--repo`:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
saga --repo ~/src/some-project --base main --head my-feature -o out.html
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Flag | Default | Meaning |
|
|
53
|
+
| ---------------------- | --------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
54
|
+
| `--base` | `main` | Base ref to diff against |
|
|
55
|
+
| `--head` | current branch | Head ref to walk through |
|
|
56
|
+
| `--intent PATH` | — | Optional plan/spec describing the change's intent, for plan-aware narration and deviation flagging |
|
|
57
|
+
| `--model` | `anthropic/claude-opus-4-8` | `provider/model` string (see [Providers](#providers)); also `$SAGA_MODEL` |
|
|
58
|
+
| `-o, --output` | `saga.html` | Output file |
|
|
59
|
+
| `--repo` | cwd | A path inside the target git repo |
|
|
60
|
+
| `--open` / `--no-open` | on | Open the result in a browser (on by default; `--no-open` to disable) |
|
|
61
|
+
|
|
62
|
+
## Providers
|
|
63
|
+
|
|
64
|
+
The model is a single `provider/model` string, dispatched through `instructor`.
|
|
65
|
+
Choose it with `--model` or the `SAGA_MODEL` environment variable, and set
|
|
66
|
+
the matching API key:
|
|
67
|
+
|
|
68
|
+
| Provider | `--model` example | API key env var |
|
|
69
|
+
| ---------- | ---------------------------------------- | -------------------- |
|
|
70
|
+
| Anthropic | `anthropic/claude-opus-4-8` | `ANTHROPIC_API_KEY` |
|
|
71
|
+
| OpenAI | `openai/gpt-4o` | `OPENAI_API_KEY` |
|
|
72
|
+
| OpenRouter | `openrouter/anthropic/claude-3.5-sonnet` | `OPENROUTER_API_KEY` |
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
export SAGA_MODEL=openai/gpt-4o
|
|
76
|
+
export OPENAI_API_KEY=sk-…
|
|
77
|
+
saga --base main --head my-feature -o saga.html
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## As a Claude Code skill
|
|
81
|
+
|
|
82
|
+
The `skills/` directory contains two Claude Code skills. To install both:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
cp -R "$(pwd)/skills" ~/.claude/skills/saga
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- **`saga`** — say **"/saga"** (or "give me a walkthrough of this branch") to generate a
|
|
89
|
+
saga. It resolves the base/head refs and runs the tool for you.
|
|
90
|
+
- **`saga-comments`** — say **"/saga-comments"** (or "address the saga comments") to read an
|
|
91
|
+
exported `saga.comments.json` and act on the reviewer's feedback in code.
|
|
92
|
+
|
|
93
|
+
## Reviewing: comments
|
|
94
|
+
|
|
95
|
+
The saga page is also a lightweight review surface. Open `saga.html` and leave three
|
|
96
|
+
kinds of comments — **inline** (click a line's number in any chapter's diff), **per-file**
|
|
97
|
+
(the "💬 File comment" control in each file header), and one **overall** review comment
|
|
98
|
+
(the box at the top of the Chapters list). Comments are drafted in your browser's
|
|
99
|
+
`localStorage`, so they survive a reload.
|
|
100
|
+
|
|
101
|
+
When you're done, click **Export comments** to download a `saga.comments.json` sidecar next
|
|
102
|
+
to the HTML. (Export is disabled in the [hosted example](https://jakeberesford.github.io/saga/example.html)
|
|
103
|
+
so it never writes a file — every other part of the review UX works.) Two commands consume it:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
# Post everything as a single PENDING review on the PR (you submit it on GitHub).
|
|
107
|
+
saga comments push --comments saga.comments.json
|
|
108
|
+
|
|
109
|
+
# Emit the comments as JSON on stdout — for a coding agent to act on.
|
|
110
|
+
saga comments read --comments saga.comments.json
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`push` uses the `gh` CLI: it finds the open PR for the sidecar's branch and creates one
|
|
114
|
+
pending review (inline → line comments, per-file → a note anchored to the file's first
|
|
115
|
+
changed line, overall → the review body). Nothing is submitted until you review and submit
|
|
116
|
+
it on GitHub. Requires the [`gh`](https://cli.github.com) CLI, authenticated.
|
|
117
|
+
|
|
118
|
+
## How it works
|
|
119
|
+
|
|
120
|
+
1. `diff.py` computes `git diff base...head` (no checkout) and the commit list.
|
|
121
|
+
2. `model.py` splits the diff into stable-id hunks (`h0, h1, …`).
|
|
122
|
+
3. `generate.py` sends the labeled diff + commits (+ optional intent) to the chosen
|
|
123
|
+
model via `instructor`, which returns chapters as schema-validated JSON. Coverage
|
|
124
|
+
is **re-validated in code** — every hunk must belong to a chapter or generation fails.
|
|
125
|
+
4. `render.py` reconstructs each chapter's diff and inlines everything into one
|
|
126
|
+
self-contained HTML file.
|
|
127
|
+
|
|
128
|
+
## Not included (yet)
|
|
129
|
+
|
|
130
|
+
- Support for Local LLMs via ollama / LM Studio
|
|
131
|
+
- A GitHub Action to auto-generate saga on PRs.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
Releases are published to PyPI **manually, by the sole maintainer**. There is
|
|
4
|
+
no CI publish workflow by design — nothing but a local machine holding the
|
|
5
|
+
maintainer's token can push a release.
|
|
6
|
+
|
|
7
|
+
## One-time setup
|
|
8
|
+
|
|
9
|
+
1. On [PyPI](https://pypi.org): create the account, enable **2FA**, and remain
|
|
10
|
+
the **sole Owner** of `saga-cli`. Do not add other Owners or Maintainers.
|
|
11
|
+
2. For the **first** upload the project does not exist yet, so create an
|
|
12
|
+
**account-scoped** API token, publish once (below), then immediately create a
|
|
13
|
+
**project-scoped** token for `saga-cli` and delete the account-scoped one.
|
|
14
|
+
3. Store the token locally only — e.g. `~/.pypirc`, or export it per release:
|
|
15
|
+
```sh
|
|
16
|
+
export UV_PUBLISH_TOKEN=pypi-…
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Cutting a release
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
# 1. Bump the version in pyproject.toml, commit, and tag
|
|
23
|
+
git tag v0.1.0 && git push origin main --tags
|
|
24
|
+
|
|
25
|
+
# 2. Build clean and publish
|
|
26
|
+
rm -rf dist
|
|
27
|
+
uv build
|
|
28
|
+
uv publish # uses UV_PUBLISH_TOKEN, or ~/.pypirc
|
|
29
|
+
|
|
30
|
+
# 3. Cut a matching GitHub Release for the tag (changelog / notes)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Verify the upload with `pip index versions saga-cli` or by visiting the PyPI
|
|
34
|
+
project page.
|