teddy-cli 0.2.2.dev1452__tar.gz → 0.2.2.dev1454__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 (165) hide show
  1. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/PKG-INFO +1 -1
  2. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/pyproject.toml +1 -1
  3. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/session_cli_handlers.py +5 -0
  4. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/litellm_adapter.py +94 -6
  5. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/execution_orchestrator.py +19 -0
  6. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/planning_service.py +12 -1
  7. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_lifecycle_manager.py +71 -14
  8. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_service.py +5 -0
  9. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/.gitignore +0 -0
  10. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/LICENSE +0 -0
  11. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/README.md +0 -0
  12. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/__init__.py +0 -0
  13. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/__main__.py +0 -0
  14. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/__init__.py +0 -0
  15. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/__init__.py +0 -0
  16. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/cli_formatter.py +0 -0
  17. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/cli_helpers.py +0 -0
  18. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer.py +0 -0
  19. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_app.py +0 -0
  20. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_editor.py +0 -0
  21. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_execution.py +0 -0
  22. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_helpers.py +0 -0
  23. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_logic.py +0 -0
  24. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_previews.py +0 -0
  25. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_widgets.py +0 -0
  26. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/__init__.py +0 -0
  27. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/console_interactor.py +0 -0
  28. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/console_interactor_ask_loop.py +0 -0
  29. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/console_interactor_helpers.py +0 -0
  30. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/console_tooling.py +0 -0
  31. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/filesystem_helpers.py +0 -0
  32. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/local_file_system_adapter.py +0 -0
  33. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/local_repo_tree_generator.py +0 -0
  34. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/openrouter_hydrator.py +0 -0
  35. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/shell_adapter.py +0 -0
  36. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/shell_command_builder.py +0 -0
  37. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/suppressed_logging.py +0 -0
  38. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/system_environment_adapter.py +0 -0
  39. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/system_environment_inspector.py +0 -0
  40. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/system_time_adapter.py +0 -0
  41. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/terminal_quit_key_listener.py +0 -0
  42. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/web_scraper_adapter.py +0 -0
  43. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/web_searcher_adapter.py +0 -0
  44. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/adapters/outbound/yaml_config_adapter.py +0 -0
  45. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/container.py +0 -0
  46. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/__init__.py +0 -0
  47. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/__init__.py +0 -0
  48. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/__init__.py +0 -0
  49. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/action_ports.py +0 -0
  50. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/change_set.py +0 -0
  51. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/config_schema.py +0 -0
  52. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/drift_report.py +0 -0
  53. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/exceptions.py +0 -0
  54. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/execution_report.py +0 -0
  55. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/orchestrator_ports.py +0 -0
  56. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/plan.py +0 -0
  57. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/planning_ports.py +0 -0
  58. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/project_context.py +0 -0
  59. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/report_assembly_data.py +0 -0
  60. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/session.py +0 -0
  61. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/shell_output.py +0 -0
  62. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/domain/models/web_search_results.py +0 -0
  63. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/__init__.py +0 -0
  64. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/__init__.py +0 -0
  65. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/edit_simulator.py +0 -0
  66. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/get_context_use_case.py +0 -0
  67. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/init.py +0 -0
  68. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/plan_parser.py +0 -0
  69. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/plan_reviewer.py +0 -0
  70. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/plan_validator.py +0 -0
  71. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/planning_use_case.py +0 -0
  72. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/inbound/run_plan_use_case.py +0 -0
  73. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/__init__.py +0 -0
  74. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/config_service.py +0 -0
  75. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/environment_inspector.py +0 -0
  76. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/execution_report_assembler.py +0 -0
  77. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/file_system_manager.py +0 -0
  78. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/llm_client.py +0 -0
  79. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/markdown_report_formatter.py +0 -0
  80. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/prompt_manager.py +0 -0
  81. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/quit_key_listener.py +0 -0
  82. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/repo_tree_generator.py +0 -0
  83. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/session_loop_guard.py +0 -0
  84. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/session_manager.py +0 -0
  85. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/session_repository.py +0 -0
  86. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/shell_executor.py +0 -0
  87. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/system_environment.py +0 -0
  88. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/time_service.py +0 -0
  89. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/user_interactor.py +0 -0
  90. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/web_scraper.py +0 -0
  91. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/ports/outbound/web_searcher.py +0 -0
  92. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/__init__.py +0 -0
  93. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/action_changeset_builder.py +0 -0
  94. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/action_diff_manager.py +0 -0
  95. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/action_dispatcher.py +0 -0
  96. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/action_executor.py +0 -0
  97. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/action_factory.py +0 -0
  98. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/action_parser_complex.py +0 -0
  99. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/action_parser_strategies.py +0 -0
  100. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/context_service.py +0 -0
  101. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/edit_simulator.py +0 -0
  102. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/execution_report_assembler.py +0 -0
  103. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/init_service.py +0 -0
  104. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/markdown_plan_parser.py +0 -0
  105. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/markdown_report_formatter.py +0 -0
  106. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/parser_infrastructure.py +0 -0
  107. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/parser_metadata.py +0 -0
  108. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/parser_reporting.py +0 -0
  109. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/plan_validator.py +0 -0
  110. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/prompt_manager.py +0 -0
  111. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_loop_guard.py +0 -0
  112. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_orchestrator.py +0 -0
  113. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_planner.py +0 -0
  114. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_pruning_service.py +0 -0
  115. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_replanner.py +0 -0
  116. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/session_repository.py +0 -0
  117. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/templates/execution_report.md.j2 +0 -0
  118. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/update_checker.py +0 -0
  119. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/__init__.py +0 -0
  120. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/edit.py +0 -0
  121. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/edit_matcher.py +0 -0
  122. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/edit_matcher_heuristics.py +0 -0
  123. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/execute.py +0 -0
  124. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/filesystem.py +0 -0
  125. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/helpers.py +0 -0
  126. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/services/validation_rules/message.py +0 -0
  127. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/__init__.py +0 -0
  128. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/diff.py +0 -0
  129. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/editor_names.py +0 -0
  130. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/interrupt_guard.py +0 -0
  131. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/interruptible_call.py +0 -0
  132. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/io.py +0 -0
  133. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/markdown.py +0 -0
  134. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/paths.py +0 -0
  135. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/serialization.py +0 -0
  136. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/session_notices.py +0 -0
  137. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/stdin_ownership.py +0 -0
  138. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/string.py +0 -0
  139. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/core/utils/terminal.py +0 -0
  140. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/prompts.py +0 -0
  141. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/registries/__init__.py +0 -0
  142. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/registries/infrastructure.py +0 -0
  143. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/registries/reviewer.py +0 -0
  144. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/registries/validators.py +0 -0
  145. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/MRP.md +0 -0
  146. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/__init__.py +0 -0
  147. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/__init__.py +0 -0
  148. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/config.yaml +0 -0
  149. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/init.context +0 -0
  150. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/prompts/architect.md +0 -0
  151. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/prompts/assistant.md +0 -0
  152. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/prompts/debugger.md +0 -0
  153. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/prompts/developer.md +0 -0
  154. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/prompts/pathfinder.md +0 -0
  155. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/config/prompts/prototyper.md +0 -0
  156. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/ARCHITECTURE.md +0 -0
  157. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/PROJECT.md +0 -0
  158. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/case-file.md +0 -0
  159. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/ci.md +0 -0
  160. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/component-design.md +0 -0
  161. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/makefile.md +0 -0
  162. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/milestone.md +0 -0
  163. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/pre-commit.md +0 -0
  164. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/specification-document.md +0 -0
  165. {teddy_cli-0.2.2.dev1452 → teddy_cli-0.2.2.dev1454}/src/teddy_executor/resources/templates/vertical-slice.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: teddy-cli
