teddy-cli 0.1.8__tar.gz → 0.1.10__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 (143) hide show
  1. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/PKG-INFO +1 -1
  2. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/pyproject.toml +1 -1
  3. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/__main__.py +1 -1
  4. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/shell_adapter.py +12 -1
  5. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/execution_orchestrator.py +4 -1
  6. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_orchestrator.py +34 -7
  7. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/templates/execution_report.md.j2 +1 -1
  8. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/.gitignore +0 -0
  9. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/LICENSE +0 -0
  10. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/__init__.py +0 -0
  11. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/__init__.py +0 -0
  12. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/__init__.py +0 -0
  13. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/cli_formatter.py +0 -0
  14. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/cli_helpers.py +0 -0
  15. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/console_plan_reviewer.py +0 -0
  16. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/session_cli_handlers.py +0 -0
  17. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer.py +0 -0
  18. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_app.py +0 -0
  19. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_editor.py +0 -0
  20. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_execution.py +0 -0
  21. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_helpers.py +0 -0
  22. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_logic.py +0 -0
  23. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_previews.py +0 -0
  24. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_widgets.py +0 -0
  25. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/__init__.py +0 -0
  26. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/console_interactor.py +0 -0
  27. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/console_interactor_ask_loop.py +0 -0
  28. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/console_interactor_helpers.py +0 -0
  29. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/console_tooling.py +0 -0
  30. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/filesystem_helpers.py +0 -0
  31. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/litellm_adapter.py +0 -0
  32. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/local_file_system_adapter.py +0 -0
  33. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/local_repo_tree_generator.py +0 -0
  34. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/openrouter_hydrator.py +0 -0
  35. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/shell_command_builder.py +0 -0
  36. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/system_environment_adapter.py +0 -0
  37. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/system_environment_inspector.py +0 -0
  38. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/system_time_adapter.py +0 -0
  39. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/web_scraper_adapter.py +0 -0
  40. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/web_searcher_adapter.py +0 -0
  41. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/adapters/outbound/yaml_config_adapter.py +0 -0
  42. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/container.py +0 -0
  43. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/__init__.py +0 -0
  44. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/__init__.py +0 -0
  45. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/__init__.py +0 -0
  46. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/action_ports.py +0 -0
  47. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/change_set.py +0 -0
  48. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/exceptions.py +0 -0
  49. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/execution_report.py +0 -0
  50. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/orchestrator_ports.py +0 -0
  51. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/plan.py +0 -0
  52. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/planning_ports.py +0 -0
  53. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/project_context.py +0 -0
  54. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/report_assembly_data.py +0 -0
  55. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/session.py +0 -0
  56. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/shell_output.py +0 -0
  57. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/domain/models/web_search_results.py +0 -0
  58. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/__init__.py +0 -0
  59. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/__init__.py +0 -0
  60. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/edit_simulator.py +0 -0
  61. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/get_context_use_case.py +0 -0
  62. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/init.py +0 -0
  63. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/plan_parser.py +0 -0
  64. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/plan_reviewer.py +0 -0
  65. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/plan_validator.py +0 -0
  66. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/planning_use_case.py +0 -0
  67. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/inbound/run_plan_use_case.py +0 -0
  68. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/__init__.py +0 -0
  69. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/config_service.py +0 -0
  70. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/environment_inspector.py +0 -0
  71. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/execution_report_assembler.py +0 -0
  72. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/file_system_manager.py +0 -0
  73. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/llm_client.py +0 -0
  74. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/markdown_report_formatter.py +0 -0
  75. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/prompt_manager.py +0 -0
  76. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/repo_tree_generator.py +0 -0
  77. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/session_loop_guard.py +0 -0
  78. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/session_manager.py +0 -0
  79. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/session_repository.py +0 -0
  80. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/shell_executor.py +0 -0
  81. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/system_environment.py +0 -0
  82. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/time_service.py +0 -0
  83. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/user_interactor.py +0 -0
  84. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/web_scraper.py +0 -0
  85. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/ports/outbound/web_searcher.py +0 -0
  86. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/__init__.py +0 -0
  87. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/action_changeset_builder.py +0 -0
  88. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/action_diff_manager.py +0 -0
  89. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/action_dispatcher.py +0 -0
  90. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/action_executor.py +0 -0
  91. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/action_factory.py +0 -0
  92. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/action_parser_complex.py +0 -0
  93. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/action_parser_strategies.py +0 -0
  94. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/context_service.py +0 -0
  95. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/edit_simulator.py +0 -0
  96. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/execution_report_assembler.py +0 -0
  97. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/init_service.py +0 -0
  98. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/markdown_plan_parser.py +0 -0
  99. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/markdown_report_formatter.py +0 -0
  100. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/parser_infrastructure.py +0 -0
  101. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/parser_metadata.py +0 -0
  102. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/parser_reporting.py +0 -0
  103. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/plan_validator.py +0 -0
  104. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/planning_service.py +0 -0
  105. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/prompt_manager.py +0 -0
  106. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_lifecycle_manager.py +0 -0
  107. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_loop_guard.py +0 -0
  108. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_planner.py +0 -0
  109. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_pruning_service.py +0 -0
  110. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_replanner.py +0 -0
  111. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_repository.py +0 -0
  112. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/session_service.py +0 -0
  113. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/update_checker.py +0 -0
  114. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/__init__.py +0 -0
  115. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/edit.py +0 -0
  116. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/edit_matcher.py +0 -0
  117. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/edit_matcher_heuristics.py +0 -0
  118. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/execute.py +0 -0
  119. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/filesystem.py +0 -0
  120. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/helpers.py +0 -0
  121. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/services/validation_rules/message.py +0 -0
  122. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/utils/__init__.py +0 -0
  123. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/utils/diff.py +0 -0
  124. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/utils/io.py +0 -0
  125. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/utils/markdown.py +0 -0
  126. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/utils/serialization.py +0 -0
  127. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/core/utils/string.py +0 -0
  128. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/prompts.py +0 -0
  129. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/registries/__init__.py +0 -0
  130. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/registries/infrastructure.py +0 -0
  131. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/registries/reviewer.py +0 -0
  132. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/registries/validators.py +0 -0
  133. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/__init__.py +0 -0
  134. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/.gitignore +0 -0
  135. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/__init__.py +0 -0
  136. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/config.yaml +0 -0
  137. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/init.context +0 -0
  138. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/prompts/architect.xml +0 -0
  139. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/prompts/assistant.xml +0 -0
  140. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/prompts/debugger.xml +0 -0
  141. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/prompts/developer.xml +0 -0
  142. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/prompts/pathfinder.xml +0 -0
  143. {teddy_cli-0.1.8 → teddy_cli-0.1.10}/src/teddy_executor/resources/config/prompts/prototyper.xml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: teddy-cli
