claude-code-generator 0.5.4__tar.gz → 0.5.5__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 (180) hide show
  1. {claude_code_generator-0.5.4/src/claude_code_generator.egg-info → claude_code_generator-0.5.5}/PKG-INFO +1 -1
  2. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/pyproject.toml +1 -1
  3. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5/src/claude_code_generator.egg-info}/PKG-INFO +1 -1
  4. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/__init__.py +1 -1
  5. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/message_parsing.py +122 -0
  6. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/sdk_runner.py +49 -2
  7. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_message_parsing.py +165 -0
  8. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/LICENSE +0 -0
  9. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/README.md +0 -0
  10. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/setup.cfg +0 -0
  11. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/claude_code_generator.egg-info/SOURCES.txt +0 -0
  12. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/claude_code_generator.egg-info/dependency_links.txt +0 -0
  13. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/claude_code_generator.egg-info/entry_points.txt +0 -0
  14. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/claude_code_generator.egg-info/requires.txt +0 -0
  15. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/claude_code_generator.egg-info/top_level.txt +0 -0
  16. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/agents.py +0 -0
  17. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/cli.py +0 -0
  18. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/__init__.py +0 -0
  19. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/_bench_io.py +0 -0
  20. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/_crash_recovery.py +0 -0
  21. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/_detect.py +0 -0
  22. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/_dispatch.py +0 -0
  23. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/_resume.py +0 -0
  24. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/_validators.py +0 -0
  25. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/bench.py +0 -0
  26. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/bench_compare.py +0 -0
  27. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/bench_export.py +0 -0
  28. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/generate.py +0 -0
  29. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/init.py +0 -0
  30. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/optimize.py +0 -0
  31. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/review.py +0 -0
  32. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/commands/status.py +0 -0
  33. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/effort.py +0 -0
  34. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/env.py +0 -0
  35. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/gh/__init__.py +0 -0
  36. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/gh/core.py +0 -0
  37. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/gh/issues.py +0 -0
  38. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/gh/labels.py +0 -0
  39. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/gh/milestones.py +0 -0
  40. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/git_ops.py +0 -0
  41. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/logging_setup.py +0 -0
  42. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/memory.py +0 -0
  43. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/__init__.py +0 -0
  44. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/_client_lifecycle.py +0 -0
  45. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/_comments.py +0 -0
  46. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/_memory_writers.py +0 -0
  47. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/_phase5_precommit.py +0 -0
  48. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/cycle_loop.py +0 -0
  49. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/cycle_prompts.py +0 -0
  50. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/ollama_budget.py +0 -0
  51. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/phase0_complexity.py +0 -0
  52. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/phase1_plan.py +0 -0
  53. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/phase2_review.py +0 -0
  54. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/phase3_4_implement.py +0 -0
  55. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/phase5_closure.py +0 -0
  56. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/phase6_test.py +0 -0
  57. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/orchestrator/phase7_commit.py +0 -0
  58. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/preflight.py +0 -0
  59. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/__init__.py +0 -0
  60. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/hashes.py +0 -0
  61. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-cycle-specializer.md +0 -0
  62. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-optimize-requirements.md +0 -0
  63. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-phase-0-complexity.md +0 -0
  64. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-phase-1-planning.md +0 -0
  65. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-phase-2-batch-review.md +0 -0
  66. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-phase-3-implementation.md +0 -0
  67. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-phase-5-final-review.md +0 -0
  68. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-phase-6-test.md +0 -0
  69. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-phase-7-commit.md +0 -0
  70. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/prompts/prompt-review.md +0 -0
  71. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/repo_info.py +0 -0
  72. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/requirements_structure.py +0 -0
  73. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/__init__.py +0 -0
  74. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/_telemetry.py +0 -0
  75. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/batch.py +0 -0
  76. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/fake_runner.py +0 -0
  77. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/mcp.py +0 -0
  78. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/options.py +0 -0
  79. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/protocol.py +0 -0
  80. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/rate_limit.py +0 -0
  81. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/retry.py +0 -0
  82. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/soft_reset.py +0 -0
  83. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/state_guard.py +0 -0
  84. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/subprocess_runner.py +0 -0
  85. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/types.py +0 -0
  86. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/runner/utils.py +0 -0
  87. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/state.py +0 -0
  88. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/state_retention.py +0 -0
  89. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/__init__.py +0 -0
  90. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/angular.md +0 -0
  91. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/base.md +0 -0
  92. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/fastapi.md +0 -0
  93. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/finance.md +0 -0
  94. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/fullstack.md +0 -0
  95. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/nestjs.md +0 -0
  96. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/src/code_generator/templates/python-cli.md +0 -0
  97. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_agents.py +0 -0
  98. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_bench.py +0 -0
  99. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_bench_compare.py +0 -0
  100. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_bench_export.py +0 -0
  101. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_bench_fixture.py +0 -0
  102. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_bench_regression.py +0 -0
  103. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_changelog.py +0 -0
  104. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_claude_md.py +0 -0
  105. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_cli_io_logging.py +0 -0
  106. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_client_lifecycle.py +0 -0
  107. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_comments.py +0 -0
  108. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_commit_message.py +0 -0
  109. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_crash_recovery.py +0 -0
  110. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_cycle_loop.py +0 -0
  111. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_cycle_loop_multicycle.py +0 -0
  112. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_cycle_ollama_model.py +0 -0
  113. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_cycle_prompts.py +0 -0
  114. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_delta_planning.py +0 -0
  115. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_dependencies.py +0 -0
  116. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_detect.py +0 -0
  117. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_dispatch_graph_report.py +0 -0
  118. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_docs_no_default_max_turns.py +0 -0
  119. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_docs_ollama_model_guide.py +0 -0
  120. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_docs_ollama_pro.py +0 -0
  121. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_effective_model_routing.py +0 -0
  122. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_effort.py +0 -0
  123. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_env.py +0 -0
  124. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_generate.py +0 -0
  125. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_generate_ollama.py +0 -0
  126. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_generate_resume.py +0 -0
  127. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_gh.py +0 -0
  128. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_gh_labels.py +0 -0
  129. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_gh_milestones.py +0 -0
  130. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_gh_repo_threading.py +0 -0
  131. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_gh_submodules.py +0 -0
  132. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_git_ops.py +0 -0
  133. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_init.py +0 -0
  134. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_logging_setup.py +0 -0
  135. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_max_turns_cli_flag.py +0 -0
  136. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_mcp.py +0 -0
  137. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_memory.py +0 -0
  138. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_memory_writers.py +0 -0
  139. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_no_max_turns_in_call_sites.py +0 -0
  140. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_no_max_turns_literal.py +0 -0
  141. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_non_goals_grep_guard.py +0 -0
  142. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_ollama_budget.py +0 -0
  143. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_ollama_rate_limit.py +0 -0
  144. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_optimize.py +0 -0
  145. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_options.py +0 -0
  146. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase0.py +0 -0
  147. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase1.py +0 -0
  148. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase2.py +0 -0
  149. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase3_4.py +0 -0
  150. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase5.py +0 -0
  151. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase5_precommit.py +0 -0
  152. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase6.py +0 -0
  153. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase7.py +0 -0
  154. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase_mcp_regression.py +0 -0
  155. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_phase_token_logging.py +0 -0
  156. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_preflight.py +0 -0
  157. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_preflight_ollama.py +0 -0
  158. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_prompt_drift.py +0 -0
  159. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_prompt_prefix_snapshots.py +0 -0
  160. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_prompt_prefix_stability.py +0 -0
  161. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_prompts.py +0 -0
  162. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_rate_limit.py +0 -0
  163. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_repo_info.py +0 -0
  164. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_requirements_structure.py +0 -0
  165. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_retry.py +0 -0
  166. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_review.py +0 -0
  167. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_runner_protocol.py +0 -0
  168. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_runner_protocol_annotations.py +0 -0
  169. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_runner_types.py +0 -0
  170. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_runner_utils.py +0 -0
  171. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_sdk_runner.py +0 -0
  172. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_sdk_runner_shared.py +0 -0
  173. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_session_mode.py +0 -0
  174. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_state.py +0 -0
  175. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_state_guard.py +0 -0
  176. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_state_retention.py +0 -0
  177. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_status.py +0 -0
  178. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_subprocess_runner.py +0 -0
  179. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/tests/test_telemetry.py +0 -0
  180. {claude_code_generator-0.5.4 → claude_code_generator-0.5.5}/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.4
