claude-code-generator 0.4.13__tar.gz → 0.4.15__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.13/src/claude_code_generator.egg-info → claude_code_generator-0.4.15}/PKG-INFO +1 -1
  2. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/pyproject.toml +1 -1
  3. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15/src/claude_code_generator.egg-info}/PKG-INFO +1 -1
  4. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/_dispatch.py +3 -0
  5. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/env.py +30 -10
  6. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/_client_lifecycle.py +15 -4
  7. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/cycle_loop.py +6 -2
  8. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/phase0_complexity.py +5 -2
  9. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/phase1_plan.py +1 -1
  10. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/phase2_review.py +1 -1
  11. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/phase3_4_implement.py +3 -2
  12. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/phase5_closure.py +1 -1
  13. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/phase7_commit.py +1 -1
  14. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/subprocess_runner.py +11 -1
  15. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/LICENSE +0 -0
  16. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/README.md +0 -0
  17. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/setup.cfg +0 -0
  18. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/claude_code_generator.egg-info/SOURCES.txt +0 -0
  19. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/claude_code_generator.egg-info/dependency_links.txt +0 -0
  20. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/claude_code_generator.egg-info/entry_points.txt +0 -0
  21. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/claude_code_generator.egg-info/requires.txt +0 -0
  22. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/claude_code_generator.egg-info/top_level.txt +0 -0
  23. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/__init__.py +0 -0
  24. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/agents.py +0 -0
  25. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/cli.py +0 -0
  26. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/__init__.py +0 -0
  27. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/_bench_io.py +0 -0
  28. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/_crash_recovery.py +0 -0
  29. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/_detect.py +0 -0
  30. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/_resume.py +0 -0
  31. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/_validators.py +0 -0
  32. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/bench.py +0 -0
  33. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/bench_compare.py +0 -0
  34. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/bench_export.py +0 -0
  35. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/generate.py +0 -0
  36. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/init.py +0 -0
  37. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/optimize.py +0 -0
  38. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/review.py +0 -0
  39. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/commands/status.py +0 -0
  40. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/effort.py +0 -0
  41. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/gh/__init__.py +0 -0
  42. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/gh/core.py +0 -0
  43. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/gh/issues.py +0 -0
  44. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/gh/labels.py +0 -0
  45. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/gh/milestones.py +0 -0
  46. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/git_ops.py +0 -0
  47. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/logging_setup.py +0 -0
  48. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/memory.py +0 -0
  49. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/__init__.py +0 -0
  50. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/_comments.py +0 -0
  51. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/_memory_writers.py +0 -0
  52. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/_phase5_precommit.py +0 -0
  53. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/cycle_prompts.py +0 -0
  54. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/ollama_budget.py +0 -0
  55. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/orchestrator/phase6_test.py +0 -0
  56. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/preflight.py +0 -0
  57. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/__init__.py +0 -0
  58. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/hashes.py +0 -0
  59. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-cycle-specializer.md +0 -0
  60. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-optimize-requirements.md +0 -0
  61. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-0-complexity.md +0 -0
  62. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-1-planning.md +0 -0
  63. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-2-batch-review.md +0 -0
  64. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-2-issue-review.md +0 -0
  65. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-3-implementation.md +0 -0
  66. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-5-final-review.md +0 -0
  67. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-6-test.md +0 -0
  68. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-phase-7-commit.md +0 -0
  69. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/prompts/prompt-review.md +0 -0
  70. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/repo_info.py +0 -0
  71. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/repomap.py +0 -0
  72. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/requirements_structure.py +0 -0
  73. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/__init__.py +0 -0
  74. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/_telemetry.py +0 -0
  75. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/batch.py +0 -0
  76. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/fake_runner.py +0 -0
  77. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/mcp.py +0 -0
  78. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/message_parsing.py +0 -0
  79. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/options.py +0 -0
  80. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/protocol.py +0 -0
  81. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/rate_limit.py +0 -0
  82. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/retry.py +0 -0
  83. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/sdk_runner.py +0 -0
  84. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/soft_reset.py +0 -0
  85. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/state_guard.py +0 -0
  86. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/types.py +0 -0
  87. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/runner/utils.py +0 -0
  88. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/state.py +0 -0
  89. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/state_retention.py +0 -0
  90. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/__init__.py +0 -0
  91. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/angular.md +0 -0
  92. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/base.md +0 -0
  93. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/fastapi.md +0 -0
  94. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/finance.md +0 -0
  95. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/fullstack.md +0 -0
  96. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/nestjs.md +0 -0
  97. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/src/code_generator/templates/python-cli.md +0 -0
  98. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_agents.py +0 -0
  99. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_bench.py +0 -0
  100. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_bench_compare.py +0 -0
  101. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_bench_export.py +0 -0
  102. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_bench_fixture.py +0 -0
  103. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_bench_regression.py +0 -0
  104. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_changelog.py +0 -0
  105. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_claude_md.py +0 -0
  106. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_client_lifecycle.py +0 -0
  107. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_comments.py +0 -0
  108. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_commit_message.py +0 -0
  109. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_crash_recovery.py +0 -0
  110. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_cycle_loop.py +0 -0
  111. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_cycle_loop_multicycle.py +0 -0
  112. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_cycle_ollama_model.py +0 -0
  113. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_cycle_prompts.py +0 -0
  114. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_delta_planning.py +0 -0
  115. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_dependencies.py +0 -0
  116. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_detect.py +0 -0
  117. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_docs_no_default_max_turns.py +0 -0
  118. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_docs_ollama_model_guide.py +0 -0
  119. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_docs_ollama_pro.py +0 -0
  120. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_effective_model_routing.py +0 -0
  121. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_effort.py +0 -0
  122. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_env.py +0 -0
  123. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_generate.py +0 -0
  124. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_generate_ollama.py +0 -0
  125. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_generate_resume.py +0 -0
  126. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_gh.py +0 -0
  127. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_gh_labels.py +0 -0
  128. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_gh_milestones.py +0 -0
  129. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_gh_repo_threading.py +0 -0
  130. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_gh_submodules.py +0 -0
  131. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_git_ops.py +0 -0
  132. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_init.py +0 -0
  133. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_logging_setup.py +0 -0
  134. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_max_turns_cli_flag.py +0 -0
  135. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_mcp.py +0 -0
  136. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_memory.py +0 -0
  137. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_memory_writers.py +0 -0
  138. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_message_parsing.py +0 -0
  139. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_no_max_turns_in_call_sites.py +0 -0
  140. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_no_max_turns_literal.py +0 -0
  141. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_non_goals_grep_guard.py +0 -0
  142. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_ollama_budget.py +0 -0
  143. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_ollama_rate_limit.py +0 -0
  144. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_optimize.py +0 -0
  145. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_options.py +0 -0
  146. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase0.py +0 -0
  147. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase1.py +0 -0
  148. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase2.py +0 -0
  149. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase2_batch.py +0 -0
  150. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase3_4.py +0 -0
  151. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase5.py +0 -0
  152. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase5_precommit.py +0 -0
  153. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase6.py +0 -0
  154. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase7.py +0 -0
  155. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase_mcp_regression.py +0 -0
  156. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_phase_token_logging.py +0 -0
  157. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_preflight.py +0 -0
  158. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_preflight_ollama.py +0 -0
  159. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_prompt_drift.py +0 -0
  160. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_prompt_prefix_snapshots.py +0 -0
  161. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_prompt_prefix_stability.py +0 -0
  162. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_prompts.py +0 -0
  163. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_rate_limit.py +0 -0
  164. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_repo_info.py +0 -0
  165. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_repomap.py +0 -0
  166. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_requirements_structure.py +0 -0
  167. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_retry.py +0 -0
  168. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_review.py +0 -0
  169. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_runner_protocol.py +0 -0
  170. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_runner_protocol_annotations.py +0 -0
  171. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_runner_types.py +0 -0
  172. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_runner_utils.py +0 -0
  173. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_sdk_runner.py +0 -0
  174. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_sdk_runner_shared.py +0 -0
  175. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_session_mode.py +0 -0
  176. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_state.py +0 -0
  177. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_state_guard.py +0 -0
  178. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_state_retention.py +0 -0
  179. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_status.py +0 -0
  180. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_subprocess_runner.py +0 -0
  181. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/tests/test_telemetry.py +0 -0
  182. {claude_code_generator-0.4.13 → claude_code_generator-0.4.15}/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.13
