claude-code-generator 0.1.0__py3-none-any.whl
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.
- claude_code_generator-0.1.0.dist-info/METADATA +176 -0
- claude_code_generator-0.1.0.dist-info/RECORD +49 -0
- claude_code_generator-0.1.0.dist-info/WHEEL +5 -0
- claude_code_generator-0.1.0.dist-info/entry_points.txt +2 -0
- claude_code_generator-0.1.0.dist-info/licenses/LICENSE +21 -0
- claude_code_generator-0.1.0.dist-info/top_level.txt +1 -0
- code_generator/__init__.py +3 -0
- code_generator/agents.py +177 -0
- code_generator/cli.py +49 -0
- code_generator/commands/__init__.py +1 -0
- code_generator/commands/generate.py +252 -0
- code_generator/commands/init.py +72 -0
- code_generator/commands/review.py +117 -0
- code_generator/commands/status.py +83 -0
- code_generator/env.py +55 -0
- code_generator/gh.py +331 -0
- code_generator/logging_setup.py +73 -0
- code_generator/orchestrator/__init__.py +4 -0
- code_generator/orchestrator/cycle_loop.py +371 -0
- code_generator/orchestrator/phase0_complexity.py +159 -0
- code_generator/orchestrator/phase1_plan.py +170 -0
- code_generator/orchestrator/phase2_review.py +126 -0
- code_generator/orchestrator/phase3_4_implement.py +164 -0
- code_generator/orchestrator/phase5_closure.py +154 -0
- code_generator/orchestrator/phase6_test.py +98 -0
- code_generator/orchestrator/phase7_commit.py +167 -0
- code_generator/prompts/__init__.py +86 -0
- code_generator/prompts/prompt-phase-0-complexity.md +85 -0
- code_generator/prompts/prompt-phase-1-planning.md +209 -0
- code_generator/prompts/prompt-phase-2-issue-review.md +84 -0
- code_generator/prompts/prompt-phase-3-implementation.md +191 -0
- code_generator/prompts/prompt-phase-5-final-review.md +135 -0
- code_generator/prompts/prompt-phase-6-test.md +102 -0
- code_generator/prompts/prompt-phase-7-commit.md +103 -0
- code_generator/prompts/prompt-review.md +124 -0
- code_generator/runner/__init__.py +26 -0
- code_generator/runner/rate_limit.py +113 -0
- code_generator/runner/retry.py +165 -0
- code_generator/runner/sdk_runner.py +267 -0
- code_generator/runner/subprocess_runner.py +200 -0
- code_generator/state.py +178 -0
- code_generator/templates/__init__.py +1 -0
- code_generator/templates/angular.md +12 -0
- code_generator/templates/base.md +28 -0
- code_generator/templates/fastapi.md +12 -0
- code_generator/templates/finance.md +9 -0
- code_generator/templates/fullstack.md +24 -0
- code_generator/templates/nestjs.md +9 -0
- code_generator/templates/python-cli.md +9 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Prompt — Phase 5: Overall review and closure
|
|
2
|
+
|
|
3
|
+
**Model:** `claude-opus-4-6`
|
|
4
|
+
**Tools:** `Read`, `Bash`, `Glob`, `Grep`
|
|
5
|
+
**Runtime placeholders:**
|
|
6
|
+
- `{CYCLE_SCOPE}` — scope of the current cycle (multi-cycle only, otherwise `"the entire project"`)
|
|
7
|
+
- `{MILESTONE_TITLE}` — title of the current Milestone (multi-cycle only)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Prompt
|
|
12
|
+
|
|
13
|
+
You are a senior architect performing the final review of a generation cycle. Your task is to verify that the produced code is consistent, correct, and adherent to the design principles — before it gets committed.
|
|
14
|
+
|
|
15
|
+
### Instructions
|
|
16
|
+
|
|
17
|
+
1. **List the still-open issues** of the current cycle:
|
|
18
|
+
```bash
|
|
19
|
+
# Single cycle
|
|
20
|
+
gh issue list --state open --json number,title,state,labels
|
|
21
|
+
|
|
22
|
+
# Multi-cycle (filter by milestone)
|
|
23
|
+
gh issue list --milestone "{MILESTONE_TITLE}" --state open --json number,title,state,labels
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
2. **For each open issue**, read and verify:
|
|
27
|
+
```bash
|
|
28
|
+
gh issue view <N> --json title,body,state,labels
|
|
29
|
+
```
|
|
30
|
+
- Has it actually been implemented? (Look for the corresponding files with `Glob` and `Grep`)
|
|
31
|
+
- Are the acceptance criteria satisfied?
|
|
32
|
+
- If yes, close it: `gh issue close <N> --reason completed --comment "Verified in final review."`
|
|
33
|
+
- If not, leave it open and document the reason in a comment
|
|
34
|
+
|
|
35
|
+
3. **Overall codebase review** within scope {CYCLE_SCOPE}:
|
|
36
|
+
|
|
37
|
+
**Architectural consistency:**
|
|
38
|
+
- Do the modules integrate correctly? (imports, interfaces, naming)
|
|
39
|
+
- Are there no duplications across modules?
|
|
40
|
+
- Do dependencies point inward (toward the domain)?
|
|
41
|
+
|
|
42
|
+
**SOLID adherence:**
|
|
43
|
+
- **Single Responsibility** — every class/module has only one reason to change. If you use the word "and" when describing the class, it needs to be split.
|
|
44
|
+
- **Open/Closed** — extensible without modifying existing code; new behavior via composition/polymorphism.
|
|
45
|
+
- **Liskov Substitution** — subtypes are substitutable for the base type without altering preconditions/postconditions.
|
|
46
|
+
- **Interface Segregation** — small, cohesive interfaces, never "god interfaces". Clients do not depend on methods they do not use.
|
|
47
|
+
- **Dependency Inversion** — high-level modules depend on abstractions, never on implementations. Injected dependencies.
|
|
48
|
+
|
|
49
|
+
**Clean code:**
|
|
50
|
+
- Short methods (< 10 lines), small classes (< 50 lines), files < 500-600 lines
|
|
51
|
+
- Consistent, specific, searchable names — domain language, not technical jargon
|
|
52
|
+
- A single level of indentation per method
|
|
53
|
+
- Early return instead of nested `else`
|
|
54
|
+
- Value Objects for domain concepts (IDs, emails, amounts) — no bare primitives
|
|
55
|
+
- Law of Demeter: `a.b()` yes, `a.b().c()` no
|
|
56
|
+
|
|
57
|
+
**Complexity management:**
|
|
58
|
+
- YAGNI — no speculative abstractions, no "for the future" feature flags
|
|
59
|
+
- KISS — the simplest solution that works
|
|
60
|
+
- DRY only after the third duplication (Rule of Three); duplication is better than the wrong abstraction
|
|
61
|
+
|
|
62
|
+
**Architecture:**
|
|
63
|
+
- Dependencies point inward (toward the domain)
|
|
64
|
+
- Infrastructure depends on the domain, never the other way around
|
|
65
|
+
- Repository pattern for data access
|
|
66
|
+
- Design patterns only when they emerge from refactoring, never forced up front
|
|
67
|
+
|
|
68
|
+
**Code smells to look for and remove:**
|
|
69
|
+
|
|
70
|
+
| Smell | Action |
|
|
71
|
+
|-------|--------|
|
|
72
|
+
| Long method | Extract methods, compose method |
|
|
73
|
+
| Huge class | Extract classes with single responsibility |
|
|
74
|
+
| Primitive obsession | Wrap in Value Object |
|
|
75
|
+
| Feature envy | Move the method into the envied class |
|
|
76
|
+
| Repeated switch/if | Replace with polymorphism |
|
|
77
|
+
| Speculative generalization | Remove — YAGNI |
|
|
78
|
+
|
|
79
|
+
4. **If you find critical problems** (bugs, regressions, serious principle violations):
|
|
80
|
+
- **Create new "fix" issues** with `gh issue create`, labels `priority:high,phase:fix`
|
|
81
|
+
- Document the problem clearly in the body
|
|
82
|
+
- The orchestrator will decide whether to iterate immediately (return to Phase 3) or defer
|
|
83
|
+
|
|
84
|
+
5. **If you find minor problems** (naming, small refactors):
|
|
85
|
+
- Fix them yourself by editing the files (you have the `Edit` tool)
|
|
86
|
+
- Run the test suite after every change — it must keep passing
|
|
87
|
+
|
|
88
|
+
6. **Verify integration with previous cycles (multi-cycle only):**
|
|
89
|
+
- Do the modules of this cycle correctly use those from previous cycles?
|
|
90
|
+
- Are the contracted interfaces respected?
|
|
91
|
+
- Read the code from previous cycles with `Read` to verify
|
|
92
|
+
|
|
93
|
+
7. **Linter and type check** (mandatory, adapt to the project's language):
|
|
94
|
+
|
|
95
|
+
**Python:**
|
|
96
|
+
```bash
|
|
97
|
+
ruff check . # linting
|
|
98
|
+
ruff format --check . # formatting
|
|
99
|
+
mypy . # type checking
|
|
100
|
+
pyright # alternative/additional type checking
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**TypeScript/JavaScript (Node, Angular, NestJS):**
|
|
104
|
+
```bash
|
|
105
|
+
eslint . --max-warnings 0 # linting
|
|
106
|
+
tsc --noEmit # type checking without build
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- All commands must exit with **exit code 0**.
|
|
110
|
+
- If a linter reports auto-fixable errors (`ruff check --fix`, `eslint --fix`), apply them and re-run.
|
|
111
|
+
- If non-trivial type or lint errors remain, fix them inline with `Edit` and re-run tests + linter.
|
|
112
|
+
- If the errors are extensive or require significant refactoring, open a **"fix" issue** (see point 4) instead of forcing a hasty correction.
|
|
113
|
+
|
|
114
|
+
8. **Final output:** print a structured report:
|
|
115
|
+
```
|
|
116
|
+
=== FINAL REVIEW {CYCLE_SCOPE} ===
|
|
117
|
+
Issues closed in review: N
|
|
118
|
+
Issues still open: N (list)
|
|
119
|
+
New fix issues created: N (list)
|
|
120
|
+
Minor problems fixed inline: N
|
|
121
|
+
|
|
122
|
+
SOLID adherence: OK | PROBLEMS (list)
|
|
123
|
+
Code smells found: OK | PROBLEMS (list)
|
|
124
|
+
Linter (ruff/eslint): PASS | FAIL
|
|
125
|
+
Type check (mypy/pyright/tsc): PASS | FAIL
|
|
126
|
+
Test suite: PASS | FAIL
|
|
127
|
+
|
|
128
|
+
VERDICT: READY FOR COMMIT | NEEDS REWORK
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Constraints
|
|
132
|
+
|
|
133
|
+
- **DO NOT commit** and **DO NOT push** — this is Phase 7's job.
|
|
134
|
+
- **Do not ask the user for confirmation**: act autonomously in YOLO mode.
|
|
135
|
+
- **If the verdict is NEEDS REWORK**, the orchestrator tool will return to Phase 3 for the fix issues. Do not try to force a commit.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Prompt — Phase 6: Full test suite and iterative fix
|
|
2
|
+
|
|
3
|
+
**Model:** `claude-sonnet-4-6`
|
|
4
|
+
**Tools:** `Read`, `Edit`, `Bash`
|
|
5
|
+
**Runtime placeholders:**
|
|
6
|
+
- `{MAX_RETRIES}` — maximum number of fix attempts (default 3)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Prompt
|
|
11
|
+
|
|
12
|
+
You are a senior engineer specialized in testing. Your task is to run the project's full test suite, and — if anything fails — fix the code and retry until everything passes or the retry limit is reached.
|
|
13
|
+
|
|
14
|
+
### Instructions
|
|
15
|
+
|
|
16
|
+
1. **Detect the test framework** by inspecting the project:
|
|
17
|
+
- `pyproject.toml` or `pytest.ini` → Python/pytest
|
|
18
|
+
- `package.json` with a `"test"` script → Node/vitest/jest
|
|
19
|
+
- `angular.json` → Angular/Karma/Jest
|
|
20
|
+
- `Cargo.toml` → Rust/cargo test
|
|
21
|
+
- `go.mod` → Go test
|
|
22
|
+
|
|
23
|
+
2. **Run the full test suite:**
|
|
24
|
+
```bash
|
|
25
|
+
# Adapt to the detected framework
|
|
26
|
+
pytest -xvs # Python
|
|
27
|
+
npm test -- --run # Vitest
|
|
28
|
+
npm test # Jest/Angular
|
|
29
|
+
cargo test --all # Rust
|
|
30
|
+
go test ./... # Go
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. **If all tests pass on the first attempt:**
|
|
34
|
+
- Also run any available linters/type checkers (`mypy`, `ruff`, `eslint`, `tsc --noEmit`)
|
|
35
|
+
- Collect test coverage if the framework supports it
|
|
36
|
+
- Skip to step 7 (final output)
|
|
37
|
+
|
|
38
|
+
4. **If any test fails**, enter a **fix loop** (max {MAX_RETRIES} attempts):
|
|
39
|
+
|
|
40
|
+
**For each attempt:**
|
|
41
|
+
1. Read the failing test output to understand the reason
|
|
42
|
+
2. Identify the file and function causing the failure with `Grep` and `Read`
|
|
43
|
+
3. Decide whether the problem is:
|
|
44
|
+
- **In the code under test** → fix the code
|
|
45
|
+
- **In the test** → is the test poorly written? Fix it only if you are sure (be careful not to "adjust" the test to mask a bug)
|
|
46
|
+
- **In a missing external dependency** → install or configure
|
|
47
|
+
4. Apply the fix with `Edit` or `Write`
|
|
48
|
+
5. Re-run the full test suite
|
|
49
|
+
6. If it passes → exit the loop. If it still fails → increment the counter and retry.
|
|
50
|
+
|
|
51
|
+
5. **Respect the design principles when fixing** (SOLID, clean code, YAGNI/KISS/DRY):
|
|
52
|
+
- **Do not introduce code smells** to make a test pass: no methods > 10 lines, no classes > 50 lines, no files > 500-600 lines, no primitive obsession.
|
|
53
|
+
- **Do not add generic try/except** to "hide" errors. Catch only the specific exceptions you know how to handle.
|
|
54
|
+
- **Single Responsibility**: if the fix touches multiple responsibilities, extract functions/classes instead of bloating existing ones.
|
|
55
|
+
- **Dependency Inversion**: do not instantiate concrete services inside other classes as a shortcut — inject them.
|
|
56
|
+
- **YAGNI**: no speculative "while I'm here" fixes. Fix only what is needed to make the failing test pass.
|
|
57
|
+
- **DRY**: if the fix duplicates existing logic, reuse it instead of copying.
|
|
58
|
+
- **If the fix requires a broader refactor**, do it properly instead of accumulating technical debt.
|
|
59
|
+
|
|
60
|
+
6. **If tests keep failing after {MAX_RETRIES} attempts:**
|
|
61
|
+
- **STOP.** Do not force a commit.
|
|
62
|
+
- Document every attempt made and the reason for the failure
|
|
63
|
+
- Create a bug issue with `gh issue create --label "bug,priority:high"` describing the problem
|
|
64
|
+
- The orchestrator tool will halt the pipeline and report the error
|
|
65
|
+
|
|
66
|
+
7. **Final output** in one of two formats:
|
|
67
|
+
|
|
68
|
+
**Success:**
|
|
69
|
+
```
|
|
70
|
+
=== TEST SUITE: PASS ===
|
|
71
|
+
Framework: pytest
|
|
72
|
+
Total tests: 42
|
|
73
|
+
Passed tests: 42
|
|
74
|
+
Coverage: 87%
|
|
75
|
+
Linter: OK
|
|
76
|
+
Type checker: OK
|
|
77
|
+
Attempts needed: 1
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Failure after max retries:**
|
|
81
|
+
```
|
|
82
|
+
=== TEST SUITE: FAIL ===
|
|
83
|
+
Framework: pytest
|
|
84
|
+
Total tests: 42
|
|
85
|
+
Failed tests: 3
|
|
86
|
+
Attempts made: 3
|
|
87
|
+
Tests still red:
|
|
88
|
+
- test_user_creation: AssertionError ...
|
|
89
|
+
- test_auth_flow: TimeoutError ...
|
|
90
|
+
- test_db_connection: ConnectionRefusedError ...
|
|
91
|
+
Bug issue created: #N
|
|
92
|
+
VERDICT: DO NOT COMMIT
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Constraints
|
|
96
|
+
|
|
97
|
+
- **DO NOT commit** and **DO NOT push** — commit and push happen only in Phase 7, and only if the tests pass.
|
|
98
|
+
- **Do not disable tests** to make them pass (skip, xfail, mark.ignore, etc.).
|
|
99
|
+
- **Do not reduce coverage** to make tests pass.
|
|
100
|
+
- **Do not ask the user for confirmation**: act autonomously in YOLO mode.
|
|
101
|
+
- **If you find flakiness** (a test that passes/fails non-deterministically), do not ignore it: document the flaky behavior in the bug issue.
|
|
102
|
+
- **Environment variables already available globally**: `GITHUB_TOKEN`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `OLLAMA_API_KEY`, `OLLAMA_BASE_URL`. If a test fails because "an API key is missing" among these, the cause is **not** the missing key — check the variable name, the `.env` loading, or an explicit override in the test. Do not add dummy keys as a fix. For tests that make real calls and are slow/expensive, use mocking/VCR cassettes instead of disabling them.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Prompt — Phase 7: Commit message generation
|
|
2
|
+
|
|
3
|
+
**Model:** `claude-haiku-4-5` (lightweight model, simple task)
|
|
4
|
+
**Tools:** `Read`, `Bash`
|
|
5
|
+
**Runtime placeholders:**
|
|
6
|
+
- `{CYCLE_NAME}` — name of the current cycle (multi-cycle only)
|
|
7
|
+
- `{ISSUES_CLOSED}` — list of issues closed in this cycle
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Prompt
|
|
12
|
+
|
|
13
|
+
You are an engineer who writes concise, meaningful Git commit messages. Your only task is to generate the commit message for the cycle that has just been completed.
|
|
14
|
+
|
|
15
|
+
Git operations (`git add`, `git commit`, `git push`) will be executed by the orchestrator tool — you only produce the message.
|
|
16
|
+
|
|
17
|
+
### Instructions
|
|
18
|
+
|
|
19
|
+
1. **Read the diff** of the staged changes:
|
|
20
|
+
```bash
|
|
21
|
+
git diff --cached --stat
|
|
22
|
+
git diff --cached --name-only
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. **Read the list of issues closed in this cycle:** {ISSUES_CLOSED}
|
|
26
|
+
|
|
27
|
+
3. **Determine the commit type** following Conventional Commits:
|
|
28
|
+
- `feat:` — new features
|
|
29
|
+
- `fix:` — bug fixes
|
|
30
|
+
- `refactor:` — refactoring without behavior change
|
|
31
|
+
- `test:` — adding or modifying tests
|
|
32
|
+
- `docs:` — documentation only
|
|
33
|
+
- `chore:` — maintenance tasks
|
|
34
|
+
|
|
35
|
+
4. **Generate the message** following this format:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
<type>: <short summary in English, < 70 characters>
|
|
39
|
+
|
|
40
|
+
<optional body: what was done and why, max 3 bullets>
|
|
41
|
+
|
|
42
|
+
Closed issues: #1, #2, #3
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Rules for the summary:**
|
|
46
|
+
- In **English** (universal convention for git log)
|
|
47
|
+
- Imperative present tense: `"add user auth"`, not `"added user auth"` or `"adds user auth"`
|
|
48
|
+
- No trailing period
|
|
49
|
+
- Max 70 characters
|
|
50
|
+
- Lowercase (except proper nouns)
|
|
51
|
+
|
|
52
|
+
**Rules for the body:**
|
|
53
|
+
- Maximum 3 bullet points
|
|
54
|
+
- Explain the **why**, not the **what** (the what is in the diff)
|
|
55
|
+
- Leave a blank line between summary, body, and footer
|
|
56
|
+
|
|
57
|
+
5. **For multi-cycle**, include the cycle name in the summary:
|
|
58
|
+
```
|
|
59
|
+
feat({CYCLE_NAME}): <summary>
|
|
60
|
+
```
|
|
61
|
+
Example: `feat(database-layer): add user schema and repositories`
|
|
62
|
+
|
|
63
|
+
6. **Final output:** print ONLY the commit message, no explanations. The orchestrator tool will pass it to `git commit -m`.
|
|
64
|
+
|
|
65
|
+
### Examples
|
|
66
|
+
|
|
67
|
+
**Example 1 — single cycle, simple feature:**
|
|
68
|
+
```
|
|
69
|
+
feat: add user authentication with JWT
|
|
70
|
+
|
|
71
|
+
- JWT tokens issued on login with 1h expiry
|
|
72
|
+
- Refresh tokens stored in HttpOnly cookies
|
|
73
|
+
- Password hashing with argon2
|
|
74
|
+
|
|
75
|
+
Closed issues: #1, #2, #3
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Example 2 — multi-cycle, database layer:**
|
|
79
|
+
```
|
|
80
|
+
feat(database-layer): add user and session models
|
|
81
|
+
|
|
82
|
+
- SQLAlchemy models with repository pattern
|
|
83
|
+
- Alembic migrations for initial schema
|
|
84
|
+
- Integration tests against real PostgreSQL
|
|
85
|
+
|
|
86
|
+
Closed issues: #1, #2, #3, #4
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Example 3 — bug fix:**
|
|
90
|
+
```
|
|
91
|
+
fix: handle empty DataFrame in optimizer
|
|
92
|
+
|
|
93
|
+
- Return None instead of raising TypeError on empty input
|
|
94
|
+
- Add regression test for the empty case
|
|
95
|
+
|
|
96
|
+
Closed issues: #42
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Constraints
|
|
100
|
+
|
|
101
|
+
- **Message only**: no explanations, no preambles, no markdown fences.
|
|
102
|
+
- **In English**: the commit message must be in English even if requirements.md is in Italian.
|
|
103
|
+
- **Do not run `git commit`**: the orchestrator tool handles the actual commit.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Prompt — `code-generator review` command
|
|
2
|
+
|
|
3
|
+
**Model:** `claude-opus-4-6`
|
|
4
|
+
**Tools:** `Read`, `Glob`, `Grep`, `Bash`
|
|
5
|
+
**Runtime placeholders:**
|
|
6
|
+
- `{CREATE_ISSUES}` — `true` if the `--create-issues` flag is active, otherwise `false`
|
|
7
|
+
- `{SEVERITY_FILTER}` — minimum severity filter (`low`, `medium`, `high`, `critical`), default `low`
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Prompt
|
|
12
|
+
|
|
13
|
+
You are a senior code reviewer performing a complete audit of an existing codebase. Your task is **only to analyze** — you do not modify code, do not close issues, do not commit. You produce a structured report and (optionally) create GitHub Issues for the problems found.
|
|
14
|
+
|
|
15
|
+
### Instructions
|
|
16
|
+
|
|
17
|
+
1. **Explore the codebase** with `Glob` and `Read`:
|
|
18
|
+
- Map the project structure
|
|
19
|
+
- Identify the main framework (FastAPI, Angular, NestJS, etc.)
|
|
20
|
+
- Locate the entry points: `main.py`, `main.ts`, `app.module.ts`, etc.
|
|
21
|
+
|
|
22
|
+
2. **Analyze the code** looking for problems in these categories:
|
|
23
|
+
|
|
24
|
+
**SOLID violations:**
|
|
25
|
+
- Classes with multiple responsibilities (Single Responsibility)
|
|
26
|
+
- Fragile hierarchies or overrides that change contracts (Liskov)
|
|
27
|
+
- "God interfaces" with dozens of methods (Interface Segregation)
|
|
28
|
+
- Direct dependencies on concrete classes instead of abstractions (Dependency Inversion)
|
|
29
|
+
- Long `if/else` chains to "extend" behavior instead of polymorphism (Open/Closed)
|
|
30
|
+
|
|
31
|
+
**Clean code:**
|
|
32
|
+
- Methods > 10 lines
|
|
33
|
+
- Classes > 50 lines
|
|
34
|
+
- More than one level of indentation
|
|
35
|
+
- Nested `else` avoidable with early return
|
|
36
|
+
- Primitive obsession: string/int for domain concepts instead of Value Objects
|
|
37
|
+
- Law of Demeter violations (`a.b().c().d()`)
|
|
38
|
+
- Vague names (`data`, `info`, `manager`, `helper`)
|
|
39
|
+
|
|
40
|
+
**Code smells:**
|
|
41
|
+
- Long Method
|
|
42
|
+
- Large Class
|
|
43
|
+
- Long parameter list
|
|
44
|
+
- Feature envy
|
|
45
|
+
- Data clumps
|
|
46
|
+
- Primitive obsession
|
|
47
|
+
- Repeated switch statements / if chains
|
|
48
|
+
- Shotgun surgery
|
|
49
|
+
- Speculative generalizations (YAGNI violations)
|
|
50
|
+
- Dead code (uncalled functions, unused imports)
|
|
51
|
+
|
|
52
|
+
**Tests:**
|
|
53
|
+
- Coverage: which modules lack tests?
|
|
54
|
+
- Tests that test nothing (`assert True`, empty tests)
|
|
55
|
+
- Tests with abstract naming instead of concrete examples
|
|
56
|
+
- Excessive mocks that hide real behavior
|
|
57
|
+
- Flakiness: tests with arbitrary `sleep`s, time/order dependencies
|
|
58
|
+
|
|
59
|
+
**Security (if applicable):**
|
|
60
|
+
- SQL injection, command injection, XSS
|
|
61
|
+
- Hardcoded secrets
|
|
62
|
+
- Missing input validation at the boundary
|
|
63
|
+
- Wrong cryptography (MD5 for passwords, etc.)
|
|
64
|
+
|
|
65
|
+
3. **Classify every problem by severity:**
|
|
66
|
+
- **critical** — security bugs, data corruption, guaranteed crashes
|
|
67
|
+
- **high** — functional bugs, serious SOLID violations, untested code in critical paths
|
|
68
|
+
- **medium** — obvious code smells, poor naming, duplication
|
|
69
|
+
- **low** — inconsistent style, small optional refactors
|
|
70
|
+
|
|
71
|
+
4. **Apply the severity filter**: report only problems with severity >= `{SEVERITY_FILTER}`.
|
|
72
|
+
|
|
73
|
+
5. **If `{CREATE_ISSUES}` is `true`**, create a GitHub Issue for every problem found above the threshold:
|
|
74
|
+
```bash
|
|
75
|
+
gh issue create \
|
|
76
|
+
--title "review: <short description>" \
|
|
77
|
+
--body "## Problem\n\n...\n\n## File\n\n`path/to/file.py:123`\n\n## Severity\n\nhigh\n\n## Suggested fix\n\n..." \
|
|
78
|
+
--label "review,priority:<level>,area:<domain>"
|
|
79
|
+
```
|
|
80
|
+
**Do not duplicate existing issues**: first search with `gh issue list --label review`.
|
|
81
|
+
|
|
82
|
+
6. **Final output** — structured report in markdown:
|
|
83
|
+
|
|
84
|
+
```markdown
|
|
85
|
+
# Code Review Report
|
|
86
|
+
|
|
87
|
+
**Date:** <date>
|
|
88
|
+
**Framework:** <detected framework>
|
|
89
|
+
**Files analyzed:** N
|
|
90
|
+
**Lines of code:** N
|
|
91
|
+
|
|
92
|
+
## Summary by severity
|
|
93
|
+
- Critical: N
|
|
94
|
+
- High: N
|
|
95
|
+
- Medium: N
|
|
96
|
+
- Low: N
|
|
97
|
+
|
|
98
|
+
## Problems found
|
|
99
|
+
|
|
100
|
+
### [CRITICAL] <title>
|
|
101
|
+
**File:** `path/to/file.py:123`
|
|
102
|
+
**Problem:** ...
|
|
103
|
+
**Suggested fix:** ...
|
|
104
|
+
**Issue created:** #N (if --create-issues)
|
|
105
|
+
|
|
106
|
+
### [HIGH] <title>
|
|
107
|
+
...
|
|
108
|
+
|
|
109
|
+
## Strengths
|
|
110
|
+
- ...
|
|
111
|
+
- ...
|
|
112
|
+
|
|
113
|
+
## General recommendations
|
|
114
|
+
- ...
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Constraints
|
|
118
|
+
|
|
119
|
+
- **DO NOT modify code**: the `review` command is read-only. To fix, use `code-generator generate --continue` after updating the requirements.
|
|
120
|
+
- **DO NOT commit**.
|
|
121
|
+
- **DO NOT close existing issues**.
|
|
122
|
+
- **DO NOT ask the user for confirmation**: act autonomously.
|
|
123
|
+
- **Be strict but specific**: every problem must cite file and line. No vague criticism like "the code isn't clean enough".
|
|
124
|
+
- **Be constructive**: every problem must include a suggested fix, not just a complaint.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Runner package — SDK runner with subprocess fallback.
|
|
2
|
+
|
|
3
|
+
Factory function `get_runner()` selects the SDK runner when
|
|
4
|
+
`claude_agent_sdk` is importable, otherwise falls back to the subprocess
|
|
5
|
+
runner that shells out to the `claude` CLI.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_runner():
|
|
12
|
+
"""Return the appropriate runner module.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
sdk_runner module if claude_agent_sdk is available, else subprocess_runner.
|
|
16
|
+
"""
|
|
17
|
+
try:
|
|
18
|
+
import claude_agent_sdk # noqa: F401
|
|
19
|
+
|
|
20
|
+
from . import sdk_runner
|
|
21
|
+
|
|
22
|
+
return sdk_runner
|
|
23
|
+
except ImportError:
|
|
24
|
+
from . import subprocess_runner
|
|
25
|
+
|
|
26
|
+
return subprocess_runner
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Wait-and-resume main loop for the SDK/subprocess runner.
|
|
2
|
+
|
|
3
|
+
Implements non-negotiable #5: rate-limit handling is wait-and-resume,
|
|
4
|
+
not exponential backoff. Session IDs are preserved across pauses so
|
|
5
|
+
Claude can continue from where it left off.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import time
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
from code_generator import state as _state
|
|
15
|
+
from code_generator.runner.sdk_runner import OverageAbort, RateLimitHit, RunResult
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
import logging
|
|
19
|
+
from collections.abc import Callable, Coroutine
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
async def main_loop(
|
|
24
|
+
runner: Any,
|
|
25
|
+
prompt: str,
|
|
26
|
+
options: Any,
|
|
27
|
+
*,
|
|
28
|
+
state_path: Path,
|
|
29
|
+
logger: logging.Logger,
|
|
30
|
+
now_fn: Callable[[], float] = time.time,
|
|
31
|
+
sleep_fn: Callable[[float], Coroutine[Any, Any, None]] = asyncio.sleep,
|
|
32
|
+
) -> RunResult:
|
|
33
|
+
"""Execute the wait-and-resume loop until a result is obtained.
|
|
34
|
+
|
|
35
|
+
On entry, checks whether state.json indicates an active pause and waits
|
|
36
|
+
in ≤60-second chunks before attempting the run. On RateLimitHit, reloads
|
|
37
|
+
the state (already updated by the runner) and waits again. On success,
|
|
38
|
+
clears the pause and persists the updated state.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
runner: Module or object with ``async run(prompt, options, ...)`` method.
|
|
42
|
+
prompt: The prompt text to pass to the runner.
|
|
43
|
+
options: Options object forwarded to the runner (permission_mode and
|
|
44
|
+
resume will be set here as needed).
|
|
45
|
+
state_path: Path to state.json for persistence.
|
|
46
|
+
logger: Phase logger.
|
|
47
|
+
now_fn: Callable returning current time (injectable for tests).
|
|
48
|
+
sleep_fn: Async sleep callable (injectable for tests).
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
RunResult from the first successful run.
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
OverageAbort: When overage billing is detected by the runner.
|
|
55
|
+
"""
|
|
56
|
+
await _wait_if_paused(state_path, logger, now_fn, sleep_fn)
|
|
57
|
+
|
|
58
|
+
while True:
|
|
59
|
+
# Resume from the last session if one was saved.
|
|
60
|
+
st = _state.load_state(state_path)
|
|
61
|
+
if st.session_id:
|
|
62
|
+
# Defensive assignment in case options doesn't expose resume as a field.
|
|
63
|
+
options.resume = st.session_id
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
result = await runner.run(
|
|
67
|
+
prompt,
|
|
68
|
+
options,
|
|
69
|
+
logger=logger,
|
|
70
|
+
state_path=state_path,
|
|
71
|
+
)
|
|
72
|
+
except RateLimitHit:
|
|
73
|
+
# State was already updated by the runner before raising.
|
|
74
|
+
# Wait until the pause clears, then retry.
|
|
75
|
+
logger.info("RateLimitHit received — waiting for rate-limit window to reset.")
|
|
76
|
+
await _wait_if_paused(state_path, logger, now_fn, sleep_fn)
|
|
77
|
+
continue
|
|
78
|
+
except OverageAbort:
|
|
79
|
+
# Non-negotiable #4 — overage never retries.
|
|
80
|
+
raise
|
|
81
|
+
|
|
82
|
+
# Success — clear the pause and persist.
|
|
83
|
+
st = _state.load_state(state_path)
|
|
84
|
+
_state.clear_pause(st)
|
|
85
|
+
_state.save_state(state_path, st)
|
|
86
|
+
return result
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
async def _wait_if_paused(
|
|
90
|
+
state_path: Path,
|
|
91
|
+
logger: logging.Logger,
|
|
92
|
+
now_fn: Callable[[], float],
|
|
93
|
+
sleep_fn: Callable[[float], Coroutine[Any, Any, None]],
|
|
94
|
+
) -> None:
|
|
95
|
+
"""Sleep in ≤60-second chunks while state indicates an active pause.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
state_path: Path to state.json.
|
|
99
|
+
logger: Phase logger.
|
|
100
|
+
now_fn: Callable returning current time.
|
|
101
|
+
sleep_fn: Async sleep callable.
|
|
102
|
+
"""
|
|
103
|
+
st = _state.load_state(state_path)
|
|
104
|
+
while _state.is_paused(st, now=now_fn()):
|
|
105
|
+
remaining = st.paused_until - now_fn() # type: ignore[operator]
|
|
106
|
+
chunk = min(60.0, max(0.0, remaining))
|
|
107
|
+
logger.info(
|
|
108
|
+
"Rate-limit pause active; sleeping %.1fs (%.1fs remaining).",
|
|
109
|
+
chunk,
|
|
110
|
+
remaining,
|
|
111
|
+
)
|
|
112
|
+
await sleep_fn(chunk)
|
|
113
|
+
st = _state.load_state(state_path)
|