claude-code-generator 0.4.11__tar.gz → 0.4.12__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.
Files changed (182) hide show
  1. {claude_code_generator-0.4.11/src/claude_code_generator.egg-info → claude_code_generator-0.4.12}/PKG-INFO +1 -1
  2. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/pyproject.toml +1 -1
  3. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12/src/claude_code_generator.egg-info}/PKG-INFO +1 -1
  4. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/__init__.py +1 -1
  5. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/phase1_plan.py +95 -21
  6. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase1.py +97 -0
  7. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/LICENSE +0 -0
  8. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/README.md +0 -0
  9. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/setup.cfg +0 -0
  10. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/claude_code_generator.egg-info/SOURCES.txt +0 -0
  11. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/claude_code_generator.egg-info/dependency_links.txt +0 -0
  12. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/claude_code_generator.egg-info/entry_points.txt +0 -0
  13. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/claude_code_generator.egg-info/requires.txt +0 -0
  14. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/claude_code_generator.egg-info/top_level.txt +0 -0
  15. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/agents.py +0 -0
  16. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/cli.py +0 -0
  17. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/__init__.py +0 -0
  18. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/_bench_io.py +0 -0
  19. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/_crash_recovery.py +0 -0
  20. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/_detect.py +0 -0
  21. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/_dispatch.py +0 -0
  22. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/_resume.py +0 -0
  23. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/_validators.py +0 -0
  24. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/bench.py +0 -0
  25. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/bench_compare.py +0 -0
  26. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/bench_export.py +0 -0
  27. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/generate.py +0 -0
  28. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/init.py +0 -0
  29. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/optimize.py +0 -0
  30. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/review.py +0 -0
  31. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/commands/status.py +0 -0
  32. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/effort.py +0 -0
  33. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/env.py +0 -0
  34. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/gh/__init__.py +0 -0
  35. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/gh/core.py +0 -0
  36. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/gh/issues.py +0 -0
  37. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/gh/labels.py +0 -0
  38. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/gh/milestones.py +0 -0
  39. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/git_ops.py +0 -0
  40. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/logging_setup.py +0 -0
  41. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/memory.py +0 -0
  42. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/__init__.py +0 -0
  43. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/_client_lifecycle.py +0 -0
  44. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/_comments.py +0 -0
  45. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/_memory_writers.py +0 -0
  46. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/_phase5_precommit.py +0 -0
  47. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/cycle_loop.py +0 -0
  48. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/cycle_prompts.py +0 -0
  49. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/ollama_budget.py +0 -0
  50. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/phase0_complexity.py +0 -0
  51. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/phase2_review.py +0 -0
  52. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/phase3_4_implement.py +0 -0
  53. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/phase5_closure.py +0 -0
  54. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/phase6_test.py +0 -0
  55. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/orchestrator/phase7_commit.py +0 -0
  56. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/preflight.py +0 -0
  57. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/__init__.py +0 -0
  58. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/hashes.py +0 -0
  59. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-cycle-specializer.md +0 -0
  60. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-optimize-requirements.md +0 -0
  61. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-0-complexity.md +0 -0
  62. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-1-planning.md +0 -0
  63. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-2-batch-review.md +0 -0
  64. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-2-issue-review.md +0 -0
  65. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-3-implementation.md +0 -0
  66. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-5-final-review.md +0 -0
  67. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-6-test.md +0 -0
  68. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-phase-7-commit.md +0 -0
  69. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/prompts/prompt-review.md +0 -0
  70. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/repo_info.py +0 -0
  71. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/repomap.py +0 -0
  72. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/requirements_structure.py +0 -0
  73. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/__init__.py +0 -0
  74. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/_telemetry.py +0 -0
  75. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/batch.py +0 -0
  76. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/fake_runner.py +0 -0
  77. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/mcp.py +0 -0
  78. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/message_parsing.py +0 -0
  79. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/options.py +0 -0
  80. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/protocol.py +0 -0
  81. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/rate_limit.py +0 -0
  82. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/retry.py +0 -0
  83. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/sdk_runner.py +0 -0
  84. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/soft_reset.py +0 -0
  85. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/state_guard.py +0 -0
  86. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/subprocess_runner.py +0 -0
  87. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/types.py +0 -0
  88. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/runner/utils.py +0 -0
  89. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/state.py +0 -0
  90. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/state_retention.py +0 -0
  91. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/__init__.py +0 -0
  92. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/angular.md +0 -0
  93. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/base.md +0 -0
  94. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/fastapi.md +0 -0
  95. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/finance.md +0 -0
  96. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/fullstack.md +0 -0
  97. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/nestjs.md +0 -0
  98. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/src/code_generator/templates/python-cli.md +0 -0
  99. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_agents.py +0 -0
  100. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_bench.py +0 -0
  101. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_bench_compare.py +0 -0
  102. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_bench_export.py +0 -0
  103. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_bench_fixture.py +0 -0
  104. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_bench_regression.py +0 -0
  105. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_changelog.py +0 -0
  106. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_claude_md.py +0 -0
  107. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_client_lifecycle.py +0 -0
  108. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_comments.py +0 -0
  109. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_commit_message.py +0 -0
  110. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_crash_recovery.py +0 -0
  111. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_cycle_loop.py +0 -0
  112. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_cycle_loop_multicycle.py +0 -0
  113. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_cycle_ollama_model.py +0 -0
  114. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_cycle_prompts.py +0 -0
  115. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_delta_planning.py +0 -0
  116. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_dependencies.py +0 -0
  117. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_detect.py +0 -0
  118. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_docs_no_default_max_turns.py +0 -0
  119. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_docs_ollama_model_guide.py +0 -0
  120. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_docs_ollama_pro.py +0 -0
  121. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_effective_model_routing.py +0 -0
  122. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_effort.py +0 -0
  123. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_env.py +0 -0
  124. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_generate.py +0 -0
  125. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_generate_ollama.py +0 -0
  126. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_generate_resume.py +0 -0
  127. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_gh.py +0 -0
  128. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_gh_labels.py +0 -0
  129. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_gh_milestones.py +0 -0
  130. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_gh_repo_threading.py +0 -0
  131. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_gh_submodules.py +0 -0
  132. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_git_ops.py +0 -0
  133. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_init.py +0 -0
  134. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_logging_setup.py +0 -0
  135. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_max_turns_cli_flag.py +0 -0
  136. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_mcp.py +0 -0
  137. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_memory.py +0 -0
  138. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_memory_writers.py +0 -0
  139. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_message_parsing.py +0 -0
  140. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_no_max_turns_in_call_sites.py +0 -0
  141. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_no_max_turns_literal.py +0 -0
  142. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_non_goals_grep_guard.py +0 -0
  143. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_ollama_budget.py +0 -0
  144. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_ollama_rate_limit.py +0 -0
  145. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_optimize.py +0 -0
  146. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_options.py +0 -0
  147. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase0.py +0 -0
  148. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase2.py +0 -0
  149. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase2_batch.py +0 -0
  150. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase3_4.py +0 -0
  151. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase5.py +0 -0
  152. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase5_precommit.py +0 -0
  153. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase6.py +0 -0
  154. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase7.py +0 -0
  155. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase_mcp_regression.py +0 -0
  156. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_phase_token_logging.py +0 -0
  157. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_preflight.py +0 -0
  158. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_preflight_ollama.py +0 -0
  159. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_prompt_drift.py +0 -0
  160. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_prompt_prefix_snapshots.py +0 -0
  161. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_prompt_prefix_stability.py +0 -0
  162. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_prompts.py +0 -0
  163. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_rate_limit.py +0 -0
  164. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_repo_info.py +0 -0
  165. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_repomap.py +0 -0
  166. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_requirements_structure.py +0 -0
  167. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_retry.py +0 -0
  168. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_review.py +0 -0
  169. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_runner_protocol.py +0 -0
  170. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_runner_protocol_annotations.py +0 -0
  171. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_runner_types.py +0 -0
  172. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_runner_utils.py +0 -0
  173. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_sdk_runner.py +0 -0
  174. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_sdk_runner_shared.py +0 -0
  175. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_session_mode.py +0 -0
  176. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_state.py +0 -0
  177. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_state_guard.py +0 -0
  178. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_state_retention.py +0 -0
  179. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_status.py +0 -0
  180. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_subprocess_runner.py +0 -0
  181. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/tests/test_telemetry.py +0 -0
  182. {claude_code_generator-0.4.11 → claude_code_generator-0.4.12}/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.4.11