3
+ Version: 0.4.15
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.13"
7
+ version = "0.4.15"
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.13
3
+ Version: 0.4.15
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
@@ -106,6 +106,7 @@ async def _apply_delta_plan(
106
106
  delta_hash: str,
107
107
  state_path: Path,
108
108
  logger: logging.Logger,
109
+ effective_model: str | None = None,
109
110
  ) -> int | None:
110
111
  """Run Phase 0 and merge new cycles into state for multi-cycle delta planning.
111
112
 
@@ -135,6 +136,7 @@ async def _apply_delta_plan(
135
136
  project_dir,
136
137
  runner_module=runner_module, # type: ignore[arg-type]
137
138
  logger=logger,
139
+ effective_model=effective_model,
138
140
  )
139
141
 
140
142
  if raw_cycles is None:
@@ -214,6 +216,7 @@ async def dispatch_async(
214
216
  delta_hash=delta_hash,
215
217
  state_path=state_path,
216
218
  logger=logger,
219
+ effective_model=ollama_model,
217
220
  )
218
221
  if first_new_id is None:
219
222
  return # No new cycles — nothing to run.
@@ -48,7 +48,17 @@ def strip_dangerous_env() -> None:
48
48
  (``sdk_runner.run``, ``run_with_shared_client``).
49
49
  """