3
- Version: 0.1.8
3
+ Version: 0.1.10
4
4
  Summary: A local-first, file-based AI coding workflow that applies the UNIX philosophy to AI collaboration.
5
5
  Author: Raphael Atteritano
6
6
  License: AGPL-3.0-only
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "teddy-cli"
3
- version = "0.1.8"
3
+ version = "0.1.10"
4
4
  description = "A local-first, file-based AI coding workflow that applies the UNIX philosophy to AI collaboration."
5
5
  authors = [{ name = "Raphael Atteritano" }]
6
6
  license = { text = "AGPL-3.0-only" }
@@ -288,7 +288,7 @@ def update(
288
288
  elif experimental:
289
289
  typer.echo(f"A new experimental version {latest} is available.")
290
290
  typer.echo(
291
- "To upgrade, run: uv tool install teddy-cli --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ --index-strategy unsafe-best-match"
291
+ "To upgrade, run: uv tool install teddy-cli --pre --force --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ --index-strategy unsafe-best-match"
292
292
  )
293
293
  typer.echo("To apply prompt updates, run: teddy init prompts")
294
294
  else:
@@ -108,7 +108,10 @@ class ShellAdapter(IShellExecutor):
108
108
  "shell": use_shell,
109
109
  "stdout": subprocess.PIPE,
110
110
  "stderr": subprocess.PIPE,
111
- "stdin": subprocess.DEVNULL,
111
+ # Use PIPE instead of DEVNULL to provide a valid file descriptor for
112
+ # Python 3.14.2's C-level initialization. The pipe is closed
113
+ # immediately after Popen so children see EOF on reads.
114
+ "stdin": subprocess.PIPE,
112
115
  "text": True,
113
116
  "cwd": cwd,
114
117
  "env": env,
@@ -279,6 +282,14 @@ class ShellAdapter(IShellExecutor):
279
282
  kwargs = self._prepare_subprocess_kwargs(use_shell, cwd, env)
280
283
  process = self._popen(command_args, **kwargs) # nosec
281
284
 
285
+ # Note: stdin is subprocess.PIPE (not DEVNULL) to provide a valid file
286
+ # descriptor for Python 3.14.2's C-level initialization. We do NOT close
287
+ # the stdin pipe here — communicate() internally flushes stdin before
288
+ # reading output, so closing stdin prematurely causes:
289
+ # ValueError: I/O operation on closed file.
290
+ # communicate() handles the pipe EOF naturally when the subprocess finishes.
291
+ # No input data is written to the pipe, so children see empty stdin.
292
+
282
293
  try:
283
294
  # Type cast is required because Mypy cannot infer str types when
284
295
  # text=True is passed via **kwargs.
@@ -106,7 +106,10 @@ class ExecutionOrchestrator(IRunPlanUseCase):
106
106
  action_log = self._action_executor.handle_failed_action(action, str(e))
107
107
  captured_message = ""
108
108
 
109
- if captured_message:
109
+ # Only propagate captured_message to user_request for non-MESSAGE actions.
110
+ # MESSAGE action replies belong in the action log (action_log.details),
111
+ # not in the User Request section of the report.
112
+ if captured_message and action.type.upper() != "MESSAGE":
110
113
  plan.metadata["user_request"] = captured_message
111
114
 
112
115
  should_halt = (
@@ -83,12 +83,17 @@ def _print_header_bar(plan: Any, is_session: bool) -> None:
83
83
 
84
84
 
85
85
  def _print_user_message(
86
- message: Optional[str], is_session: bool, plan: Optional[Any] = None
86
+ message: Optional[str],
87
+ is_session: bool,
88
+ plan: Optional[Any] = None,
89
+ action_logs: Optional[list] = None,
87
90
  ) -> None:
88
91
  """Print the user message after all actions execute.
89
92
 
90
- If message is not provided (None) and plan is set, falls back to
91
- plan.metadata.get("user_request").
93
+ Priority order:
94
+ 1. Direct `message` parameter (from TUI `m` input).
95
+ 2. `plan.metadata["user_request"]` (for non-MESSAGE action replies).
96
+ 3. MESSAGE action replies from `action_logs` (for MESSAGE action responses).
92
97
 
93
98
  Only prints when is_session=True and message is non-empty.
94
99
  Output::
@@ -99,14 +104,30 @@ def _print_user_message(
99
104
  """
100
105
  if not is_session:
101
106
  return
102
- # Resolve message from plan metadata if not provided
107
+
108
+ # Priority 1: Direct message parameter
109
+ # Priority 2: plan.metadata["user_request"] (non-MESSAGE actions, TUI 'm' input)
103
110
  if not message or not message.strip():
104
111
  if plan:
105
112
  meta_msg = getattr(plan, "metadata", {}).get("user_request") or ""
106
113
  if meta_msg.strip():
107
114
  message = meta_msg.strip()
108
- if not message or not message.strip():
109
- return
115
+
116
+ # Priority 3: Fallback to MESSAGE action replies from action_logs
117
+ # When Bug 16 prevents MESSAGE replies from being stored in
118
+ # plan.metadata["user_request"], we still want to print them to
119
+ # terminal by reading directly from the action logs.
120
+ if (not message or not message.strip()) and action_logs:
121
+ for log in action_logs:
122
+ log_type = getattr(log, "action_type", "") or ""
123
+ log_details = getattr(log, "details", "") or ""
124
+ if log_type.upper() == "MESSAGE" and log_details.strip():
125
+ message = log_details.strip()
126
+ break # Use the last MESSAGE action's reply
127
+
128
+ if not message or not message.strip():
129
+ return
130
+
110
131
  typer.secho("")
111
132
  typer.secho("User Message:")
112
133
  typer.secho(message.strip())
@@ -312,9 +333,15 @@ class SessionOrchestrator(IRunPlanUseCase):
312
333
  # Print user message after all actions executed (only for session mode)
313
334
  # Uses plan.metadata["user_request"] which is populated by _dispatch_single_action
314
335
  # when the user provides a reply during execution.
336
+ # Also extracts MESSAGE action replies from action_logs as a fallback
337
+ # (see Bug 17: Bug 16's guard prevents MESSAGE replies from being stored
338
+ # in plan.metadata["user_request"]).
315
339
  if is_session:
316
340
  user_reply = plan.metadata.get("user_request", "") if plan else ""
317
- _print_user_message(user_reply, is_session, plan=plan)
341
+ action_logs = report.action_logs if report else []
342
+ _print_user_message(
343
+ user_reply, is_session, plan=plan, action_logs=action_logs
344
+ )
318
345
 
319
346
  # 4. Turn Transition
320
347
  if is_session and plan_path:
@@ -268,7 +268,7 @@
268
268
  {% endfor %}
269
269
  {% endfor %}
270
270
 
271
- _**Hint:** NOW you MUST use READ on the most promising results)_
271
+ _**Hint:** NOW you MUST use READ on the most promising results_
272
272
  {% endif %}
273
273
 
274
274
  {% if action_type == 'READ' and log.details and log.details is mapping and log.details.get('content') and params.get('lines') %}
File without changes
File without changes