3
- Version: 0.2.2.dev1452
3
+ Version: 0.2.2.dev1454
4
4
  Summary: The local-first, test-driven agentic engineering harness. Because you should own the means of development.
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.2.2.dev1452"
3
+ version = "0.2.2.dev1454"
4
4
  description = "The local-first, test-driven agentic engineering harness. Because you should own the means of development."
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -836,6 +836,11 @@ def handle_new_session( # noqa: PLR0913
836
836
  _start_background_update_check()
837
837
 
838
838
  try:
839
+ # 0. An empty or whitespace-only -m means the flag was omitted: the
840
+ # interactive opening prompt fires, and pipeline mode errors on empty.
841
+ if message is not None and not message.strip():
842
+ message = None
843
+
839
844
  # 0. Pipeline mode requires an initial message
840
845
  if pipeline and message is None:
841
846
  raise ValueError(
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import math
2
3
  from typing import Any, Dict, List, Optional, Protocol
3
4
  from teddy_executor.core.ports.outbound.config_service import IConfigService
4
5
  from teddy_executor.core.domain.models.exceptions import ConfigurationError
@@ -274,12 +275,25 @@ class LiteLLMAdapter(ILlmClient):
274
275
  def get_completion_cost(
275
276
  self, completion_response: Any, model_override: Optional[str] = None
276
277
  ) -> float:
277
- """Calculates the precise USD cost of a completion response."""
278
+ """Calculates the precise USD cost of a completion response.
279
+
280
+ Prefers the cost the provider already reported on the response (litellm
281
+ stores it in ``_hidden_params["response_cost"]``) because it reflects the
282
+ vendor that actually served the request. Falls back to the registry
283
+ recompute when no reported cost is present.
284
+ """
285
+ reported = self._reported_cost(completion_response)
286
+ if reported is not None:
287
+ self._mark_cost_recorded(completion_response)
288
+ return reported
289
+
278
290
  litellm = self._get_litellm()
279
291
  try:
280
- return float(
292
+ cost = float(
281
293
  litellm.completion_cost(completion_response=completion_response)
282
294
  )
295
+ self._mark_cost_recorded(completion_response)
296
+ return cost
283
297
  except (Exception, TypeError) as e:
284
298
  if "This model isn't mapped yet" in str(e) and self._hydrator:
285
299
  candidates = set()
@@ -291,11 +305,13 @@ class LiteLLMAdapter(ILlmClient):
291
305
 
292
306
  if self._hydrate_all_candidates(candidates):
293
307
  try:
294
- return float(
308
+ cost = float(
295
309
  litellm.completion_cost(
296
310
  completion_response=completion_response
297
311
  )
298
312
  )
313
+ self._mark_cost_recorded(completion_response)
314
+ return cost
299
315
  except (Exception, TypeError) as retry_error:
300
316
  self._log_cost_failure(
301
317
  retry_error, completion_response, model_override
@@ -306,6 +322,70 @@ class LiteLLMAdapter(ILlmClient):
306
322
  self._log_cost_failure(e, completion_response, model_override)
307
323
  return 0.0
308
324
 
325
+ def _reported_cost(self, completion_response: Any) -> Optional[float]:
326
+ """Returns the cost the provider reported on the response, if any.
327
+
328
+ litellm writes the vendor-reported spend to
329
+ ``_hidden_params["response_cost"]``; when that key is absent, the same
330
+ reported spend may instead be carried by the OpenRouter response-cost
331
+ header under ``_hidden_params["additional_headers"]``, exactly as the
332
+ litellm ``get_response_cost_from_hidden_params`` helper reads it. A
333
+ non-dict holder, an absent key, a ``None`` value, or an unconvertible or
334
+ non-finite value all mean "no reported cost" from that source, so the
335
+ read falls through to the next source and ultimately the recompute. A
336
+ ``0.0`` reported cost is a valid free-model price and is returned as-is.
337
+ """
338
+ hidden = getattr(completion_response, "_hidden_params", None)
339
+ if not isinstance(hidden, dict):
340
+ return None
341
+
342
+ direct = self._finite_cost(hidden.get("response_cost"))
343
+ if direct is not None:
344
+ return direct
345
+
346
+ additional_headers = hidden.get("additional_headers")
347
+ if isinstance(additional_headers, dict):
348
+ header_cost = self._finite_cost(
349
+ additional_headers.get("llm_provider-x-litellm-response-cost")
350
+ )
351
+ if header_cost is not None:
352
+ return header_cost
353
+
354
+ return None
355
+
356
+ @staticmethod
357
+ def _finite_cost(value: Any) -> Optional[float]:
358
+ """Converts a reported value to a finite float, or None when unusable.
359
+
360
+ A ``NaN`` or infinite reported cost cannot be a spend, so it is treated
361
+ as absent. The graph at the call site depends only on which price source
362
+ is authoritative, never on a non-finite anomaly.
363
+ """
364
+ if value is None:
365
+ return None
366
+ try:
367
+ number = float(value)
368
+ except (TypeError, ValueError):
369
+ return None
370
+ return number if math.isfinite(number) else None
371
+
372
+ @staticmethod
373
+ def _mark_cost_recorded(completion_response: Any) -> None:
374
+ """Flags the response so the display can trust the recorded cost.
375
+
376
+ A real price was used whenever a reported value is returned or the
377
+ registry recompute succeeds, including a valid free-model ``0.0``. The
378
+ fallback ``0.0`` (a recompute failure) is deliberately NOT marked, so
379
+ the display keeps its ``$???`` placeholder for a genuinely unpriced
380
+ model. A response that forbids attribute assignment still yields its
381
+ cost; only the display hint is lost.
382
+ """
383
+ try:
384
+ completion_response._teddy_cost_recorded = True
385
+ except (AttributeError, TypeError):
386
+ # Only the display hint is affected; the cost itself is unaffected.
387
+ pass
388
+
309
389
  def _log_cost_failure(
310
390
  self, error: Exception, completion_response: Any, model_override: Optional[str]
311
391
  ) -> None:
@@ -347,12 +427,20 @@ class LiteLLMAdapter(ILlmClient):
347
427
  def _resolve_cost_model(
348
428
  self, completion_response: Any, model_override: Optional[str]
349
429
  ) -> Optional[str]:
350
- """Resolves the model identity used by cost-failure diagnostics."""
351
- if model_override:
352
- return str(model_override)
430
+ """Resolves the model identity used by cost-failure diagnostics.
431
+
432
+ Prefers ``completion_response.model`` because that is the identity the
433
+ registry recompute actually prices against. A configured override names
434
+ the routing alias (e.g. ``openrouter/foo``), which need not be present in
435
+ the registry, so naming it would both mislabel the anomaly summary and
436
+ pick the wrong log tier — silently downgrading a real priced-model
437
+ failure to DEBUG instead of WARNING.
438
+ """
353
439
  model_id = getattr(completion_response, "model", None)
354
440
  if model_id:
355
441
  return str(model_id)
442
+ if model_override:
443
+ return str(model_override)
356
444
  config_model = self._config_service.get_setting("llm.model")
357
445
  return str(config_model) if config_model else None
358
446
 
@@ -97,6 +97,24 @@ class ExecutionOrchestrator(IRunPlanUseCase):
97
97
  halt_execution = True
98
98
  return action_logs
99
99
 
100
+ def _emit_preexecuted_console_log(
101
+ self, action: ActionData, action_log: ActionLog
102
+ ) -> None:
103
+ """Emit the console lines a freshly dispatched action would log.
104
+
105
+ Actions executed manually in the TUI run silently, so on plan
106
+ submission the orchestrator re-emits the same progress lines
107
+ ``ActionDispatcher`` logs for freshly dispatched actions
108
+ (``{ACTION} - {description}`` then the uppercase status). MESSAGE
109
+ actions stay silent, matching the dispatcher.
110
+ """
111
+ action_name = action.type.upper()
112
+ if action_name == "MESSAGE":
113
+ return
114
+ log_desc = f" - {action.description}" if action.description else ""
115
+ logger.info(f"{action_name}{log_desc}")
116
+ logger.info(action_log.status.value.upper())
117
+
100
118
  def _handle_action_in_loop(
101
119
  self,
102
120
  action: ActionData,
@@ -116,6 +134,7 @@ class ExecutionOrchestrator(IRunPlanUseCase):
116
134
  )
117
135
 
118
136
  if action.executed and action.action_log:
137
+ self._emit_preexecuted_console_log(action, action.action_log)
119
138
  should_halt = (
120
139
  action.action_log.status == ActionStatus.FAILURE
121
140
  and not action.params.get("allow_failure")
@@ -98,6 +98,13 @@ class PlanningService(IPlanningUseCase):
98
98
  lambda: self._run_planning_phase(messages, model, meta)
99
99
  )
100
100
 
101
+ # Persist the explicit recorded-cost signal (Option B): a real price was
102
+ # used for this turn whenever the adapter marked the response, so a
103
+ # later turn can show the accumulated figure even for an unpriced model.
104
+ # The `is True` guard keeps an auto-specced Mock response from counting.
105
+ if getattr(response, "_teddy_cost_recorded", False) is True:
106
+ meta["cost_recorded"] = True
107
+
101
108
  cost_val = self._prompt_manager.log_telemetry(token_count, turn_cost)
102
109
  plan_path = (turn_path / "plan.md").as_posix()
103
110
  self._file_system_manager.write_file(plan_path, plan_content)
@@ -229,9 +236,13 @@ class PlanningService(IPlanningUseCase):
229
236
  )
230
237
 
231
238
  pricing_supported = self._llm_client.supports_pricing(model=model)
239
+ # Option B: gate on an explicit recorded-cost signal, never on
240
+ # `cumulative_cost > 0`, because a free model legitimately records 0.0
241
+ # and cannot be distinguished from "no cost" by cost > 0.
242
+ cost_recorded = meta.get("cost_recorded") is True
232
243
  cost_str = (
233
244
  f"${cumulative_cost:.4f}"
234
- if context_window > 0 and pricing_supported
245
+ if context_window > 0 and (pricing_supported or cost_recorded)
235
246
  else "$???"
236
247
  )
237
248
  self._user_interactor.display_message(
@@ -21,6 +21,11 @@ from teddy_executor.core.utils.markdown import embed_in_fence
21
21
 
22
22
  logger = logging.getLogger(__name__)
23
23
 
24
+ # The prompt shown when a resume injects a present-but-blank `-m` and the run is
25
+ # interactive. Mirrors the start-boundary opening prompt so both entry points
26
+ # present the same question.
27
+ _NEXT_INSTRUCTION_PROMPT = "What are we working on?"
28
+
24
29
  if TYPE_CHECKING:
25
30
  from teddy_executor.core.domain.models.planning_ports import (
26
31
  SessionPorts,
@@ -106,6 +111,42 @@ class SessionLifecycleManager:
106
111
  )
107
112
  return (session_name, report)
108
113
 
114
+ if state in (SessionState.EMPTY, SessionState.COMPLETE_TURN):
115
+ return self._resume_ready_turn(
116
+ session_name,
117
+ state,
118
+ turn_path,
119
+ orchestrator,
120
+ interactive,
121
+ project_context,
122
+ pipeline,
123
+ message,
124
+ )
125
+
126
+ return (session_name, None)
127
+
128
+ def _resume_ready_turn( # noqa: PLR0913 # threads the resume state-machine inputs
129
+ self,
130
+ session_name: str,
131
+ state: SessionState,
132
+ turn_path: str,
133
+ orchestrator: IRunPlanUseCase,
134
+ interactive: bool,
135
+ project_context: Optional[Any],
136
+ pipeline: bool,
137
+ message: Optional[str],
138
+ ) -> tuple[str, Optional[ExecutionReport]]:
139
+ """Drive resume for an EMPTY or COMPLETE_TURN session ready to plan.
140
+
141
+ A present-but-blank message is resolved first (interactive prompt, empty
142
+ reply terminates; non-interactive normalizes to absent). An EMPTY turn
143
+ appends the message to the initial request or the previous report, then
144
+ plans in place. A COMPLETE_TURN turn appends a ``## User Request``
145
+ section, transitions to the next turn, then plans.
146
+ """
147
+ message, terminated = self._resolve_blank_message(message, interactive)
148
+ if terminated:
149
+ return (session_name, None)
109
150
  if state == SessionState.EMPTY:
110
151
  if message:
111
152
  if Path(turn_path).name == "01":
@@ -120,22 +161,38 @@ class SessionLifecycleManager:
120
161
  pipeline=pipeline,
121
162
  message=message,
122
163
  )
164
+ if message:
165
+ self._append_user_request(turn_path, message)
166
+ next_turn_dir = self._session_service.transition_to_next_turn(
167
+ plan_path=f"{turn_path}/plan.md"
168
+ )
169
+ return self._handle_planning_and_execution(
170
+ next_turn_dir,
171
+ orchestrator,
172
+ interactive,
173
+ project_context=project_context,
174
+ message=message,
175
+ )
123
176
 
124
- if state == SessionState.COMPLETE_TURN:
125
- if message:
126
- self._append_user_request(turn_path, message)
127
- next_turn_dir = self._session_service.transition_to_next_turn(
128
- plan_path=f"{turn_path}/plan.md"
129
- )
130
- return self._handle_planning_and_execution(
131
- next_turn_dir,
132
- orchestrator,
133
- interactive,
134
- project_context=project_context,
135
- message=message,
136
- )
177
+ def _resolve_blank_message(
178
+ self, message: Optional[str], interactive: bool
179
+ ) -> tuple[Optional[str], bool]:
180
+ """Resolve a present-but-blank message in the EMPTY/COMPLETE_TURN branches.
137
181
 
138
- return (session_name, None)
182
+ A blank ``-m`` must not seed a turn with no real instruction. When the
183
+ run is interactive, the user is prompted for the next instruction and an
184
+ empty reply terminates the session (abort idiom, reported by ``True``).
185
+ A non-interactive run cannot block, so the message normalizes to absent.
186
+ A present-and-non-blank or absent message is returned unchanged.
187
+ """
188
+ if message is None or message.strip():
189
+ return message, False
190
+ if not interactive:
191
+ return None, False
192
+ reply = self._user_interactor.ask_question(_NEXT_INSTRUCTION_PROMPT)
193
+ if not reply or not reply.strip():
194
+ return None, True
195
+ return reply, False
139
196
 
140
197
  def _parse_pending_plan(
141
198
  self, turn_path: str, plan_path: str, message: Optional[str]
@@ -488,6 +488,11 @@ class SessionService(ISessionManager):
488
488
  if key in current_meta:
489
489
  meta[key] = current_meta[key]
490
490
 
491
+ # A recorded cost stays recorded for the rest of the session, so an
492
+ # unpriced model keeps showing its accumulated figure, not "$???".
493
+ if current_meta.get("cost_recorded") is True:
494
+ meta["cost_recorded"] = True
495
+
491
496
  if is_validation_failure:
492
497
  meta["is_replan"] = True
493
498
  if "user_request" in current_meta: