claude-code-generator 0.5.2__tar.gz → 0.5.4__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 (181) hide show
  1. {claude_code_generator-0.5.2/src/claude_code_generator.egg-info → claude_code_generator-0.5.4}/PKG-INFO +15 -4
  2. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/README.md +14 -3
  3. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/pyproject.toml +1 -1
  4. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4/src/claude_code_generator.egg-info}/PKG-INFO +15 -4
  5. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/claude_code_generator.egg-info/SOURCES.txt +1 -0
  6. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/__init__.py +1 -1
  7. claude_code_generator-0.5.4/src/code_generator/cli.py +93 -0
  8. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/_dispatch.py +36 -50
  9. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/logging_setup.py +21 -6
  10. claude_code_generator-0.5.4/tests/test_cli_io_logging.py +73 -0
  11. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_dispatch_graph_report.py +53 -51
  12. claude_code_generator-0.5.2/src/code_generator/cli.py +0 -53
  13. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/LICENSE +0 -0
  14. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/setup.cfg +0 -0
  15. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/claude_code_generator.egg-info/dependency_links.txt +0 -0
  16. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/claude_code_generator.egg-info/entry_points.txt +0 -0
  17. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/claude_code_generator.egg-info/requires.txt +0 -0
  18. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/claude_code_generator.egg-info/top_level.txt +0 -0
  19. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/agents.py +0 -0
  20. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/__init__.py +0 -0
  21. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/_bench_io.py +0 -0
  22. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/_crash_recovery.py +0 -0
  23. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/_detect.py +0 -0
  24. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/_resume.py +0 -0
  25. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/_validators.py +0 -0
  26. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/bench.py +0 -0
  27. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/bench_compare.py +0 -0
  28. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/bench_export.py +0 -0
  29. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/generate.py +0 -0
  30. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/init.py +0 -0
  31. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/optimize.py +0 -0
  32. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/review.py +0 -0
  33. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/commands/status.py +0 -0
  34. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/effort.py +0 -0
  35. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/env.py +0 -0
  36. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/gh/__init__.py +0 -0
  37. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/gh/core.py +0 -0
  38. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/gh/issues.py +0 -0
  39. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/gh/labels.py +0 -0
  40. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/gh/milestones.py +0 -0
  41. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/git_ops.py +0 -0
  42. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/memory.py +0 -0
  43. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/__init__.py +0 -0
  44. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/_client_lifecycle.py +0 -0
  45. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/_comments.py +0 -0
  46. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/_memory_writers.py +0 -0
  47. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/_phase5_precommit.py +0 -0
  48. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/cycle_loop.py +0 -0
  49. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/cycle_prompts.py +0 -0
  50. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/ollama_budget.py +0 -0
  51. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/phase0_complexity.py +0 -0
  52. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/phase1_plan.py +0 -0
  53. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/phase2_review.py +0 -0
  54. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/phase3_4_implement.py +0 -0
  55. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/phase5_closure.py +0 -0
  56. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/phase6_test.py +0 -0
  57. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/orchestrator/phase7_commit.py +0 -0
  58. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/preflight.py +0 -0
  59. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/__init__.py +0 -0
  60. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/hashes.py +0 -0
  61. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-cycle-specializer.md +0 -0
  62. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-optimize-requirements.md +0 -0
  63. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-phase-0-complexity.md +0 -0
  64. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-phase-1-planning.md +0 -0
  65. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-phase-2-batch-review.md +0 -0
  66. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-phase-3-implementation.md +0 -0
  67. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-phase-5-final-review.md +0 -0
  68. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-phase-6-test.md +0 -0
  69. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-phase-7-commit.md +0 -0
  70. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/prompts/prompt-review.md +0 -0
  71. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/repo_info.py +0 -0
  72. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/requirements_structure.py +0 -0
  73. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/__init__.py +0 -0
  74. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/_telemetry.py +0 -0
  75. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/batch.py +0 -0
  76. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/fake_runner.py +0 -0
  77. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/mcp.py +0 -0
  78. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/message_parsing.py +0 -0
  79. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/options.py +0 -0
  80. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/protocol.py +0 -0
  81. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/rate_limit.py +0 -0
  82. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/retry.py +0 -0
  83. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/sdk_runner.py +0 -0
  84. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/soft_reset.py +0 -0
  85. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/state_guard.py +0 -0
  86. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/subprocess_runner.py +0 -0
  87. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/types.py +0 -0
  88. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/runner/utils.py +0 -0
  89. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/state.py +0 -0
  90. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/state_retention.py +0 -0
  91. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/__init__.py +0 -0
  92. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/angular.md +0 -0
  93. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/base.md +0 -0
  94. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/fastapi.md +0 -0
  95. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/finance.md +0 -0
  96. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/fullstack.md +0 -0
  97. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/nestjs.md +0 -0
  98. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/src/code_generator/templates/python-cli.md +0 -0
  99. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_agents.py +0 -0
  100. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_bench.py +0 -0
  101. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_bench_compare.py +0 -0
  102. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_bench_export.py +0 -0
  103. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_bench_fixture.py +0 -0
  104. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_bench_regression.py +0 -0
  105. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_changelog.py +0 -0
  106. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_claude_md.py +0 -0
  107. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_client_lifecycle.py +0 -0
  108. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_comments.py +0 -0
  109. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_commit_message.py +0 -0
  110. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_crash_recovery.py +0 -0
  111. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_cycle_loop.py +0 -0
  112. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_cycle_loop_multicycle.py +0 -0
  113. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_cycle_ollama_model.py +0 -0
  114. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_cycle_prompts.py +0 -0
  115. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_delta_planning.py +0 -0
  116. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_dependencies.py +0 -0
  117. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_detect.py +0 -0
  118. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_docs_no_default_max_turns.py +0 -0
  119. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_docs_ollama_model_guide.py +0 -0
  120. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_docs_ollama_pro.py +0 -0
  121. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_effective_model_routing.py +0 -0
  122. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_effort.py +0 -0
  123. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_env.py +0 -0
  124. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_generate.py +0 -0
  125. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_generate_ollama.py +0 -0
  126. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_generate_resume.py +0 -0
  127. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_gh.py +0 -0
  128. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_gh_labels.py +0 -0
  129. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_gh_milestones.py +0 -0
  130. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_gh_repo_threading.py +0 -0
  131. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_gh_submodules.py +0 -0
  132. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_git_ops.py +0 -0
  133. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_init.py +0 -0
  134. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_logging_setup.py +0 -0
  135. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_max_turns_cli_flag.py +0 -0
  136. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_mcp.py +0 -0
  137. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_memory.py +0 -0
  138. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_memory_writers.py +0 -0
  139. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_message_parsing.py +0 -0
  140. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_no_max_turns_in_call_sites.py +0 -0
  141. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_no_max_turns_literal.py +0 -0
  142. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_non_goals_grep_guard.py +0 -0
  143. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_ollama_budget.py +0 -0
  144. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_ollama_rate_limit.py +0 -0
  145. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_optimize.py +0 -0
  146. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_options.py +0 -0
  147. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase0.py +0 -0
  148. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase1.py +0 -0
  149. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase2.py +0 -0
  150. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase3_4.py +0 -0
  151. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase5.py +0 -0
  152. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase5_precommit.py +0 -0
  153. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase6.py +0 -0
  154. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase7.py +0 -0
  155. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase_mcp_regression.py +0 -0
  156. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_phase_token_logging.py +0 -0
  157. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_preflight.py +0 -0
  158. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_preflight_ollama.py +0 -0
  159. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_prompt_drift.py +0 -0
  160. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_prompt_prefix_snapshots.py +0 -0
  161. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_prompt_prefix_stability.py +0 -0
  162. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_prompts.py +0 -0
  163. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_rate_limit.py +0 -0
  164. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_repo_info.py +0 -0
  165. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_requirements_structure.py +0 -0
  166. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_retry.py +0 -0
  167. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_review.py +0 -0
  168. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_runner_protocol.py +0 -0
  169. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_runner_protocol_annotations.py +0 -0
  170. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_runner_types.py +0 -0
  171. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_runner_utils.py +0 -0
  172. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_sdk_runner.py +0 -0
  173. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_sdk_runner_shared.py +0 -0
  174. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_session_mode.py +0 -0
  175. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_state.py +0 -0
  176. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_state_guard.py +0 -0
  177. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_state_retention.py +0 -0
  178. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_status.py +0 -0
  179. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_subprocess_runner.py +0 -0
  180. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/tests/test_telemetry.py +0 -0
  181. {claude_code_generator-0.5.2 → claude_code_generator-0.5.4}/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.5.2