50
50
  ollama_mode = _is_localhost_base_url(os.environ.get("ANTHROPIC_BASE_URL"))
51
- protected = {"ANTHROPIC_AUTH_TOKEN"} if ollama_mode else set()
51
+ # On the Ollama codepath, ANTHROPIC_AUTH_TOKEN carries the daemon token
52
+ # and must survive stripping. ANTHROPIC_API_KEY is also protected when it
53
+ # has been set to "" by assert_safe_environment_ollama() — the empty-string
54
+ # sentinel tells the SDK to accept non-Claude model tags. A non-empty
55
+ # ANTHROPIC_API_KEY (e.g. "sk-evil") is still stripped because it would
56
+ # route traffic to Anthropic's real API, defeating the localhost redirect.
57
+ protected: set[str] = set()
58
+ if ollama_mode:
59
+ protected.add("ANTHROPIC_AUTH_TOKEN")
60
+ if os.environ.get("ANTHROPIC_API_KEY") == "":
61
+ protected.add("ANTHROPIC_API_KEY")
52
62
  for var in DANGEROUS_VARS:
53
63
  if var in protected:
54
64
  continue
@@ -116,7 +126,7 @@ def _require_ollama_preconditions() -> str:
116
126
 
117
127
  Refuses the bypass when:
118
128
  * ``OLLAMA_API_KEY`` is unset or empty.
119
- * ``ANTHROPIC_BASE_URL`` is pre-set to anything other than the pinned URL.
129
+ * ``ANTHROPIC_BASE_URL`` is pre-set to a non-localhost value.
120
130
 
121
131
  A non-empty ``ANTHROPIC_API_KEY`` in the parent env is **not** a refusal:
122
132
  ``_build_ollama_env`` strips every ``ANTHROPIC_*`` var from the returned
@@ -132,10 +142,10 @@ def _require_ollama_preconditions() -> str:
132
142
  "before running with provider='ollama'."
133
143
  )
134
144
  preset_base = os.environ.get("ANTHROPIC_BASE_URL")
135
- if preset_base and preset_base != OLLAMA_BASE_URL:
145
+ if preset_base and not _is_localhost_base_url(preset_base):
136
146
  raise RuntimeError(
137
- f"ANTHROPIC_BASE_URL={preset_base!r} does not match the pinned "
138
- f"{OLLAMA_BASE_URL!r}. Unset it or point it at the local daemon."
147
+ f"ANTHROPIC_BASE_URL={preset_base!r} does not point at a local "
148
+ f"daemon. Unset it or point it at localhost/127.0.0.1."
139
149
  )
140
150
  return token
141
151
 
@@ -222,14 +232,24 @@ def assert_single_workspace(
222
232
  )
223
233
 
224
234
 
