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
code_generator/state.py
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Atomic state persistence for the code-generator orchestrator.
|
|
2
|
+
|
|
3
|
+
State is serialized to JSON and written via a tmp-file + os.replace() pattern
|
|
4
|
+
so a crash mid-write cannot corrupt the existing state file.
|
|
5
|
+
|
|
6
|
+
Non-negotiables #5 (wait-and-resume) and #7 (atomic writes).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import dataclasses
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import time
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from datetime import UTC, datetime
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Literal
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class IssueState:
|
|
21
|
+
"""Lightweight record for a single GitHub issue within a phase."""
|
|
22
|
+
|
|
23
|
+
number: int
|
|
24
|
+
status: Literal["open", "closed"]
|
|
25
|
+
agent: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class CycleState:
|
|
30
|
+
"""State for one generation cycle (maps 1-to-1 with a GitHub Milestone)."""
|
|
31
|
+
|
|
32
|
+
id: int
|
|
33
|
+
name: str
|
|
34
|
+
milestone_number: int | None
|
|
35
|
+
milestone_title: str
|
|
36
|
+
status: str
|
|
37
|
+
phase: int
|
|
38
|
+
issues: list[IssueState]
|
|
39
|
+
commit_sha: str | None
|
|
40
|
+
depends_on: list[int] = field(default_factory=list)
|
|
41
|
+
scope: str = ""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class State:
|
|
46
|
+
"""Root state object persisted to .code-generator/state.json."""
|
|
47
|
+
|
|
48
|
+
mode: Literal["single", "multi-cycle", "unknown"]
|
|
49
|
+
started_at: str
|
|
50
|
+
updated_at: str
|
|
51
|
+
current_cycle: int | None = None
|
|
52
|
+
cycles: list[CycleState] = field(default_factory=list)
|
|
53
|
+
phase: int | None = None
|
|
54
|
+
issues: list[IssueState] = field(default_factory=list)
|
|
55
|
+
session_id: str | None = None
|
|
56
|
+
paused_until: int | None = None
|
|
57
|
+
rate_limit_type: str | None = None
|
|
58
|
+
last_error: str | None = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _utc_now() -> str:
|
|
62
|
+
return datetime.now(tz=UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _issue_from_dict(d: dict) -> IssueState: # type: ignore[type-arg]
|
|
66
|
+
return IssueState(number=d["number"], status=d["status"], agent=d["agent"])
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _cycle_from_dict(d: dict) -> CycleState: # type: ignore[type-arg]
|
|
70
|
+
return CycleState(
|
|
71
|
+
id=d["id"],
|
|
72
|
+
name=d["name"],
|
|
73
|
+
milestone_number=d.get("milestone_number"),
|
|
74
|
+
milestone_title=d["milestone_title"],
|
|
75
|
+
status=d["status"],
|
|
76
|
+
phase=d["phase"],
|
|
77
|
+
issues=[_issue_from_dict(i) for i in d.get("issues", [])],
|
|
78
|
+
commit_sha=d.get("commit_sha"),
|
|
79
|
+
depends_on=d.get("depends_on", []),
|
|
80
|
+
scope=d.get("scope", ""),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def load_state(path: Path) -> State:
|
|
85
|
+
"""Load state from path, or return a fresh default when the file is missing.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
path: Location of state.json (need not exist).
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Deserialized State, or a default single-mode State if the file is absent.
|
|
92
|
+
"""
|
|
93
|
+
if not path.exists():
|
|
94
|
+
now = _utc_now()
|
|
95
|
+
return State(mode="unknown", started_at=now, updated_at=now)
|
|
96
|
+
|
|
97
|
+
raw = json.loads(path.read_text(encoding="utf-8"))
|
|
98
|
+
return State(
|
|
99
|
+
mode=raw["mode"],
|
|
100
|
+
started_at=raw["started_at"],
|
|
101
|
+
updated_at=raw["updated_at"],
|
|
102
|
+
current_cycle=raw.get("current_cycle"),
|
|
103
|
+
cycles=[_cycle_from_dict(c) for c in raw.get("cycles", [])],
|
|
104
|
+
phase=raw.get("phase"),
|
|
105
|
+
issues=[_issue_from_dict(i) for i in raw.get("issues", [])],
|
|
106
|
+
session_id=raw.get("session_id"),
|
|
107
|
+
paused_until=raw.get("paused_until"),
|
|
108
|
+
rate_limit_type=raw.get("rate_limit_type"),
|
|
109
|
+
last_error=raw.get("last_error"),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def save_state(path: Path, state: State) -> None:
|
|
114
|
+
"""Atomically persist state to path.
|
|
115
|
+
|
|
116
|
+
Updates state.updated_at, serializes to JSON with 2-space indentation,
|
|
117
|
+
writes to a sibling .tmp file, then replaces the target via os.replace()
|
|
118
|
+
so no partial write is ever visible.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
path: Destination for state.json.
|
|
122
|
+
state: State object to persist.
|
|
123
|
+
"""
|
|
124
|
+
state.updated_at = _utc_now()
|
|
125
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
126
|
+
|
|
127
|
+
tmp = Path(str(path) + ".tmp")
|
|
128
|
+
data = json.dumps(dataclasses.asdict(state), indent=2)
|
|
129
|
+
tmp.write_text(data, encoding="utf-8")
|
|
130
|
+
os.replace(tmp, path)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def mark_paused(
|
|
134
|
+
state: State,
|
|
135
|
+
*,
|
|
136
|
+
resets_at: int,
|
|
137
|
+
rate_limit_type: str,
|
|
138
|
+
session_id: str | None,
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Record a rate-limit pause in the state object (in-memory only).
|
|
141
|
+
|
|
142
|
+
Caller must call save_state() afterwards to persist.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
state: State to mutate.
|
|
146
|
+
resets_at: Unix timestamp when the rate-limit window resets.
|
|
147
|
+
rate_limit_type: Identifier for the type of rate limit hit.
|
|
148
|
+
session_id: SDK session ID to resume from, if available.
|
|
149
|
+
"""
|
|
150
|
+
state.paused_until = resets_at
|
|
151
|
+
state.rate_limit_type = rate_limit_type
|
|
152
|
+
state.session_id = session_id
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def clear_pause(state: State) -> None:
|
|
156
|
+
"""Clear pause fields after the rate-limit window has passed.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
state: State to mutate in place.
|
|
160
|
+
"""
|
|
161
|
+
state.paused_until = None
|
|
162
|
+
state.rate_limit_type = None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def is_paused(state: State, *, now: float | None = None) -> bool:
|
|
166
|
+
"""Return True when the state indicates an active rate-limit pause.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
state: State to inspect.
|
|
170
|
+
now: Override for the current time (seconds since epoch). Defaults to
|
|
171
|
+
time.time() when omitted.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
True if paused_until is set and lies in the future.
|
|
175
|
+
"""
|
|
176
|
+
if state.paused_until is None:
|
|
177
|
+
return False
|
|
178
|
+
return state.paused_until > (now if now is not None else time.time())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Template files for `code-generator init`."""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
## Pages and Routing
|
|
3
|
+
<!-- List the main routes -->
|
|
4
|
+
| Path | Component | Description |
|
|
5
|
+
|------|-----------|-------------|
|
|
6
|
+
| / | HomePage | ... |
|
|
7
|
+
|
|
8
|
+
## State and Data
|
|
9
|
+
<!-- How to manage state: signals, ngrx, service-based -->
|
|
10
|
+
|
|
11
|
+
## Design System
|
|
12
|
+
<!-- Tailwind / Material / custom, color palette, typography -->
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Project Name
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
<!-- Describe the project in 2-3 sentences: what it does, for whom, why -->
|
|
5
|
+
|
|
6
|
+
## Tech Stack
|
|
7
|
+
<!-- The tool uses this information to select the right agents -->
|
|
8
|
+
- **Language**: [Python / TypeScript / ...]
|
|
9
|
+
- **Framework**: [FastAPI / Angular / NestJS / ...]
|
|
10
|
+
- **Database**: [PostgreSQL / Supabase / MongoDB / none]
|
|
11
|
+
- **Deploy**: [Fly.io / Vercel / Docker / local]
|
|
12
|
+
- **Tests**: [pytest / vitest / jest / ...]
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
<!-- List the features. Each entry becomes a GitHub Issue -->
|
|
16
|
+
1. ...
|
|
17
|
+
2. ...
|
|
18
|
+
3. ...
|
|
19
|
+
|
|
20
|
+
## Non-functional Requirements
|
|
21
|
+
<!-- Performance, security, scalability, accessibility -->
|
|
22
|
+
- ...
|
|
23
|
+
|
|
24
|
+
## Project Structure
|
|
25
|
+
<!-- Optional: folder structure preferences -->
|
|
26
|
+
|
|
27
|
+
## Additional Notes
|
|
28
|
+
<!-- Particular constraints, external integrations, third-party APIs -->
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
## API Endpoints
|
|
3
|
+
<!-- List the REST endpoints: method, path, description -->
|
|
4
|
+
| Method | Path | Description |
|
|
5
|
+
|--------|------|-------------|
|
|
6
|
+
| GET | /api/v1/... | ... |
|
|
7
|
+
|
|
8
|
+
## Database Models
|
|
9
|
+
<!-- List the main entities and their relationships -->
|
|
10
|
+
|
|
11
|
+
## Authentication
|
|
12
|
+
<!-- JWT / OAuth2 / API key / none -->
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
## API Endpoints
|
|
3
|
+
<!-- List the REST endpoints: method, path, description -->
|
|
4
|
+
| Method | Path | Description |
|
|
5
|
+
|--------|------|-------------|
|
|
6
|
+
| GET | /api/v1/... | ... |
|
|
7
|
+
|
|
8
|
+
## Database Models
|
|
9
|
+
<!-- List the main entities and their relationships -->
|
|
10
|
+
|
|
11
|
+
## Authentication
|
|
12
|
+
<!-- JWT / OAuth2 / API key / none -->
|
|
13
|
+
|
|
14
|
+
## Pages and Routing
|
|
15
|
+
<!-- List the main routes -->
|
|
16
|
+
| Path | Component | Description |
|
|
17
|
+
|------|-----------|-------------|
|
|
18
|
+
| / | HomePage | ... |
|
|
19
|
+
|
|
20
|
+
## State and Data
|
|
21
|
+
<!-- How to manage state: signals, ngrx, service-based -->
|
|
22
|
+
|
|
23
|
+
## Design System
|
|
24
|
+
<!-- Tailwind / Material / custom, color palette, typography -->
|