claude-code-generator 0.2.0__tar.gz → 0.2.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.
- {claude_code_generator-0.2.0/src/claude_code_generator.egg-info → claude_code_generator-0.2.2}/PKG-INFO +17 -3
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/README.md +16 -2
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/pyproject.toml +1 -1
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2/src/claude_code_generator.egg-info}/PKG-INFO +17 -3
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/__init__.py +1 -1
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/_dispatch.py +58 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/phase2_review.py +17 -2
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_generate_resume.py +126 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/LICENSE +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/setup.cfg +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/claude_code_generator.egg-info/SOURCES.txt +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/claude_code_generator.egg-info/dependency_links.txt +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/claude_code_generator.egg-info/entry_points.txt +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/claude_code_generator.egg-info/requires.txt +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/claude_code_generator.egg-info/top_level.txt +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/agents.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/cli.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/__init__.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/_detect.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/_resume.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/generate.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/init.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/optimize.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/review.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/status.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/effort.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/env.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/gh/__init__.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/gh/core.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/gh/issues.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/gh/labels.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/gh/milestones.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/git_ops.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/logging_setup.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/__init__.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/_comments.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/cycle_loop.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/phase0_complexity.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/phase1_plan.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/phase3_4_implement.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/phase5_closure.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/phase6_test.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/orchestrator/phase7_commit.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/__init__.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-optimize-requirements.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-phase-0-complexity.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-phase-1-planning.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-phase-2-issue-review.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-phase-3-implementation.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-phase-5-final-review.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-phase-6-test.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-phase-7-commit.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/prompt-review.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/requirements_structure.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/__init__.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/message_parsing.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/options.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/protocol.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/rate_limit.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/retry.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/sdk_runner.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/subprocess_runner.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/types.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/utils.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/state.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/__init__.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/angular.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/base.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/fastapi.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/finance.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/fullstack.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/nestjs.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/python-cli.md +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_agents.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_comments.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_commit_message.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_cycle_loop.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_cycle_loop_multicycle.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_delta_planning.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_detect.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_effort.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_env.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_generate.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_gh.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_gh_labels.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_gh_milestones.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_gh_submodules.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_git_ops.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_init.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_logging_setup.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_message_parsing.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_optimize.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_options.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase0.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase1.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase2.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase3_4.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase5.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase6.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase7.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase_token_logging.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_prompts.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_rate_limit.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_requirements_structure.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_retry.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_review.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_runner_protocol.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_runner_protocol_annotations.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_runner_types.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_runner_utils.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_sdk_runner.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_state.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_status.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_subprocess_runner.py +0 -0
- {claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-code-generator
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Orchestrator CLI that drives Claude Code end-to-end to generate whole projects from a requirements.md file.
|
|
5
5
|
Author: Silvio Baratto
|
|
6
6
|
License: MIT
|
|
@@ -31,7 +31,7 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# code-generator
|
|
33
33
|
|
|
34
|
-
A Python CLI that orchestrates Claude Code end-to-end to generate a whole project from a `requirements.md` file.
|
|
34
|
+
A Python CLI that orchestrates Claude Code end-to-end to generate a whole project from a `requirements.md` file. Five commands — `init`, `optimize`, `generate`, `review`, `status`. Works for any project type: Python CLI, FastAPI, Angular, NestJS, full-stack, finance, BAML/LLM.
|
|
35
35
|
|
|
36
36
|
> **Max subscription only.** This tool uses **exclusively** the Claude Max subscription. It strips every environment variable that could route a call through the API and aborts on startup if any are still present. There is no path to API credit billing — see [Safety constraints](#safety-constraints) below.
|
|
37
37
|
|
|
@@ -68,6 +68,20 @@ code-generator init --template fastapi
|
|
|
68
68
|
$EDITOR .code-generator/requirements.md
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
### `code-generator optimize [--dry-run] [--force]`
|
|
72
|
+
|
|
73
|
+
Pre-flight rewrite of `.code-generator/requirements.md` into the canonical structure the orchestrator expects: `# Title` → `## Description` → `## Tech Stack` → `## Goals` → `## Scope` (numbered `### N.` subsections with per-section `Acceptance criteria` checklists) → `## Non-goals` → `## Constraints` → `## Global acceptance criteria`.
|
|
74
|
+
|
|
75
|
+
Runs a single Opus 4.6 session with a dedicated prompt, preserves the original intent verbatim when ambiguous (never invents new scope), and writes the rewrite back to disk atomically. The pre-optimize original is saved to `.code-generator/requirements.backup-<UTC-timestamp>.md` so you can always `diff` and recover. The command is stateless — it never reads or writes `state.json` and never calls `gh`.
|
|
76
|
+
|
|
77
|
+
Short-circuits and exits 0 if the file is already canonical. Use `--force` to re-optimize anyway. Use `--dry-run` to print the proposed rewrite to stdout without touching the file or creating a backup.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
code-generator optimize --dry-run # preview
|
|
81
|
+
code-generator optimize # commit the rewrite
|
|
82
|
+
code-generator generate # then run the pipeline
|
|
83
|
+
```
|
|
84
|
+
|
|
71
85
|
### `code-generator generate [flags]`
|
|
72
86
|
|
|
73
87
|
Read `.code-generator/requirements.md` and orchestrate Claude Code through the 0→7 phase pipeline:
|
|
@@ -155,7 +169,7 @@ src/code_generator/
|
|
|
155
169
|
│ ├── phase6_test.py # test runner, max 3 retries
|
|
156
170
|
│ ├── phase7_commit.py # Opus commit message + push with rebase retry
|
|
157
171
|
│ └── cycle_loop.py # multi-cycle driver
|
|
158
|
-
└── commands/ # init, status, generate, review (Typer commands)
|
|
172
|
+
└── commands/ # init, optimize, status, generate, review (Typer commands)
|
|
159
173
|
```
|
|
160
174
|
|
|
161
175
|
## Development
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# code-generator
|
|
2
2
|
|
|
3
|
-
A Python CLI that orchestrates Claude Code end-to-end to generate a whole project from a `requirements.md` file.
|
|
3
|
+
A Python CLI that orchestrates Claude Code end-to-end to generate a whole project from a `requirements.md` file. Five commands — `init`, `optimize`, `generate`, `review`, `status`. Works for any project type: Python CLI, FastAPI, Angular, NestJS, full-stack, finance, BAML/LLM.
|
|
4
4
|
|
|
5
5
|
> **Max subscription only.** This tool uses **exclusively** the Claude Max subscription. It strips every environment variable that could route a call through the API and aborts on startup if any are still present. There is no path to API credit billing — see [Safety constraints](#safety-constraints) below.
|
|
6
6
|
|
|
@@ -37,6 +37,20 @@ code-generator init --template fastapi
|
|
|
37
37
|
$EDITOR .code-generator/requirements.md
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
### `code-generator optimize [--dry-run] [--force]`
|
|
41
|
+
|
|
42
|
+
Pre-flight rewrite of `.code-generator/requirements.md` into the canonical structure the orchestrator expects: `# Title` → `## Description` → `## Tech Stack` → `## Goals` → `## Scope` (numbered `### N.` subsections with per-section `Acceptance criteria` checklists) → `## Non-goals` → `## Constraints` → `## Global acceptance criteria`.
|
|
43
|
+
|
|
44
|
+
Runs a single Opus 4.6 session with a dedicated prompt, preserves the original intent verbatim when ambiguous (never invents new scope), and writes the rewrite back to disk atomically. The pre-optimize original is saved to `.code-generator/requirements.backup-<UTC-timestamp>.md` so you can always `diff` and recover. The command is stateless — it never reads or writes `state.json` and never calls `gh`.
|
|
45
|
+
|
|
46
|
+
Short-circuits and exits 0 if the file is already canonical. Use `--force` to re-optimize anyway. Use `--dry-run` to print the proposed rewrite to stdout without touching the file or creating a backup.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
code-generator optimize --dry-run # preview
|
|
50
|
+
code-generator optimize # commit the rewrite
|
|
51
|
+
code-generator generate # then run the pipeline
|
|
52
|
+
```
|
|
53
|
+
|
|
40
54
|
### `code-generator generate [flags]`
|
|
41
55
|
|
|
42
56
|
Read `.code-generator/requirements.md` and orchestrate Claude Code through the 0→7 phase pipeline:
|
|
@@ -124,7 +138,7 @@ src/code_generator/
|
|
|
124
138
|
│ ├── phase6_test.py # test runner, max 3 retries
|
|
125
139
|
│ ├── phase7_commit.py # Opus commit message + push with rebase retry
|
|
126
140
|
│ └── cycle_loop.py # multi-cycle driver
|
|
127
|
-
└── commands/ # init, status, generate, review (Typer commands)
|
|
141
|
+
└── commands/ # init, optimize, status, generate, review (Typer commands)
|
|
128
142
|
```
|
|
129
143
|
|
|
130
144
|
## Development
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "claude-code-generator"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Orchestrator CLI that drives Claude Code end-to-end to generate whole projects from a requirements.md file."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-code-generator
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Orchestrator CLI that drives Claude Code end-to-end to generate whole projects from a requirements.md file.
|
|
5
5
|
Author: Silvio Baratto
|
|
6
6
|
License: MIT
|
|
@@ -31,7 +31,7 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# code-generator
|
|
33
33
|
|
|
34
|
-
A Python CLI that orchestrates Claude Code end-to-end to generate a whole project from a `requirements.md` file.
|
|
34
|
+
A Python CLI that orchestrates Claude Code end-to-end to generate a whole project from a `requirements.md` file. Five commands — `init`, `optimize`, `generate`, `review`, `status`. Works for any project type: Python CLI, FastAPI, Angular, NestJS, full-stack, finance, BAML/LLM.
|
|
35
35
|
|
|
36
36
|
> **Max subscription only.** This tool uses **exclusively** the Claude Max subscription. It strips every environment variable that could route a call through the API and aborts on startup if any are still present. There is no path to API credit billing — see [Safety constraints](#safety-constraints) below.
|
|
37
37
|
|
|
@@ -68,6 +68,20 @@ code-generator init --template fastapi
|
|
|
68
68
|
$EDITOR .code-generator/requirements.md
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
### `code-generator optimize [--dry-run] [--force]`
|
|
72
|
+
|
|
73
|
+
Pre-flight rewrite of `.code-generator/requirements.md` into the canonical structure the orchestrator expects: `# Title` → `## Description` → `## Tech Stack` → `## Goals` → `## Scope` (numbered `### N.` subsections with per-section `Acceptance criteria` checklists) → `## Non-goals` → `## Constraints` → `## Global acceptance criteria`.
|
|
74
|
+
|
|
75
|
+
Runs a single Opus 4.6 session with a dedicated prompt, preserves the original intent verbatim when ambiguous (never invents new scope), and writes the rewrite back to disk atomically. The pre-optimize original is saved to `.code-generator/requirements.backup-<UTC-timestamp>.md` so you can always `diff` and recover. The command is stateless — it never reads or writes `state.json` and never calls `gh`.
|
|
76
|
+
|
|
77
|
+
Short-circuits and exits 0 if the file is already canonical. Use `--force` to re-optimize anyway. Use `--dry-run` to print the proposed rewrite to stdout without touching the file or creating a backup.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
code-generator optimize --dry-run # preview
|
|
81
|
+
code-generator optimize # commit the rewrite
|
|
82
|
+
code-generator generate # then run the pipeline
|
|
83
|
+
```
|
|
84
|
+
|
|
71
85
|
### `code-generator generate [flags]`
|
|
72
86
|
|
|
73
87
|
Read `.code-generator/requirements.md` and orchestrate Claude Code through the 0→7 phase pipeline:
|
|
@@ -155,7 +169,7 @@ src/code_generator/
|
|
|
155
169
|
│ ├── phase6_test.py # test runner, max 3 retries
|
|
156
170
|
│ ├── phase7_commit.py # Opus commit message + push with rebase retry
|
|
157
171
|
│ └── cycle_loop.py # multi-cycle driver
|
|
158
|
-
└── commands/ # init, status, generate, review (Typer commands)
|
|
172
|
+
└── commands/ # init, optimize, status, generate, review (Typer commands)
|
|
159
173
|
```
|
|
160
174
|
|
|
161
175
|
## Development
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/_dispatch.py
RENAMED
|
@@ -25,6 +25,56 @@ _logger = logging.getLogger(__name__)
|
|
|
25
25
|
__all__ = ["dispatch_async", "dispatch_orchestrator"]
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def _reset_failed_cycles_for_continue(
|
|
29
|
+
st: state_module.State,
|
|
30
|
+
*,
|
|
31
|
+
target_cycle: int | None,
|
|
32
|
+
state_path: Path,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Reset ``failed`` cycles back to ``open`` on ``--continue``.
|
|
35
|
+
|
|
36
|
+
When a cycle crashes mid-run, ``cycle_loop.run_multi_cycle`` marks it as
|
|
37
|
+
``status="failed"`` and persists the exception in ``state.last_error``.
|
|
38
|
+
The next ``--continue`` must treat these as retryable, otherwise the user
|
|
39
|
+
has to hand-edit ``state.json`` every time a cycle crashes — which
|
|
40
|
+
defeats the whole point of ``--continue``.
|
|
41
|
+
|
|
42
|
+
When ``target_cycle`` is set (``--cycle N``), only that cycle is reset.
|
|
43
|
+
Otherwise every failed cycle is reset. ``state.last_error`` and
|
|
44
|
+
``state.rate_limit_type`` are cleared on any successful reset so the
|
|
45
|
+
status line stops showing red for a resolved failure.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
st: Root state (mutated in place).
|
|
49
|
+
target_cycle: When set, only reset this cycle id; otherwise reset all.
|
|
50
|
+
state_path: Path to ``state.json`` for atomic persistence.
|
|
51
|
+
"""
|
|
52
|
+
from code_generator import state as _state_module
|
|
53
|
+
|
|
54
|
+
reset_ids: list[int] = []
|
|
55
|
+
for c in st.cycles:
|
|
56
|
+
if c.status != "failed":
|
|
57
|
+
continue
|
|
58
|
+
if target_cycle is not None and c.id != target_cycle:
|
|
59
|
+
continue
|
|
60
|
+
c.status = "open"
|
|
61
|
+
reset_ids.append(c.id)
|
|
62
|
+
|
|
63
|
+
if not reset_ids:
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
if getattr(st, "last_error", None):
|
|
67
|
+
st.last_error = None
|
|
68
|
+
if getattr(st, "rate_limit_type", None):
|
|
69
|
+
st.rate_limit_type = None
|
|
70
|
+
|
|
71
|
+
_state_module.save_state(state_path, st)
|
|
72
|
+
_logger.info(
|
|
73
|
+
"--continue: reset failed cycles to open: %s",
|
|
74
|
+
", ".join(str(i) for i in reset_ids),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
28
78
|
async def _apply_delta_plan(
|
|
29
79
|
st: state_module.State,
|
|
30
80
|
project_dir: Path,
|
|
@@ -250,6 +300,14 @@ def dispatch_orchestrator(
|
|
|
250
300
|
start_cycle: int | None = None
|
|
251
301
|
|
|
252
302
|
if continue_:
|
|
303
|
+
# A cycle that crashed mid-run is marked "failed" by the exception
|
|
304
|
+
# handler in cycle_loop.run_multi_cycle. Without this reset, `--continue`
|
|
305
|
+
# would skip it forever because `_eligible_cycles` only returns "open"
|
|
306
|
+
# cycles. Semantically, `--continue` means "retry from where we
|
|
307
|
+
# crashed", so flip any failed cycle back to "open" and clear the
|
|
308
|
+
# stale error. Explicit --cycle N also benefits: reset just the target.
|
|
309
|
+
_reset_failed_cycles_for_continue(st, target_cycle=cycle, state_path=state_path)
|
|
310
|
+
|
|
253
311
|
# Resume from the *next* phase/cycle after the last completed one.
|
|
254
312
|
if effective_mode == "multi-cycle":
|
|
255
313
|
start_cycle, start_phase = resolve_continue_multi_cycle(st)
|
|
@@ -18,7 +18,7 @@ from code_generator.orchestrator._comments import fetch_formatted_comments
|
|
|
18
18
|
from code_generator.prompts import load_prompt
|
|
19
19
|
from code_generator.runner import rate_limit, retry
|
|
20
20
|
from code_generator.runner.options import make_agent_options
|
|
21
|
-
from code_generator.runner.types import TokenUsage
|
|
21
|
+
from code_generator.runner.types import MaxTurnsExceeded, TokenUsage
|
|
22
22
|
from code_generator.state import get_issues, save_state
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
@@ -84,7 +84,7 @@ async def run(
|
|
|
84
84
|
effort=effort_level,
|
|
85
85
|
allowed_tools=["Read", "Bash", "Glob", "Grep"],
|
|
86
86
|
cwd=str(project_dir),
|
|
87
|
-
max_turns=
|
|
87
|
+
max_turns=40,
|
|
88
88
|
)
|
|
89
89
|
|
|
90
90
|
breaker = retry.CircuitBreaker(max_failures=3)
|
|
@@ -103,6 +103,21 @@ async def run(
|
|
|
103
103
|
breaker=breaker,
|
|
104
104
|
)
|
|
105
105
|
issue_usage = result.usage if result is not None else TokenUsage()
|
|
106
|
+
except MaxTurnsExceeded:
|
|
107
|
+
reviewed = False
|
|
108
|
+
logger.error(
|
|
109
|
+
"Phase 2: issue #%d hit max_turns ceiling"
|
|
110
|
+
" — no retry (deterministic failure), tagging for manual review.",
|
|
111
|
+
issue.number,
|
|
112
|
+
)
|
|
113
|
+
try:
|
|
114
|
+
gh.add_label(issue.number, "needs-manual-review")
|
|
115
|
+
except gh.GhError as exc:
|
|
116
|
+
logger.warning(
|
|
117
|
+
"Could not add needs-manual-review label to #%d: %s",
|
|
118
|
+
issue.number,
|
|
119
|
+
exc,
|
|
120
|
+
)
|
|
106
121
|
except retry.CircuitOpen:
|
|
107
122
|
reviewed = False
|
|
108
123
|
logger.error(
|
|
@@ -1337,3 +1337,129 @@ class TestNoOpDetection:
|
|
|
1337
1337
|
|
|
1338
1338
|
st_after = state_module.load_state(cg / "state.json")
|
|
1339
1339
|
assert st_after.requirements_hash == new_hash
|
|
1340
|
+
|
|
1341
|
+
|
|
1342
|
+
# ---------------------------------------------------------------------------
|
|
1343
|
+
# --continue resets failed cycles back to open (retry-on-continue)
|
|
1344
|
+
# ---------------------------------------------------------------------------
|
|
1345
|
+
|
|
1346
|
+
|
|
1347
|
+
class TestContinueResetsFailedCycles:
|
|
1348
|
+
"""Regression guard: `--continue` must retry cycles marked `status=failed`.
|
|
1349
|
+
|
|
1350
|
+
When a cycle crashes mid-run, `cycle_loop.run_multi_cycle` sets
|
|
1351
|
+
`cycle.status = "failed"` and persists `state.last_error`. Without the
|
|
1352
|
+
reset, `_eligible_cycles` filters out failed cycles and `--continue`
|
|
1353
|
+
prints "all eligible cycles complete" without actually running anything.
|
|
1354
|
+
"""
|
|
1355
|
+
|
|
1356
|
+
def test_continue_resets_failed_cycle_to_open(
|
|
1357
|
+
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
1358
|
+
) -> None:
|
|
1359
|
+
"""--continue flips cycles[0].status from 'failed' back to 'open' and clears last_error."""
|
|
1360
|
+
monkeypatch.chdir(tmp_path)
|
|
1361
|
+
|
|
1362
|
+
cg = tmp_path / ".code-generator"
|
|
1363
|
+
cg.mkdir(parents=True, exist_ok=True)
|
|
1364
|
+
st = state_module.State(
|
|
1365
|
+
mode="multi-cycle", # type: ignore[arg-type]
|
|
1366
|
+
started_at="2026-01-01T00:00:00Z",
|
|
1367
|
+
updated_at="2026-01-01T00:00:00Z",
|
|
1368
|
+
current_cycle=1,
|
|
1369
|
+
phase=None,
|
|
1370
|
+
cycles=[
|
|
1371
|
+
_make_cycle(cycle_id=1, phase=1, status="failed"),
|
|
1372
|
+
_make_cycle(cycle_id=2, phase=0, status="open"),
|
|
1373
|
+
],
|
|
1374
|
+
)
|
|
1375
|
+
st.last_error = "SDK session exhausted max_turns budget"
|
|
1376
|
+
state_module.save_state(cg / "state.json", st)
|
|
1377
|
+
|
|
1378
|
+
captured: list[dict] = []
|
|
1379
|
+
|
|
1380
|
+
async def mock_multi(state, *_args, start_cycle=None, start_phase=1, **_kwargs):
|
|
1381
|
+
captured.append({"start_cycle": start_cycle, "start_phase": start_phase})
|
|
1382
|
+
return state
|
|
1383
|
+
|
|
1384
|
+
from code_generator.orchestrator import cycle_loop
|
|
1385
|
+
|
|
1386
|
+
monkeypatch.setattr(cycle_loop, "run_multi_cycle", mock_multi)
|
|
1387
|
+
_mock_phase0_single(monkeypatch)
|
|
1388
|
+
|
|
1389
|
+
result = runner.invoke(app, ["generate", "--continue"])
|
|
1390
|
+
assert result.exit_code == 0, result.output
|
|
1391
|
+
|
|
1392
|
+
st_after = state_module.load_state(cg / "state.json")
|
|
1393
|
+
assert st_after.cycles[0].status == "open"
|
|
1394
|
+
assert st_after.last_error is None
|
|
1395
|
+
assert captured == [{"start_cycle": 1, "start_phase": 2}]
|
|
1396
|
+
|
|
1397
|
+
def test_continue_resets_only_target_cycle_when_cycle_flag_set(
|
|
1398
|
+
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
1399
|
+
) -> None:
|
|
1400
|
+
"""--continue --cycle 2 resets cycle 2 only, leaves cycle 1 failed."""
|
|
1401
|
+
monkeypatch.chdir(tmp_path)
|
|
1402
|
+
|
|
1403
|
+
cg = tmp_path / ".code-generator"
|
|
1404
|
+
cg.mkdir(parents=True, exist_ok=True)
|
|
1405
|
+
st = state_module.State(
|
|
1406
|
+
mode="multi-cycle", # type: ignore[arg-type]
|
|
1407
|
+
started_at="2026-01-01T00:00:00Z",
|
|
1408
|
+
updated_at="2026-01-01T00:00:00Z",
|
|
1409
|
+
current_cycle=2,
|
|
1410
|
+
phase=None,
|
|
1411
|
+
cycles=[
|
|
1412
|
+
_make_cycle(cycle_id=1, phase=3, status="failed"),
|
|
1413
|
+
_make_cycle(cycle_id=2, phase=4, status="failed"),
|
|
1414
|
+
],
|
|
1415
|
+
)
|
|
1416
|
+
state_module.save_state(cg / "state.json", st)
|
|
1417
|
+
|
|
1418
|
+
async def mock_multi(*_args, **_kwargs):
|
|
1419
|
+
return None
|
|
1420
|
+
|
|
1421
|
+
from code_generator.orchestrator import cycle_loop
|
|
1422
|
+
|
|
1423
|
+
monkeypatch.setattr(cycle_loop, "run_multi_cycle", mock_multi)
|
|
1424
|
+
_mock_phase0_single(monkeypatch)
|
|
1425
|
+
|
|
1426
|
+
result = runner.invoke(
|
|
1427
|
+
app, ["generate", "--continue", "--cycle", "2", "--mode", "multi-cycle"]
|
|
1428
|
+
)
|
|
1429
|
+
assert result.exit_code == 0, result.output
|
|
1430
|
+
|
|
1431
|
+
st_after = state_module.load_state(cg / "state.json")
|
|
1432
|
+
assert st_after.cycles[0].status == "failed"
|
|
1433
|
+
assert st_after.cycles[1].status == "open"
|
|
1434
|
+
|
|
1435
|
+
def test_continue_without_failed_cycles_is_noop_on_reset(
|
|
1436
|
+
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
1437
|
+
) -> None:
|
|
1438
|
+
"""--continue on a state with no failed cycles does not mutate status."""
|
|
1439
|
+
monkeypatch.chdir(tmp_path)
|
|
1440
|
+
|
|
1441
|
+
cg = tmp_path / ".code-generator"
|
|
1442
|
+
cg.mkdir(parents=True, exist_ok=True)
|
|
1443
|
+
st = state_module.State(
|
|
1444
|
+
mode="multi-cycle", # type: ignore[arg-type]
|
|
1445
|
+
started_at="2026-01-01T00:00:00Z",
|
|
1446
|
+
updated_at="2026-01-01T00:00:00Z",
|
|
1447
|
+
current_cycle=1,
|
|
1448
|
+
phase=None,
|
|
1449
|
+
cycles=[_make_cycle(cycle_id=1, phase=3, status="open")],
|
|
1450
|
+
)
|
|
1451
|
+
state_module.save_state(cg / "state.json", st)
|
|
1452
|
+
|
|
1453
|
+
async def mock_multi(*_args, **_kwargs):
|
|
1454
|
+
return None
|
|
1455
|
+
|
|
1456
|
+
from code_generator.orchestrator import cycle_loop
|
|
1457
|
+
|
|
1458
|
+
monkeypatch.setattr(cycle_loop, "run_multi_cycle", mock_multi)
|
|
1459
|
+
_mock_phase0_single(monkeypatch)
|
|
1460
|
+
|
|
1461
|
+
result = runner.invoke(app, ["generate", "--continue"])
|
|
1462
|
+
assert result.exit_code == 0, result.output
|
|
1463
|
+
|
|
1464
|
+
st_after = state_module.load_state(cg / "state.json")
|
|
1465
|
+
assert st_after.cycles[0].status == "open"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/__init__.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/_detect.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/_resume.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/generate.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/init.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/optimize.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/review.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/commands/status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/gh/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/gh/milestones.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/logging_setup.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/prompts/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/options.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/protocol.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/rate_limit.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/retry.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/sdk_runner.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/types.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/runner/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/__init__.py
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/angular.md
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/base.md
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/fastapi.md
RENAMED
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/finance.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/src/code_generator/templates/nestjs.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_cycle_loop_multicycle.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_phase_token_logging.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.2.0 → claude_code_generator-0.2.2}/tests/test_requirements_structure.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|