3
+ Version: 0.4.12
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "claude-code-generator"
7
- version = "0.4.11"
7
+ version = "0.4.12"
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.4.11
3
+ Version: 0.4.12
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
@@ -1,3 +1,3 @@
1
1
  """code-generator: orchestrator CLI for end-to-end project generation."""
2
2
 
3
- __version__ = "0.4.11"
3
+ __version__ = "0.4.12"
@@ -116,6 +116,47 @@ _PHASE1_DEFAULT_MODEL = "claude-opus-4-7"
116
116
  # CLAUDE.md invariant #8; overridden via ``effective_model`` on Ollama — #219.
117
117
 
118
118
 
119
+ _PHASE1_MAX_ATTEMPTS = 3
120
+ """Max planning attempts before surfacing ``Phase1NoIssuesError`` (0.4.12).
121
+
122
+ Weak open models on the Ollama codepath often respond with prose describing
123
+ the plan instead of invoking ``gh issue create`` via the Bash tool. A single
124
+ stricter re-prompt is usually enough to unblock them without operator
125
+ intervention.
126
+ """
127
+
128
+
129
+ _PHASE1_RETRY_NUDGE = (
130
+ "Your previous attempt finished without creating any GitHub issues. "
131
+ "This is a CRITICAL failure. You MUST use the Bash tool to invoke "
132
+ "`gh issue create` for each issue right now. Do NOT output markdown "
133
+ "or prose describing the plan — every planned issue must become a "
134
+ "real GitHub issue via `gh issue create ... --milestone "
135
+ '"{MILESTONE}" --assignee @me --label "..."`. Once you have called '
136
+ "`gh issue create` for every planned issue, print a one-line summary "
137
+ "per issue and stop.\n\n"
138
+ "The original instructions follow.\n\n"
139
+ )
140
+
141
+
142
+ def _accumulate_usage(
143
+ total: _state.TokenUsage | None,
144
+ delta: _state.TokenUsage,
145
+ ) -> _state.TokenUsage:
146
+ """Sum two TokenUsage records field-by-field across Phase 1 attempts."""
147
+ from code_generator.runner.types import TokenUsage
148
+
149
+ if total is None:
150
+ return delta
151
+ return TokenUsage(
152
+ input=total.input + delta.input,
153
+ output=total.output + delta.output,
154
+ cache_read=total.cache_read + delta.cache_read,
155
+ cache_write=total.cache_write + delta.cache_write,
156
+ num_turns=total.num_turns + delta.num_turns,
157
+ )
158
+
159
+
119
160
  def _load_specialized_prompt(
120
161
  project_dir: Path,
121
162
  state: State,
@@ -249,28 +290,56 @@ async def run(
249
290
  **max_turns_kwargs(max_turns),
250
291
  )
251
292
 
252
- result = await rate_limit.main_loop(
253
- runner_module,
254
- prompt,
255
- options,
256
- state_path=state_path,
257
- logger=logger,
258
- )
293
+ # Up to _PHASE1_MAX_ATTEMPTS attempts: the first with the normal
294
+ # prompt, subsequent attempts prefixed with a stricter nudge that
295
+ # tells the model to use the Bash tool to call ``gh issue create``
296
+ # right now. Weak open models on the Ollama codepath commonly
297
+ # respond with prose on the first turn; the nudge recovers most
298
+ # of those cases without operator intervention (0.4.12).
299
+ issue_states: list[_state.IssueState] = []
300
+ total_usage = result = None # type: ignore[assignment]
301
+ attempt_prompt = prompt
302
+ effective_model_name = effective_model or _PHASE1_DEFAULT_MODEL
303
+ for attempt in range(1, _PHASE1_MAX_ATTEMPTS + 1):
304
+ result = await rate_limit.main_loop(
305
+ runner_module,
306
+ attempt_prompt,
307
+ options,
308
+ state_path=state_path,
309
+ logger=logger,
310
+ )
311
+ total_usage = _accumulate_usage(total_usage, result.usage)
259
312
 
260
- # Fetch all issues in the milestone (open + closed) to support deduplication.
261
- raw_issues = gh.list_issues(
262
- repo,
263
- milestone=milestone_title,
264
- state="all",
265
- )
266
- issue_states = _build_issue_states(raw_issues)
313
+ raw_issues = gh.list_issues(
314
+ repo,
315
+ milestone=milestone_title,
316
+ state="all",
317
+ )
318
+ issue_states = _build_issue_states(raw_issues)
319
+ if issue_states:
320
+ break
321
+
322
+ if attempt >= _PHASE1_MAX_ATTEMPTS:
323
+ break
324
+
325
+ logger.warning(
326
+ "Phase 1 attempt %d/%d: model returned without creating any "
327
+ "GitHub issues. Re-prompting with a stricter nudge.",
328
+ attempt,
329
+ _PHASE1_MAX_ATTEMPTS,
330
+ )
331
+ nudge = _PHASE1_RETRY_NUDGE.replace("{MILESTONE}", milestone_title or "")
332
+ attempt_prompt = nudge + prompt
267
333
 
268
334
  if not issue_states:
269
335
  raise Phase1NoIssuesError(
270
- "Phase 1 finished without creating any GitHub issues. "
271
- "Opus likely misread the task (e.g. audited existing code instead "
272
- "of planning new work). Inspect .code-generator/logs/phase1.log, "
273
- "adjust prompt-phase-1-planning.md if needed, and re-run."
336
+ f"Phase 1 finished without creating any GitHub issues after "
337
+ f"{_PHASE1_MAX_ATTEMPTS} attempts (model={effective_model_name!r}). "
338
+ "The model likely responded with prose instead of invoking "
339
+ "`gh issue create` via the Bash tool. Inspect "
340
+ ".code-generator/logs/phase1.log for the tool-call trace, "
341
+ "try a stronger model, or simplify the cycle scope in "
342
+ "requirements.md and re-run."
274
343
  )
275
344
 
276
345
  target = cycle if cycle is not None else state
@@ -278,12 +347,17 @@ async def run(
278
347
  cycle.issues = issue_states
279
348
  else:
280
349
  state.issues = issue_states
281
- target.token_usage["phase1"] = result.usage
350
+ # Persist the accumulated usage across all attempts (not just the last).
351
+ target.token_usage["phase1"] = total_usage if total_usage is not None else result.usage
282
352
  if hasattr(target, "cache_telemetry"):
283
- accumulate_telemetry(target.cache_telemetry, result.usage, result.wall_seconds)
353
+ accumulate_telemetry(
354
+ target.cache_telemetry,
355
+ target.token_usage["phase1"],
356
+ result.wall_seconds,
357
+ )
284
358
 
285
359
  _state.save_state(state_path, state)
286
- log_phase_usage(logger, 1, result.usage)
360
+ log_phase_usage(logger, 1, target.token_usage["phase1"])
287
361
  logger.info("Phase 1: %d issues created.", len(issue_states))
288
362
 
289
363
  except Exception:
@@ -414,9 +414,71 @@ class TestBuildIssueStates:
414
414
  class TestPhase1NoIssuesError:
415
415
  @pytest.mark.asyncio
416
416
  async def test_raises_when_list_issues_returns_empty(self, tmp_path: Path) -> None:
417
+ """Three consecutive empty listings → Phase1NoIssuesError with model name."""
417
418
  state = _make_state(tmp_path)
419
+ call_count = 0
418
420
 
419
421
  async def fake_main_loop(runner, prompt, options, *, state_path, logger, **kw):
422
+ nonlocal call_count
423
+ call_count += 1
424
+ return _make_run_result()
425
+
426
+ with (
427
+ patch.object(phase1_plan.rate_limit, "main_loop", side_effect=fake_main_loop),
428
+ patch.object(phase1_plan.gh, "ensure_standard_labels"),
429
+ patch.object(phase1_plan.gh, "list_issues", return_value=[]),
430
+ ):
431
+ with pytest.raises(phase1_plan.Phase1NoIssuesError, match="3 attempts"):
432
+ await phase1_plan.run(
433
+ state,
434
+ None,
435
+ tmp_path,
436
+ runner_module=MagicMock(),
437
+ logger=logging.getLogger("test"),
438
+ )
439
+
440
+ assert call_count == phase1_plan._PHASE1_MAX_ATTEMPTS
441
+
442
+ @pytest.mark.asyncio
443
+ async def test_retry_succeeds_after_first_empty_attempt(self, tmp_path: Path) -> None:
444
+ """If the first attempt created 0 issues but the second populates them, no raise."""
445
+ state = _make_state(tmp_path)
446
+ call_count = 0
447
+ # First call → empty list; second call → real issues.
448
+ listings = [[], _raw_issues([1, 2])]
449
+
450
+ async def fake_main_loop(runner, prompt, options, *, state_path, logger, **kw):
451
+ nonlocal call_count
452
+ call_count += 1
453
+ return _make_run_result()
454
+
455
+ def fake_list_issues(*_a, **_kw):
456
+ return listings[min(call_count - 1, len(listings) - 1)]
457
+
458
+ with (
459
+ patch.object(phase1_plan.rate_limit, "main_loop", side_effect=fake_main_loop),
460
+ patch.object(phase1_plan.gh, "ensure_standard_labels"),
461
+ patch.object(phase1_plan.gh, "list_issues", side_effect=fake_list_issues),
462
+ ):
463
+ await phase1_plan.run(
464
+ state,
465
+ None,
466
+ tmp_path,
467
+ runner_module=MagicMock(),
468
+ logger=logging.getLogger("test"),
469
+ )
470
+
471
+ assert call_count == 2
472
+ assert len(state.issues) == 2
473
+
474
+ @pytest.mark.asyncio
475
+ async def test_retry_prompt_includes_strict_nudge(self, tmp_path: Path) -> None:
476
+ """Second attempt's prompt must be prefixed with the stricter nudge."""
477
+ state = _make_state(tmp_path)
478
+ captured_prompts: list[str] = []
479
+
480
+ async def fake_main_loop(runner, prompt, options, *, state_path, logger, **kw):
481
+ captured_prompts.append(prompt)
420
482
  return _make_run_result()
421
483
 
422
484
  with (
@@ -433,6 +495,41 @@ class TestPhase1NoIssuesError:
433
495
  logger=logging.getLogger("test"),
434
496
  )
435
497
 
498
+ assert len(captured_prompts) == phase1_plan._PHASE1_MAX_ATTEMPTS
499
+ # First prompt is the plain Phase 1 prompt.
500
+ assert (
501
+ "Your previous attempt finished without creating any GitHub issues"
502
+ not in (captured_prompts[0])
503
+ )
504
+ # Subsequent prompts carry the stricter nudge prefix.
505
+ for retry_prompt in captured_prompts[1:]:
506
+ assert retry_prompt.startswith(
507
+ "Your previous attempt finished without creating any GitHub issues"
508
+ )
509
+
510
+ @pytest.mark.asyncio
511
+ async def test_error_message_names_effective_model(self, tmp_path: Path) -> None:
512
+ """Ollama path: final error text must reference the operator-supplied tag."""
513
+ state = _make_state(tmp_path)
514
+
515
+ async def fake_main_loop(runner, prompt, options, *, state_path, logger, **kw):
516
+ return _make_run_result()
517
+
518
+ with (
519
+ patch.object(phase1_plan.rate_limit, "main_loop", side_effect=fake_main_loop),
520
+ patch.object(phase1_plan.gh, "ensure_standard_labels"),
521
+ patch.object(phase1_plan.gh, "list_issues", return_value=[]),
522
+ ):
523
+ with pytest.raises(phase1_plan.Phase1NoIssuesError, match="glm-5.1:cloud"):
524
+ await phase1_plan.run(
525
+ state,
526
+ None,
527
+ tmp_path,
528
+ runner_module=MagicMock(),
529
+ logger=logging.getLogger("test"),
530
+ effective_model="glm-5.1:cloud",
531
+ )
532
+
436
533
 
437
534
  # ---------------------------------------------------------------------------
438
535
  # Phase 1 idempotency — AC from issue #134