3
+ Version: 0.5.5
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.5.4"
7
+ version = "0.5.5"
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.4
3
+ Version: 0.5.5
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.5.4"
3
+ __version__ = "0.5.5"
@@ -94,6 +94,128 @@ def is_result_message(msg: Any) -> bool:
94
94
  )
95
95
 
96
96
 
97
+ def is_system_message(msg: Any) -> bool:
98
+ """Return True when msg looks like a SDK ``SystemMessage``.
99
+
100
+ Duck-typed: SystemMessage carries a ``subtype`` (e.g. ``"init"``) and an
101
+ optional ``data`` dict, while not having the discriminating attributes of
102
+ AssistantMessage (``model``) or ResultMessage (``is_error``).
103
+ """
104
+ return (
105
+ hasattr(msg, "subtype")
106
+ and not hasattr(msg, "model")
107
+ and not hasattr(msg, "is_error")
108
+ and not hasattr(msg, "rate_limit_info")
109
+ )
110
+
111
+
112
+ def is_user_message(msg: Any) -> bool:
113
+ """Return True when msg looks like a SDK ``UserMessage``.
114
+
115
+ Duck-typed: UserMessage has ``content`` (a list of blocks) and a
116
+ ``role`` of ``"user"``, but not the AssistantMessage ``model`` field.
117
+ """
118
+ role = getattr(msg, "role", None)
119
+ return (
120
+ role == "user"
121
+ and hasattr(msg, "content")
122
+ and not hasattr(msg, "model")
123
+ and not hasattr(msg, "is_error")
124
+ )
125
+
126
+
127
+ def render_system_message(msg: Any) -> str:
128
+ """Format a SystemMessage's ``subtype`` + ``data`` payload for DEBUG logs.
129
+
130
+ Full payload — no truncation. Large ``data`` values can produce long
131
+ lines; that is intentional so users running with ``LOGLEVEL=DEBUG`` see
132
+ exactly what the SDK emitted.
133
+ """
134
+ subtype = getattr(msg, "subtype", None)
135
+ data = getattr(msg, "data", None)
136
+ if subtype is None and data is None:
137
+ return type(msg).__name__
138
+
139
+ if isinstance(data, dict):
140
+ previews = [f"{k}={v!r}" for k, v in data.items()]
141
+ body = " ".join(previews) if previews else "<empty>"
142
+ elif data is None:
143
+ body = "<no data>"
144
+ else:
145
+ body = repr(data)
146
+
147
+ return f"subtype={subtype} {body}"
148
+
149
+
150
+ def render_blocks(content: Any) -> str:
151
+ """Render an SDK message's ``content`` (list of blocks) verbatim.
152
+
153
+ Handles every block shape the agent SDK currently emits:
154
+ - **TextBlock** (``.text``) → ``text: <body>``
155
+ - **ToolUseBlock** (``.name``, ``.input``) → ``tool_use(name): {args}``
156
+ - **ToolResultBlock** (``.tool_use_id``, ``.content``) → ``tool_result(id): <body>``
157
+ - **ThinkingBlock** (``.thinking``) → ``thinking: <body>``
158
+ - Anything else falls through to the class name.
159
+
160
+ No truncation: tool results, prompts, and thinking blocks render in
161
+ full. Long lines are intentional so DEBUG logs are lossless.
162
+
163
+ Args:
164
+ content: The message's ``content`` attribute. Lists are walked
165
+ block-by-block; non-lists are repr'd directly.
166
+
167
+ Returns:
168
+ A single string suitable for a DEBUG log line.
169
+ """
170
+ if not isinstance(content, list):
171
+ return repr(content)
172
+
173
+ if not content:
174
+ return "<empty>"
175
+
176
+ return " | ".join(_render_block(block) for block in content)
177
+
178
+
179
+ def _render_block(block: Any) -> str:
180
+ """Render a single content block — see :func:`render_blocks`."""
181
+ if hasattr(block, "text") and isinstance(block.text, str):
182
+ return f"text: {block.text}"
183
+ if hasattr(block, "name") and hasattr(block, "input"):
184
+ return f"tool_use({block.name}): {block.input!r}"
185
+ if hasattr(block, "tool_use_id"):
186
+ result = getattr(block, "content", "<no content>")
187
+ is_error = bool(getattr(block, "is_error", False))
188
+ body = _render_tool_result(result)
189
+ prefix = "tool_result_error" if is_error else "tool_result"
190
+ return f"{prefix}({block.tool_use_id}): {body}"
191
+ if hasattr(block, "thinking") and isinstance(block.thinking, str):
192
+ return f"thinking: {block.thinking}"
193
+ return type(block).__name__
194
+
195
+
196
+ def _render_tool_result(content: Any) -> str:
197
+ """Render a ToolResultBlock's ``.content`` (str | list[block] | other) verbatim."""
198
+ if isinstance(content, str):
199
+ return content
200
+ if isinstance(content, list):
201
+ chunks: list[str] = []
202
+ for item in content:
203
+ text = getattr(item, "text", None)
204
+ if isinstance(text, str):
205
+ chunks.append(text)
206
+ elif isinstance(item, dict) and isinstance(item.get("text"), str):
207
+ chunks.append(item["text"])
208
+ else:
209
+ chunks.append(repr(item))
210
+ return " / ".join(chunks) if chunks else "<empty>"
211
+ return repr(content)
212
+
213
+
214
+ def render_prompt(prompt: str) -> str:
215
+ """Return the outgoing prompt verbatim for DEBUG logging (no truncation)."""
216
+ return prompt
217
+
218
+
97
219
  def is_context_edit_message(msg: Any) -> bool:
98
220
  """Return True when msg looks like a CompactionResult or ContextEditResult.
99
221
 
@@ -18,6 +18,11 @@ from code_generator.runner.message_parsing import (
18
18
  is_context_edit_message,
19
19
  is_rate_limit_event,
20
20
  is_result_message,
21
+ is_system_message,
22
+ is_user_message,
23
+ render_blocks,
24
+ render_prompt,
25
+ render_system_message,
21
26
  )
22
27
  from code_generator.runner.types import (
23
28
  ApiUpstreamError,
@@ -145,7 +150,14 @@ async def _drain_messages(
145
150
  chunk.rstrip(),
146
151
  )
147
152
  else:
148
- logger.debug("msg #%d: assistant (empty)", msg_count)
153
+ # No text content — almost always a tool_use block. Render it
154
+ # at DEBUG so users can trace exactly which tool the model
155
+ # invoked and with what arguments.
156
+ logger.debug(
157
+ "msg #%d: assistant (tool_use) %s",
158
+ msg_count,
159
+ render_blocks(getattr(msg, "content", None)),
160
+ )
149
161
  # Some SDK versions attach session_id to AssistantMessage.
150
162
  if session_id is None:
151
163
  session_id = getattr(msg, "session_id", None)
@@ -202,8 +214,33 @@ async def _drain_messages(
202
214
  f"tokens_out={usage.output}): {tail}"
203
215
  )
204
216
  break
217
+ elif is_system_message(msg):
218
+ logger.debug("msg #%d: SystemMessage %s", msg_count, render_system_message(msg))
219
+ elif is_user_message(msg):
220
+ logger.debug(
221
+ "msg #%d: UserMessage %s",
222
+ msg_count,
223
+ render_blocks(getattr(msg, "content", None)),
224
+ )
205
225
  else:
206
- logger.debug("msg #%d: %s", msg_count, type(msg).__name__)
226
+ # Catch-all for less common message types (TaskStartedMessage,
227
+ # TaskFinishedMessage, etc.). Render any ``content`` /
228
+ # ``data`` / ``message`` payload we can find so the type-name
229
+ # alone is never the only signal.
230
+ payload = (
231
+ getattr(msg, "content", None)
232
+ or getattr(msg, "data", None)
233
+ or getattr(msg, "message", None)
234
+ )
235
+ if payload is not None:
236
+ logger.debug(
237
+ "msg #%d: %s %s",
238
+ msg_count,
239
+ type(msg).__name__,
240
+ render_blocks(payload),
241
+ )
242
+ else:
243
+ logger.debug("msg #%d: %s", msg_count, type(msg).__name__)
207
244
 
208
245
  return "".join(text_parts), session_id, usage or TokenUsage()
209
246
 
@@ -256,6 +293,11 @@ async def run(
256
293
  getattr(options, "effort", None) or "default",
257
294
  getattr(options, "max_turns", "?"),
258
295
  )
296
+ logger.debug(
297
+ "SDK prompt (%d chars):\n%s",
298
+ len(prompt),
299
+ render_prompt(prompt),
300
+ )
259
301
 
260
302
  t0 = time.monotonic()
261
303
  async with ClaudeSDKClient(options=options) as client:
@@ -311,6 +353,11 @@ async def run_with_shared_client(
311
353
  getattr(options, "effort", None) or "default",
312
354
  getattr(options, "max_turns", "?"),
313
355
  )
356
+ logger.debug(
357
+ "SDK prompt (%d chars):\n%s",
358
+ len(prompt),
359
+ render_prompt(prompt),
360
+ )
314
361
 
315
362
  t0 = time.monotonic()
316
363
  await client.query(prompt)
@@ -483,3 +483,168 @@ def test_handle_rate_limit_event_rejected_without_resets_at_logs_warning(
483
483
  handle_rate_limit_event(event, logger, state_path)
484
484
 
485
485
  assert any("no resets_at" in r.message for r in caplog.records)
486
+
487
+
488
+ # ---------------------------------------------------------------------------
489
+ # render_blocks / render_system_message / render_prompt / new predicates
490
+ # ---------------------------------------------------------------------------
491
+
492
+
493
+ class FakeToolUseBlock:
494
+ def __init__(self, name: str, input_data: dict) -> None:
495
+ self.name = name
496
+ self.input = input_data
497
+ self.id = "tu-x"
498
+
499
+
500
+ class FakeToolResultBlock:
501
+ def __init__(self, tool_use_id: str, content, is_error: bool = False) -> None:
502
+ self.tool_use_id = tool_use_id
503
+ self.content = content
504
+ self.is_error = is_error
505
+
506
+
507
+ class FakeThinkingBlock:
508
+ def __init__(self, thinking: str) -> None:
509
+ self.thinking = thinking
510
+
511
+
512
+ class FakeSystemMessage:
513
+ def __init__(self, subtype: str, data: dict | None = None) -> None:
514
+ self.subtype = subtype
515
+ self.data = data
516
+
517
+
518
+ class FakeUserMessage:
519
+ def __init__(self, content) -> None:
520
+ self.role = "user"
521
+ self.content = content
522
+
523
+
524
+ def test_render_blocks_handles_text_block() -> None:
525
+ from code_generator.runner.message_parsing import render_blocks
526
+
527
+ rendered = render_blocks([FakeTextBlock("hello world")])
528
+ assert rendered == "text: hello world"
529
+
530
+
531
+ def test_render_blocks_handles_tool_use_block() -> None:
532
+ from code_generator.runner.message_parsing import render_blocks
533
+
534
+ rendered = render_blocks([FakeToolUseBlock("Read", {"file_path": "/tmp/x.py"})])
535
+ assert rendered.startswith("tool_use(Read): ")
536
+ assert "/tmp/x.py" in rendered
537
+
538
+
539
+ def test_render_blocks_handles_tool_result_block_str() -> None:
540
+ from code_generator.runner.message_parsing import render_blocks
541
+
542
+ rendered = render_blocks([FakeToolResultBlock("tu-1", "result body")])
543
+ assert rendered == "tool_result(tu-1): result body"
544
+
545
+
546
+ def test_render_blocks_marks_tool_result_errors() -> None:
547
+ from code_generator.runner.message_parsing import render_blocks
548
+
549
+ rendered = render_blocks(
550
+ [FakeToolResultBlock("tu-2", "boom", is_error=True)]
551
+ )
552
+ assert rendered.startswith("tool_result_error(tu-2): ")
553
+
554
+
555
+ def test_render_blocks_handles_thinking_block() -> None:
556
+ from code_generator.runner.message_parsing import render_blocks
557
+
558
+ rendered = render_blocks([FakeThinkingBlock("planning step…")])
559
+ assert rendered == "thinking: planning step…"
560
+
561
+
562
+ def test_render_blocks_renders_long_text_in_full() -> None:
563
+ """No truncation — full text is preserved so DEBUG logs are lossless."""
564
+ from code_generator.runner.message_parsing import render_blocks
565
+
566
+ long = "x" * 5000
567
+ rendered = render_blocks([FakeTextBlock(long)])
568
+ assert rendered == f"text: {long}"
569
+ assert "truncated" not in rendered
570
+
571
+
572
+ def test_render_blocks_joins_multiple_with_pipe() -> None:
573
+ from code_generator.runner.message_parsing import render_blocks
574
+
575
+ rendered = render_blocks(
576
+ [
577
+ FakeTextBlock("first"),
578
+ FakeToolUseBlock("Read", {"path": "a.py"}),
579
+ ]
580
+ )
581
+ assert " | " in rendered
582
+ assert "text: first" in rendered
583
+ assert "tool_use(Read)" in rendered
584
+
585
+
586
+ def test_render_blocks_empty_list_returns_marker() -> None:
587
+ from code_generator.runner.message_parsing import render_blocks
588
+
589
+ assert render_blocks([]) == "<empty>"
590
+
591
+
592
+ def test_render_system_message_with_subtype_and_data() -> None:
593
+ from code_generator.runner.message_parsing import render_system_message
594
+
595
+ msg = FakeSystemMessage("init", {"model": "claude-opus-4-7", "session_id": "s1"})
596
+ rendered = render_system_message(msg)
597
+ assert rendered.startswith("subtype=init")
598
+ assert "model=" in rendered
599
+ assert "session_id=" in rendered
600
+
601
+
602
+ def test_render_system_message_subtype_only() -> None:
603
+ from code_generator.runner.message_parsing import render_system_message
604
+
605
+ msg = FakeSystemMessage("compaction", None)
606
+ rendered = render_system_message(msg)
607
+ assert rendered.startswith("subtype=compaction")
608
+ assert "no data" in rendered
609
+
610
+
611
+ def test_is_system_message_predicate() -> None:
612
+ from code_generator.runner.message_parsing import is_system_message
613
+
614
+ assert is_system_message(FakeSystemMessage("init"))
615
+ assert not is_system_message(FakeAssistantMessage("hi"))
616
+ assert not is_system_message(FakeUserMessage([FakeTextBlock("hi")]))
617
+
618
+
619
+ def test_is_user_message_predicate() -> None:
620
+ from code_generator.runner.message_parsing import is_user_message
621
+
622
+ assert is_user_message(FakeUserMessage([FakeTextBlock("hi")]))
623
+ assert not is_user_message(FakeSystemMessage("init"))
624
+ assert not is_user_message(FakeAssistantMessage("hi"))
625
+
626
+
627
+ def test_render_prompt_renders_long_input_verbatim() -> None:
628
+ """No truncation — prompts log in full so the model's exact input is auditable."""
629
+ from code_generator.runner.message_parsing import render_prompt
630
+
631
+ long = "y" * 5000
632
+ rendered = render_prompt(long)
633
+ assert rendered == long
634
+ assert "truncated" not in rendered
635
+
636
+
637
+ def test_render_prompt_passthrough_short_input() -> None:
638
+ from code_generator.runner.message_parsing import render_prompt
639
+
640
+ assert render_prompt("hello") == "hello"
641
+
642
+
643
+ def test_render_blocks_renders_long_tool_result_in_full() -> None:
644
+ """Tool results render verbatim — no body cap."""
645
+ from code_generator.runner.message_parsing import render_blocks
646
+
647
+ long = "z" * 5000
648
+ rendered = render_blocks([FakeToolResultBlock("tu-9", long)])
649
+ assert rendered == f"tool_result(tu-9): {long}"
650
+ assert "truncated" not in rendered