235
+ _LOCALHOST_PREFIXES: tuple[str, ...] = (
236
+ "http://localhost:",
237
+ "http://127.0.0.1:",
238
+ "http://[::1]:",
239
+ )
240
+
241
+
225
242
  def _is_localhost_base_url(base_url: str | None) -> bool:
226
243
  """Return True when the ANTHROPIC_BASE_URL points at any localhost port.
227
244
 
228
- Deliberately lenient — any ``http://localhost:*`` prefix matches — because
229
- the workspace invariant is \"local endpoint\", not the strict :11434 the
230
- Ollama preflight refusal gate enforces.
245
+ Deliberately lenient — ``http://localhost:*``, ``http://127.0.0.1:*``,
246
+ and ``http://[::1]:*`` all match because the workspace invariant is
247
+ \"local endpoint\", not the strict :11434 the Ollama preflight refusal
248
+ gate enforces.
231
249
  """
232
- return base_url is not None and base_url.startswith("http://localhost:")
250
+ if base_url is None:
251
+ return False
252
+ return any(base_url.startswith(prefix) for prefix in _LOCALHOST_PREFIXES)
233
253
 
234
254
 
235
255
  def _log_localhost_short_circuit_once(state: dict[str, object]) -> None:
@@ -302,7 +322,7 @@ def assert_safe_environment_ollama() -> None:
302
322
  preset_base = os.environ.get("ANTHROPIC_BASE_URL")
303
323
  if not token:
304
324
  return
305
- if preset_base and preset_base != OLLAMA_BASE_URL:
325
+ if preset_base and not _is_localhost_base_url(preset_base):
306
326
  return
307
327
 
308
328
  os.environ["ANTHROPIC_AUTH_TOKEN"] = token
@@ -92,12 +92,15 @@ def _open_cycle_client(options_template: Any) -> Any:
92
92
  return ClaudeSDKClient(options=options_template)
93
93
 
94
94
 
95
- def _build_cycle_options(project_dir: Path) -> Any:
95
+ def _build_cycle_options(project_dir: Path, effective_model: str | None = None) -> Any:
96
96
  """Return cycle-scoped options for the shared ``ClaudeSDKClient``.
97
97
 
98
98
  ``ClaudeSDKClient`` locks options at open-time — per-query changes do not
99
99
  apply. The shared client therefore opens with:
100
100
 
101
+ - ``model``: the effective Ollama model tag (when on the Ollama codepath),
102
+ or ``None`` to let the SDK default (Anthropic Max path). Must be set at
103
+ open-time because per-query overrides are silently ignored.
101
104
  - ``system_prompt``: canonical ``claude_code`` preset with
102
105
  ``exclude_dynamic_sections=True`` (§2 cache-safe prefix).
103
106
  - ``extra_headers``: default betas (extended-cache-ttl + token-efficient-tools).
@@ -114,6 +117,9 @@ def _build_cycle_options(project_dir: Path) -> Any:
114
117
 
115
118
  Args:
116
119
  project_dir: Project root; used to resolve MCP servers.
120
+ effective_model: Ollama model tag to lock into the shared client
121
+ (threaded from cycle_loop). When ``None``, the SDK default
122
+ (Anthropic Max path) is used.
117
123
 
118
124
  Returns:
119
125
  A ``ClaudeAgentOptions`` instance (or duck-typed fallback) suitable
@@ -121,15 +127,18 @@ def _build_cycle_options(project_dir: Path) -> Any:
121
127
  """
122
128
  mcp_servers = build_mcp_servers(project_dir)
123
129
  allowed_tools: list[str] = list(_SHARED_CLIENT_ALLOWED_TOOLS) + mcp_tool_wildcards(mcp_servers)
124
- return make_agent_options(
130
+ kwargs: dict[str, Any] = dict(
125
131
  allowed_tools=allowed_tools,
126
132
  permission_mode="bypassPermissions",
127
133
  mcp_servers=mcp_servers,
128
134
  )
135
+ if effective_model is not None:
136
+ kwargs["model"] = effective_model
137
+ return make_agent_options(**kwargs)
129
138
 
130
139
 
131
140
  @contextlib.asynccontextmanager
132
- async def managed_shared_client(state: State, state_path: Path): # type: ignore[return]
141
+ async def managed_shared_client(state: State, state_path: Path, effective_model: str | None = None): # type: ignore[return]
133
142
  """Async context manager owning the full shared-client lifecycle.
134
143
 
135
144
  On entry: strips dangerous env vars (non-negotiable #1), opens one
@@ -151,6 +160,8 @@ async def managed_shared_client(state: State, state_path: Path): # type: ignore
151
160
  Args:
152
161
  state: Root state (mutated by mark/clear helpers).
153
162
  state_path: Path to ``state.json`` for atomic persistence.
163
+ effective_model: Ollama model tag to lock into the shared client.
164
+ When ``None``, the SDK default (Anthropic Max path) is used.
154
165
 
155
166
  Yields:
156
167
  The open ``ClaudeSDKClient`` instance.
@@ -158,7 +169,7 @@ async def managed_shared_client(state: State, state_path: Path): # type: ignore
158
169
  _env.strip_dangerous_env()
159
170
  # state.json lives at {project_dir}/.code-generator/state.json.
160
171
  project_dir = state_path.parent.parent
161
- options = _build_cycle_options(project_dir)
172
+ options = _build_cycle_options(project_dir, effective_model=effective_model)
162
173
  async with _open_cycle_client(options) as client:
163
174
  _state.mark_client_alive(state, state_path)
164
175
  try:
@@ -435,7 +435,9 @@ async def run_single_mode(
435
435
  state_path = project_dir / ".code-generator" / "state.json"
436
436
 
437
437
  if state.session_mode in ("shared", "batch"):
438
- async with managed_shared_client(state, state_path) as client:
438
+ async with managed_shared_client(
439
+ state, state_path, effective_model=effective_model
440
+ ) as client:
439
441
  await _run_phases(
440
442
  state,
441
443
  None,
@@ -665,7 +667,9 @@ async def _run_cycle_phases(
665
667
  log_prefix = f"cycle{cycle.id}_"
666
668
 
667
669
  if state.session_mode in ("shared", "batch"):
668
- async with managed_shared_client(state, state_path) as client:
670
+ async with managed_shared_client(
671
+ state, state_path, effective_model=effective_model
672
+ ) as client:
669
673
  await _run_phases(
670
674
  state,
671
675
  cycle,
@@ -125,12 +125,14 @@ def _parse_json(text: str) -> dict[str, Any] | None:
125
125
  return None
126
126
 
127
127
 
128
- def _apply_result(state: State, output: Phase0Output) -> None:
128
+ def _apply_result(state: State, output: Phase0Output, effective_model: str | None = None) -> None:
129
129
  """Write validated phase-0 output into *state* in place.
130
130
 
131
131
  Args:
132
132
  state: The state object to mutate.
133
133
  output: Validated :class:`Phase0Output` instance.
134
+ effective_model: Ollama model tag to stamp on new cycles (``None``
135
+ on the Anthropic Max path).
134
136
  """
135
137
  state.mode = output.mode # type: ignore[assignment]
136
138
 
@@ -154,6 +156,7 @@ def _apply_result(state: State, output: Phase0Output) -> None:
154
156
  )
155
157
  for h in cycle.effort_hints
156
158
  ],
159
+ ollama_model=effective_model,
157
160
  )
158
161
  for cycle in output.cycles
159
162
  ]
@@ -283,7 +286,7 @@ async def run(
283
286
 
284
287
  if data is not None:
285
288
  output = parse_phase0_output(data)
286
- _apply_result(state, output)
289
+ _apply_result(state, output, effective_model=effective_model)
287
290
  logger.info("Phase 0: mode=%s, cycles=%d", state.mode, len(state.cycles))
288
291
  _state.save_state(state_path, state)
289
292
  if state.mode == "multi-cycle" and state.cycles:
@@ -280,7 +280,7 @@ async def run(
280
280
  issue_labels=[],
281
281
  retry_count=0,
282
282
  )
283
- _effort.validate_effort(effort_level, "claude-opus-4-7")
283
+ _effort.validate_effort(effort_level, effective_model or _PHASE1_DEFAULT_MODEL)
284
284
 
285
285
  options = make_agent_options(
286
286
  model=effective_model or _PHASE1_DEFAULT_MODEL,
@@ -272,7 +272,7 @@ async def run_batch(
272
272
  REPO_MAP=repo_map,
273
273
  )
274
274
  params = {
275
- "model": "claude-opus-4-7",
275
+ "model": effective_model or _PHASE2_DEFAULT_MODEL,
276
276
  "max_tokens": 8192,
277
277
  "messages": [{"role": "user", "content": prompt}],
278
278
  }
@@ -108,6 +108,7 @@ def _resolve_issue_effort(
108
108
  effort_hints: list[_state.EffortHint],
109
109
  attempt: int,
110
110
  complexity: str,
111
+ effective_model: str | None = None,
111
112
  ) -> _effort.EffortLevel | None:
112
113
  """Resolve and validate the effort level for an issue attempt.
113
114
 
@@ -134,7 +135,7 @@ def _resolve_issue_effort(
134
135
  retry_count=attempt,
135
136
  effort_hint=effort_hint,
136
137
  )
137
- _effort.validate_effort(effort_level, "claude-sonnet-4-6")
138
+ _effort.validate_effort(effort_level, effective_model or _PHASE3_4_DEFAULT_MODEL)
138
139
  return effort_level
139
140
 
140
141
 
@@ -243,7 +244,7 @@ async def _implement_single_issue(
243
244
  # a failure stay within the same issue; no fresh reset needed.
244
245
  if attempt == 0 and boundary_prefix:
245
246
  prompt = boundary_prefix + prompt
246
- effort_level = _resolve_issue_effort(issue, effort_hints, attempt, complexity=state.mode)
247
+ effort_level = _resolve_issue_effort(issue, effort_hints, attempt, complexity=state.mode, effective_model=effective_model)
247
248
  options = make_agent_options(
248
249
  model=effective_model or _PHASE3_4_DEFAULT_MODEL,
249
250
  effort=effort_level,
@@ -338,7 +338,7 @@ async def run(
338
338
  mcp_tools = mcp_tool_wildcards(mcp_servers)
339
339
 
340
340
  effort_level = _effort.resolve_effort(phase=5, complexity="", issue_labels=[], retry_count=0)
341
- _effort.validate_effort(effort_level, "claude-opus-4-7")
341
+ _effort.validate_effort(effort_level, effective_model or _PHASE5_DEFAULT_MODEL)
342
342
 
343
343
  options = make_agent_options(
344
344
  model=effective_model or _PHASE5_DEFAULT_MODEL,
@@ -266,7 +266,7 @@ async def run(
266
266
  issue_labels=[],
267
267
  retry_count=0,
268
268
  )
269
- _effort.validate_effort(effort_level, "claude-opus-4-7")
269
+ _effort.validate_effort(effort_level, effective_model or _PHASE7_DEFAULT_MODEL)
270
270
 
271
271
  options = make_agent_options(
272
272
  model=effective_model or _PHASE7_DEFAULT_MODEL,
@@ -13,6 +13,7 @@ from __future__ import annotations
13
13
  import asyncio
14
14
  import contextlib
15
15
  import json
16
+ import os
16
17
  import subprocess
17
18
  import time
18
19
  from typing import TYPE_CHECKING, Any
@@ -313,7 +314,16 @@ async def run(
313
314
  "CLI session starting (model=%s effort=%s max_turns=%s).", model, effort_display, max_turns
314
315
  )
315
316
 
316
- safe_env = _env.build_agent_env()
317
+ # Detect Ollama mode so build_agent_env() preserves the scoped localhost
318
+ # routing (ANTHROPIC_API_KEY="" + pinned BASE_URL). Without provider="ollama"
319
+ # the default "anthropic-max" path omits ANTHROPIC_API_KEY, which causes
320
+ # the CLI to reject non-Claude model tags or fall back to real credentials.
321
+ _provider: _env.Provider = (
322
+ "ollama"
323
+ if _env._is_localhost_base_url(os.environ.get("ANTHROPIC_BASE_URL"))
324
+ else "anthropic-max"
325
+ )
326
+ safe_env = _env.build_agent_env(provider=_provider)
317
327
 
318
328
  text_parts: list[str] = []
319
329
  result_holder: dict[str, Any] = {