3
+ Version: 0.5.4
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
@@ -55,17 +55,28 @@ cd code-generator && pip install -e ".[dev]"
55
55
 
56
56
  ### Optional: codebase graph (graphify)
57
57
 
58
- Phases 0, 1, and 2 inject a knowledge-graph report from [graphify](https://github.com/safishamsi/graphify) for richer code orientation. When the binary is missing, the orchestrator falls back to a sentinel string and continues.
58
+ Phases 0, 1, and 2 inject a knowledge-graph report from [graphify](https://github.com/safishamsi/graphify) for richer code orientation. When the graph is missing, the orchestrator falls back to a sentinel string and continues — nothing breaks.
59
+
60
+ **Install the CLI** (required to use graphify at all):
59
61
 
60
62
  ```bash
61
63
  pipx install graphifyy # CLI binary is `graphify`
62
64
  ```
63
65
 
66
+ **Seed the graph (one-time, per project)**: graphify's full LLM-driven build runs through the `/graphify` slash-command inside an AI assistant — *not* through the shell binary. From inside Claude Code (or any other graphify-supported assistant) run:
67
+
68
+ ```
69
+ /graphify .
70
+ ```
71
+
72
+ This produces `graphify-out/graph.json` and `graphify-out/GRAPH_REPORT.md`.
73
+
74
+ **Subsequent code-generator runs** will automatically refresh the graph with `graphify update .` (AST-only, no LLM cost). Doc / paper / image changes still need a manual `/graphify .` re-run inside your assistant.
75
+
64
76
  Add to your project's `.gitignore`:
65
77
 
66
78
  ```
67
- graphify-out/manifest.json
68
- graphify-out/cost.json
79
+ graphify-out/
69
80
  ```
70
81
 
71
82
  ## Authentication
@@ -17,17 +17,28 @@ cd code-generator && pip install -e ".[dev]"
17
17
 
18
18
  ### Optional: codebase graph (graphify)
19
19
 
20
- Phases 0, 1, and 2 inject a knowledge-graph report from [graphify](https://github.com/safishamsi/graphify) for richer code orientation. When the binary is missing, the orchestrator falls back to a sentinel string and continues.
20
+ Phases 0, 1, and 2 inject a knowledge-graph report from [graphify](https://github.com/safishamsi/graphify) for richer code orientation. When the graph is missing, the orchestrator falls back to a sentinel string and continues — nothing breaks.
21
+
22
+ **Install the CLI** (required to use graphify at all):
21
23
 
22
24
  ```bash
23
25
  pipx install graphifyy # CLI binary is `graphify`
24
26
  ```
25
27
 
28
+ **Seed the graph (one-time, per project)**: graphify's full LLM-driven build runs through the `/graphify` slash-command inside an AI assistant — *not* through the shell binary. From inside Claude Code (or any other graphify-supported assistant) run:
29
+
30
+ ```
31
+ /graphify .
32
+ ```
33
+
34
+ This produces `graphify-out/graph.json` and `graphify-out/GRAPH_REPORT.md`.
35
+
36
+ **Subsequent code-generator runs** will automatically refresh the graph with `graphify update .` (AST-only, no LLM cost). Doc / paper / image changes still need a manual `/graphify .` re-run inside your assistant.
37
+
26
38
  Add to your project's `.gitignore`:
27
39
 
28
40
  ```
29
- graphify-out/manifest.json
30
- graphify-out/cost.json
41
+ graphify-out/
31
42
  ```
32
43
 
33
44
  ## Authentication
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "claude-code-generator"
7
- version = "0.5.2"
7
+ version = "0.5.4"
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.5.2
3
+ Version: 0.5.4
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
@@ -55,17 +55,28 @@ cd code-generator && pip install -e ".[dev]"
55
55
 
56
56
  ### Optional: codebase graph (graphify)
57
57
 
58
- Phases 0, 1, and 2 inject a knowledge-graph report from [graphify](https://github.com/safishamsi/graphify) for richer code orientation. When the binary is missing, the orchestrator falls back to a sentinel string and continues.
58
+ Phases 0, 1, and 2 inject a knowledge-graph report from [graphify](https://github.com/safishamsi/graphify) for richer code orientation. When the graph is missing, the orchestrator falls back to a sentinel string and continues — nothing breaks.
59
+
60
+ **Install the CLI** (required to use graphify at all):
59
61
 
60
62
  ```bash
61
63
  pipx install graphifyy # CLI binary is `graphify`
62
64
  ```
63
65
 
66
+ **Seed the graph (one-time, per project)**: graphify's full LLM-driven build runs through the `/graphify` slash-command inside an AI assistant — *not* through the shell binary. From inside Claude Code (or any other graphify-supported assistant) run:
67
+
68
+ ```
69
+ /graphify .
70
+ ```
71
+
72
+ This produces `graphify-out/graph.json` and `graphify-out/GRAPH_REPORT.md`.
73
+
74
+ **Subsequent code-generator runs** will automatically refresh the graph with `graphify update .` (AST-only, no LLM cost). Doc / paper / image changes still need a manual `/graphify .` re-run inside your assistant.
75
+
64
76
  Add to your project's `.gitignore`:
65
77
 
66
78
  ```
67
- graphify-out/manifest.json
68
- graphify-out/cost.json
79
+ graphify-out/
69
80
  ```
70
81
 
71
82
  ## Authentication
@@ -99,6 +99,7 @@ tests/test_bench_fixture.py
99
99
  tests/test_bench_regression.py
100
100
  tests/test_changelog.py
101
101
  tests/test_claude_md.py
102
+ tests/test_cli_io_logging.py
102
103
  tests/test_client_lifecycle.py
103
104
  tests/test_comments.py
104
105
  tests/test_commit_message.py
@@ -1,3 +1,3 @@
1
1
  """code-generator: orchestrator CLI for end-to-end project generation."""
2
2
 
3
- __version__ = "0.5.2"
3
+ __version__ = "0.5.4"
@@ -0,0 +1,93 @@
1
+ """Entry-point CLI for code-generator.
2
+
3
+ Exposes a Typer application with --version and subcommands:
4
+ init, status, generate, review.
5
+
6
+ At import time we reconfigure stdout/stderr for line-buffered output (the
7
+ in-process equivalent of ``PYTHONUNBUFFERED=1``) so phase progress shows up
8
+ in the terminal in real time even when the CLI is invoked through buffering
9
+ wrappers like ``conda run``. The default log level is DEBUG, overridable
10
+ via the ``LOGLEVEL`` env var (set ``LOGLEVEL=INFO`` for the quieter behaviour
11
+ that earlier 0.4.x releases shipped with).
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import contextlib
17
+ import logging
18
+ import os
19
+ import sys
20
+ from typing import Annotated
21
+
22
+ import typer
23
+
24
+ import code_generator
25
+ from code_generator.commands.bench import bench_app
26
+ from code_generator.commands.generate import generate_app
27
+ from code_generator.commands.init import init_command
28
+ from code_generator.commands.optimize import optimize_command
29
+ from code_generator.commands.review import review_command
30
+ from code_generator.commands.status import status_command
31
+
32
+
33
+ def _configure_io_and_logging() -> None:
34
+ """Force line-buffered stdout/stderr and apply LOGLEVEL (default DEBUG).
35
+
36
+ Equivalent to running with ``PYTHONUNBUFFERED=1 LOGLEVEL=DEBUG`` from
37
+ the shell, but always-on so users don't have to remember the env vars.
38
+ Both can still be overridden externally — ``LOGLEVEL=INFO`` reverts to
39
+ the quieter default.
40
+
41
+ Idempotent: safe to call multiple times (the ``reconfigure`` call is a
42
+ no-op when line buffering is already on, and ``logging.basicConfig`` is
43
+ a no-op once root handlers exist).
44
+ """
45
+ # Line-buffered console I/O: each ``\n`` flushes immediately. The
46
+ # `contextlib.suppress` wrapper handles streams that are already buffered
47
+ # as needed or are non-seekable (e.g. piped to another process).
48
+ for stream in (sys.stdout, sys.stderr):
49
+ with contextlib.suppress(AttributeError, OSError):
50
+ stream.reconfigure(line_buffering=True) # type: ignore[union-attr]
51
+
52
+ level_name = os.environ.get("LOGLEVEL", "DEBUG").upper()
53
+ level = getattr(logging, level_name, logging.DEBUG)
54
+ logging.getLogger("code_generator").setLevel(level)
55
+
56
+
57
+ _configure_io_and_logging()
58
+
59
+ app = typer.Typer(
60
+ name="code-generator",
61
+ help="Orchestrate Claude Code to generate whole projects from a requirements.md.",
62
+ no_args_is_help=True,
63
+ )
64
+
65
+
66
+ def _version_callback(value: bool) -> None:
67
+ if value:
68
+ typer.echo(f"code-generator {code_generator.__version__}")
69
+ raise typer.Exit()
70
+
71
+
72
+ @app.callback()
73
+ def root(
74
+ version: Annotated[
75
+ bool | None,
76
+ typer.Option(
77
+ "--version",
78
+ "-V",
79
+ help="Show version and exit.",
80
+ callback=_version_callback,
81
+ is_eager=True,
82
+ ),
83
+ ] = None,
84
+ ) -> None:
85
+ """code-generator CLI root."""
86
+
87
+
88
+ app.add_typer(bench_app, name="bench")
89
+ app.add_typer(generate_app, name="generate")
90
+ app.command(name="init")(init_command)
91
+ app.command(name="status")(status_command)
92
+ app.command(name="optimize")(optimize_command)
93
+ app.command(name="review")(review_command)
@@ -37,34 +37,12 @@ __all__ = ["dispatch_async", "dispatch_orchestrator"]
37
37
  _GRAPHIFY_TIMEOUT = int(os.environ.get("CODE_GENERATOR_GRAPHIFY_TIMEOUT", "600"))
38
38
 
39
39
 
40
- def _graphify_command(project_dir: Path) -> list[str]:
41
- """Return the right graphify CLI invocation based on whether a prior graph exists.
42
-
43
- Graphify's CLI parser treats the first positional arg as a *subcommand*
44
- name (``install``, ``query``, ``update``, ...) and only falls through to
45
- "build the graph for this directory" when the arg looks like a relative
46
- path (``.``, ``./src``). Passing an absolute path like
47
- ``/Volumes/External SSD/optimizer`` makes graphify exit 1 with
48
- ``error: unknown command '<path>'``. We always pass ``.`` and rely on
49
- ``subprocess.run(cwd=project_dir)`` to anchor it.
50
-
51
- Graphify's ``--update`` flag *requires* an existing ``graph.json`` to
52
- merge into ("re-extract only changed files, merge into existing graph").
53
- On a virgin project tree it fails with exit 1. We detect that case by
54
- looking for ``graphify-out/graph.json`` and skipping ``--update`` on the
55
- first run.
56
-
57
- Args:
58
- project_dir: Project root directory.
59
-
60
- Returns:
61
- The argv list to pass to ``subprocess.run``.
62
- """
63
- graph_json = project_dir / "graphify-out" / "graph.json"
64
- base = ["graphify", ".", "--no-viz"]
65
- if graph_json.exists():
66
- base.append("--update")
67
- return base
40
+ _SETUP_HINT = (
41
+ "graph-report: graphify-out/graph.json not found run `/graphify .` once "
42
+ "inside Claude Code (or another graphify-compatible assistant) to seed the "
43
+ "knowledge graph. After that, code-generator will keep it fresh "
44
+ "automatically with `graphify update .`. Using fallback for now."
45
+ )
68
46
 
69
47
 
70
48
  def _decode_stderr(stderr: bytes | str | None) -> str:
@@ -77,35 +55,37 @@ def _decode_stderr(stderr: bytes | str | None) -> str:
77
55
 
78
56
 
79
57
  def _compute_and_persist_graph_report(project_dir: Path, log: logging.Logger) -> None:
80
- """Build the codebase graph via graphify and persist it to memories.
58
+ """Refresh the codebase graph via graphify and persist the report.
59
+
60
+ Graphify's shell CLI does **not** support a "build" subcommand — the full
61
+ LLM-driven build only happens through the ``/graphify`` slash-command
62
+ inside an AI assistant (Claude Code, Codex, Cursor, etc.). The shell
63
+ binary only supports maintenance subcommands like ``update``, ``watch``,
64
+ ``query``.
81
65
 
82
- Invokes the ``graphify`` CLI to (re)build ``graphify-out/GRAPH_REPORT.md``
83
- and copies the resulting markdown into
84
- ``.code-generator/memories/cycle-repo-map.md`` so Phases 0, 1, 2 can read
85
- it via :func:`code_generator.memory.read_cycle_repomap`.
66
+ Strategy:
86
67
 
87
- Two modes:
68
+ 1. If ``graphify-out/graph.json`` does **not** exist, the user has never
69
+ seeded the graph. Log a one-time setup hint, write the fallback
70
+ sentinel, and return — do not call subprocess. The user must run
71
+ ``/graphify .`` in their assistant once to seed it.
88
72
 
89
- - **First run** (no ``graphify-out/graph.json``): full build via
90
- ``graphify <path> --no-viz``. ``--update`` is *not* added because it
91
- requires a prior graph to merge into passing it on a virgin tree
92
- makes graphify exit 1.
93
- - **Incremental** (graph.json exists): ``graphify <path> --update
94
- --no-viz``. Graphify's SHA256-keyed cache in ``graphify-out/cache/``
95
- keeps subsequent runs cheap.
73
+ 2. If it exists, run ``graphify update .`` (cwd=project_dir). This is
74
+ AST-only re-extraction, no LLM cost, fast on cached files. It
75
+ refreshes ``graph.json`` and ``GRAPH_REPORT.md``. Doc / paper /
76
+ image changes are *not* picked up — for those the user must run
77
+ ``/graphify .`` again in their assistant.
96
78
 
97
79
  Falls back to :data:`code_generator.memory.REPOMAP_FALLBACK` on any
98
80
  failure (binary missing, timeout, non-zero exit, missing report file).
99
81
  Stderr from graphify is captured and logged at WARN level on failure so
100
82
  the user can diagnose without re-running by hand.
101
83
 
102
- Auth: graphify inherits the parent process env (Claude Code OAuth
103
- subscription). Do **not** strip ``ANTHROPIC_*`` here graphify is a
104
- user-facing dev tool that piggybacks on whichever assistant invoked it.
105
- The startup ``env.assert_safe_environment()`` check (CLAUDE.md
106
- non-negotiable #1) already guarantees no API-key vars are present in the
107
- process environment when the orchestrator runs on the Anthropic Max
108
- path, so passing the inherited env to graphify is safe.
84
+ Auth: graphify inherits the parent process env. ``graphify update`` is
85
+ AST-only and makes no LLM calls, so OAuth context is irrelevant on this
86
+ codepath but we still don't strip ``ANTHROPIC_*`` because the startup
87
+ ``env.assert_safe_environment()`` check (CLAUDE.md non-negotiable #1)
88
+ already guarantees those vars are absent on the Anthropic Max path.
109
89
 
110
90
  Args:
111
91
  project_dir: Project root directory (graphify writes ``graphify-out/``
@@ -114,6 +94,7 @@ def _compute_and_persist_graph_report(project_dir: Path, log: logging.Logger) ->
114
94
  """
115
95
  memories_dir = project_dir / ".code-generator" / "memories"
116
96
  report_path = project_dir / "graphify-out" / "GRAPH_REPORT.md"
97
+ graph_json = project_dir / "graphify-out" / "graph.json"
117
98
 
118
99
  if shutil.which("graphify") is None:
119
100
  log.warning(
@@ -123,9 +104,14 @@ def _compute_and_persist_graph_report(project_dir: Path, log: logging.Logger) ->
123
104
  _memory.write_memory_file(memories_dir, "cycle-repo-map.md", _memory.REPOMAP_FALLBACK)
124
105
  return
125
106
 
126
- cmd = _graphify_command(project_dir)
107
+ if not graph_json.exists():
108
+ log.info(_SETUP_HINT)
109
+ _memory.write_memory_file(memories_dir, "cycle-repo-map.md", _memory.REPOMAP_FALLBACK)
110
+ return
111
+
112
+ cmd = ["graphify", "update", "."]
127
113
  try:
128
- log.info("graph-report: building (cmd=%s)", " ".join(cmd))
114
+ log.info("graph-report: refreshing (cmd=%s)", " ".join(cmd))
129
115
  subprocess.run( # noqa: S603
130
116
  cmd,
131
117
  cwd=project_dir,
@@ -3,9 +3,14 @@
3
3
  Each phase gets its own log file under .code-generator/logs/ and a shared
4
4
  RichHandler for colour-coded console output. The setup is idempotent: calling
5
5
  setup_phase_logger() twice for the same phase does not duplicate handlers.
6
+
7
+ The default console level is DEBUG, overridable via the ``LOGLEVEL`` env var
8
+ (``LOGLEVEL=INFO`` for the quieter behaviour shipped in 0.4.x). The file
9
+ handler always writes at DEBUG so post-mortem inspection retains everything.
6
10
  """
7
11
 
8
12
  import logging
13
+ import os
9
14
  from pathlib import Path
10
15
 
11
16
  from rich.logging import RichHandler
@@ -13,11 +18,19 @@ from rich.logging import RichHandler
13
18
  _FILE_FORMATTER = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
14
19
 
15
20
 
21
+ def _resolve_level(default: int = logging.DEBUG) -> int:
22
+ """Read the ``LOGLEVEL`` env var, falling back to *default* on miss/typo."""
23
+ name = os.environ.get("LOGLEVEL", "").upper()
24
+ if not name:
25
+ return default
26
+ return getattr(logging, name, default)
27
+
28
+
16
29
  def setup_phase_logger(
17
30
  phase_name: str,
18
31
  project_dir: Path,
19
32
  *,
20
- level: int = logging.INFO,
33
+ level: int | None = None,
21
34
  ) -> logging.Logger:
22
35
  """Configure and return a logger for a single orchestration phase.
23
36
 
@@ -29,21 +42,23 @@ def setup_phase_logger(
29
42
  phase_name: Short identifier for the phase (e.g. ``"planning"``).
30
43
  project_dir: Root directory of the user's project. Logs are written to
31
44
  ``project_dir / ".code-generator" / "logs" / f"{phase_name}.log"``.
32
- level: Python logging level applied to the logger. Defaults to INFO.
45
+ level: Python logging level applied to the logger. Defaults to the
46
+ value of the ``LOGLEVEL`` env var, or DEBUG if unset.
33
47
 
34
48
  Returns:
35
49
  Configured :class:`logging.Logger` instance.
36
50
  """
51
+ effective_level = level if level is not None else _resolve_level()
37
52
  logger = logging.getLogger(f"code_generator.phase.{phase_name}")
38
53
 
39
54
  if _already_configured(logger):
40
55
  return logger
41
56
 
42
- logger.setLevel(level)
57
+ logger.setLevel(effective_level)
43
58
  logger.propagate = False
44
59
 
45
60
  _attach_file_handler(logger, project_dir, phase_name)
46
- _attach_rich_handler(logger)
61
+ _attach_rich_handler(logger, effective_level)
47
62
 
48
63
  return logger
49
64
 
@@ -67,9 +82,9 @@ def _attach_file_handler(
67
82
  logger.addHandler(handler)
68
83
 
69
84
 
70
- def _attach_rich_handler(logger: logging.Logger) -> None:
85
+ def _attach_rich_handler(logger: logging.Logger, level: int) -> None:
71
86
  handler = RichHandler(show_time=False, show_path=False)
72
- handler.setLevel(logging.INFO)
87
+ handler.setLevel(level)
73
88
  logger.addHandler(handler)
74
89
 
75
90
 
@@ -0,0 +1,73 @@
1
+ """Tests for ``cli._configure_io_and_logging``.
2
+
3
+ The CLI applies two startup defaults so users don't need to set env vars
4
+ manually: line-buffered stdout/stderr (PYTHONUNBUFFERED=1) and DEBUG-level
5
+ console logging (LOGLEVEL=DEBUG). Both are overridable via ``LOGLEVEL``.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from typing import TYPE_CHECKING
12
+
13
+ from code_generator import cli
14
+
15
+ if TYPE_CHECKING:
16
+ import pytest
17
+
18
+
19
+ class TestConfigureIoAndLogging:
20
+ """``_configure_io_and_logging`` sets sane defaults at CLI startup."""
21
+
22
+ def test_default_loglevel_is_debug(self, monkeypatch: pytest.MonkeyPatch) -> None:
23
+ """When ``LOGLEVEL`` is unset, the code_generator namespace uses DEBUG."""
24
+ monkeypatch.delenv("LOGLEVEL", raising=False)
25
+ cli._configure_io_and_logging()
26
+
27
+ assert logging.getLogger("code_generator").level == logging.DEBUG
28
+
29
+ def test_loglevel_env_overrides_default(self, monkeypatch: pytest.MonkeyPatch) -> None:
30
+ """``LOGLEVEL=INFO`` reverts to the quieter 0.4.x default."""
31
+ monkeypatch.setenv("LOGLEVEL", "INFO")
32
+ cli._configure_io_and_logging()
33
+
34
+ assert logging.getLogger("code_generator").level == logging.INFO
35
+
36
+ def test_unknown_loglevel_falls_back_to_debug(
37
+ self, monkeypatch: pytest.MonkeyPatch
38
+ ) -> None:
39
+ """Typos like ``LOGLEVEL=NOPE`` fall back to DEBUG, not raise."""
40
+ monkeypatch.setenv("LOGLEVEL", "NOPE")
41
+ cli._configure_io_and_logging()
42
+
43
+ assert logging.getLogger("code_generator").level == logging.DEBUG
44
+
45
+ def test_idempotent_when_called_twice(self, monkeypatch: pytest.MonkeyPatch) -> None:
46
+ """Calling twice in a row does not raise (e.g. on `--version` re-import)."""
47
+ monkeypatch.setenv("LOGLEVEL", "INFO")
48
+ cli._configure_io_and_logging()
49
+ cli._configure_io_and_logging() # must not raise
50
+
51
+ assert logging.getLogger("code_generator").level == logging.INFO
52
+
53
+ def test_stdout_is_line_buffered_after_setup(
54
+ self, monkeypatch: pytest.MonkeyPatch
55
+ ) -> None:
56
+ """sys.stdout / sys.stderr must report line buffering after setup.
57
+
58
+ On terminals where stdout is already line-buffered, this is a no-op;
59
+ when running through a pipe (default block buffering), the call
60
+ switches the stream to line buffering.
61
+ """
62
+ import sys
63
+
64
+ monkeypatch.delenv("LOGLEVEL", raising=False)
65
+ cli._configure_io_and_logging()
66
+
67
+ # `line_buffering` attribute exists on TextIOWrapper. After
68
+ # reconfigure(line_buffering=True), it must be True. Streams that
69
+ # don't support the attribute (rare) are intentionally tolerated.
70
+ for stream in (sys.stdout, sys.stderr):
71
+ buffering = getattr(stream, "line_buffering", None)
72
+ if buffering is not None:
73
+ assert buffering is True, f"{stream} not line-buffered"