teddy-cli 0.1.17.dev1320__tar.gz → 0.1.17.dev1321__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 (163) hide show
  1. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/PKG-INFO +1 -1
  2. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/pyproject.toml +1 -1
  3. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/__main__.py +18 -0
  4. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/session_cli_handlers.py +42 -2
  5. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/session_loop_guard.py +10 -0
  6. teddy_cli-0.1.17.dev1321/src/teddy_executor/core/services/session_loop_guard.py +133 -0
  7. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/config.yaml +2 -2
  8. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/ci.md +1 -0
  9. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/makefile.md +2 -0
  10. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/pre-commit.md +2 -0
  11. teddy_cli-0.1.17.dev1320/src/teddy_executor/core/services/session_loop_guard.py +0 -62
  12. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/.gitignore +0 -0
  13. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/LICENSE +0 -0
  14. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/README.md +0 -0
  15. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/__init__.py +0 -0
  16. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/__init__.py +0 -0
  17. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/__init__.py +0 -0
  18. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/cli_formatter.py +0 -0
  19. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/cli_helpers.py +0 -0
  20. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer.py +0 -0
  21. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_app.py +0 -0
  22. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_editor.py +0 -0
  23. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_execution.py +0 -0
  24. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_helpers.py +0 -0
  25. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_logic.py +0 -0
  26. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_previews.py +0 -0
  27. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_widgets.py +0 -0
  28. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/__init__.py +0 -0
  29. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/console_interactor.py +0 -0
  30. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/console_interactor_ask_loop.py +0 -0
  31. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/console_interactor_helpers.py +0 -0
  32. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/console_tooling.py +0 -0
  33. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/filesystem_helpers.py +0 -0
  34. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/litellm_adapter.py +0 -0
  35. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/local_file_system_adapter.py +0 -0
  36. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/local_repo_tree_generator.py +0 -0
  37. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/openrouter_hydrator.py +0 -0
  38. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/shell_adapter.py +0 -0
  39. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/shell_command_builder.py +0 -0
  40. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/suppressed_logging.py +0 -0
  41. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/system_environment_adapter.py +0 -0
  42. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/system_environment_inspector.py +0 -0
  43. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/system_time_adapter.py +0 -0
  44. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/terminal_quit_key_listener.py +0 -0
  45. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/web_scraper_adapter.py +0 -0
  46. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/web_searcher_adapter.py +0 -0
  47. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/adapters/outbound/yaml_config_adapter.py +0 -0
  48. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/container.py +0 -0
  49. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/__init__.py +0 -0
  50. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/__init__.py +0 -0
  51. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/__init__.py +0 -0
  52. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/action_ports.py +0 -0
  53. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/change_set.py +0 -0
  54. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/drift_report.py +0 -0
  55. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/exceptions.py +0 -0
  56. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/execution_report.py +0 -0
  57. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/orchestrator_ports.py +0 -0
  58. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/plan.py +0 -0
  59. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/planning_ports.py +0 -0
  60. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/project_context.py +0 -0
  61. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/report_assembly_data.py +0 -0
  62. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/session.py +0 -0
  63. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/shell_output.py +0 -0
  64. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/domain/models/web_search_results.py +0 -0
  65. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/__init__.py +0 -0
  66. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/__init__.py +0 -0
  67. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/edit_simulator.py +0 -0
  68. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/get_context_use_case.py +0 -0
  69. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/init.py +0 -0
  70. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/plan_parser.py +0 -0
  71. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/plan_reviewer.py +0 -0
  72. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/plan_validator.py +0 -0
  73. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/planning_use_case.py +0 -0
  74. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/inbound/run_plan_use_case.py +0 -0
  75. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/__init__.py +0 -0
  76. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/config_service.py +0 -0
  77. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/environment_inspector.py +0 -0
  78. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/execution_report_assembler.py +0 -0
  79. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/file_system_manager.py +0 -0
  80. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/llm_client.py +0 -0
  81. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/markdown_report_formatter.py +0 -0
  82. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/prompt_manager.py +0 -0
  83. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/quit_key_listener.py +0 -0
  84. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/repo_tree_generator.py +0 -0
  85. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/session_manager.py +0 -0
  86. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/session_repository.py +0 -0
  87. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/shell_executor.py +0 -0
  88. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/system_environment.py +0 -0
  89. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/time_service.py +0 -0
  90. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/user_interactor.py +0 -0
  91. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/web_scraper.py +0 -0
  92. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/ports/outbound/web_searcher.py +0 -0
  93. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/__init__.py +0 -0
  94. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/action_changeset_builder.py +0 -0
  95. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/action_diff_manager.py +0 -0
  96. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/action_dispatcher.py +0 -0
  97. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/action_executor.py +0 -0
  98. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/action_factory.py +0 -0
  99. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/action_parser_complex.py +0 -0
  100. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/action_parser_strategies.py +0 -0
  101. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/context_service.py +0 -0
  102. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/edit_simulator.py +0 -0
  103. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/execution_orchestrator.py +0 -0
  104. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/execution_report_assembler.py +0 -0
  105. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/init_service.py +0 -0
  106. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/markdown_plan_parser.py +0 -0
  107. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/markdown_report_formatter.py +0 -0
  108. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/parser_infrastructure.py +0 -0
  109. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/parser_metadata.py +0 -0
  110. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/parser_reporting.py +0 -0
  111. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/plan_validator.py +0 -0
  112. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/planning_service.py +0 -0
  113. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/prompt_manager.py +0 -0
  114. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/session_lifecycle_manager.py +0 -0
  115. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/session_orchestrator.py +0 -0
  116. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/session_planner.py +0 -0
  117. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/session_pruning_service.py +0 -0
  118. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/session_replanner.py +0 -0
  119. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/session_repository.py +0 -0
  120. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/session_service.py +0 -0
  121. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/templates/execution_report.md.j2 +0 -0
  122. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/update_checker.py +0 -0
  123. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/__init__.py +0 -0
  124. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/edit.py +0 -0
  125. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/edit_matcher.py +0 -0
  126. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/edit_matcher_heuristics.py +0 -0
  127. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/execute.py +0 -0
  128. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/filesystem.py +0 -0
  129. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/helpers.py +0 -0
  130. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/services/validation_rules/message.py +0 -0
  131. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/__init__.py +0 -0
  132. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/diff.py +0 -0
  133. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/interrupt_guard.py +0 -0
  134. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/io.py +0 -0
  135. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/markdown.py +0 -0
  136. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/paths.py +0 -0
  137. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/serialization.py +0 -0
  138. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/session_notices.py +0 -0
  139. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/stdin_ownership.py +0 -0
  140. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/string.py +0 -0
  141. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/core/utils/terminal.py +0 -0
  142. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/prompts.py +0 -0
  143. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/registries/__init__.py +0 -0
  144. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/registries/infrastructure.py +0 -0
  145. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/registries/reviewer.py +0 -0
  146. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/registries/validators.py +0 -0
  147. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/MRP.md +0 -0
  148. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/__init__.py +0 -0
  149. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/__init__.py +0 -0
  150. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/init.context +0 -0
  151. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/prompts/architect.md +0 -0
  152. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/prompts/assistant.md +0 -0
  153. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/prompts/debugger.md +0 -0
  154. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/prompts/developer.md +0 -0
  155. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/prompts/pathfinder.md +0 -0
  156. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/config/prompts/prototyper.md +0 -0
  157. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/ARCHITECTURE.md +0 -0
  158. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/PROJECT.md +0 -0
  159. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/case-file.md +0 -0
  160. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/component-design.md +0 -0
  161. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/milestone.md +0 -0
  162. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/src/teddy_executor/resources/templates/specification-document.md +0 -0
  163. {teddy_cli-0.1.17.dev1320 → teddy_cli-0.1.17.dev1321}/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.1.17.dev1320
3
+ Version: 0.1.17.dev1321
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.1.17.dev1320"
3
+ version = "0.1.17.dev1321"
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 = [
@@ -214,6 +214,16 @@ OPT_PIPELINE = typer.Option(
214
214
  "-p",
215
215
  help="Pipeline mode: auto-approve all actions, requires -m, exits after first ## Message.",
216
216
  )
217
+ OPT_MAX_TURNS = typer.Option(
218
+ None,
219
+ "--max-turns",
220
+ help="Maximum turns for a non-interactive run (overrides config).",
221
+ )
222
+ OPT_MAX_COST = typer.Option(
223
+ None,
224
+ "--max-cost",
225
+ help="Maximum session cost in dollars for a non-interactive run.",
226
+ )
217
227
 
218
228
 
219
229
  @app.command()
@@ -255,6 +265,8 @@ def start( # noqa: PLR0913
255
265
  api_key: Optional[str] = typer.Option(
256
266
  None, "--api-key", help="LLM API key override."
257
267
  ),
268
+ max_turns: Optional[int] = OPT_MAX_TURNS,
269
+ max_cost: Optional[float] = OPT_MAX_COST,
258
270
  ):
259
271
  """
260
272
  Initializes a new session directory and bootstraps it for Turn 1.
@@ -293,6 +305,8 @@ def start( # noqa: PLR0913
293
305
  additional_context=additional_context,
294
306
  model=model,
295
307
  api_key=api_key,
308
+ max_turns=max_turns,
309
+ max_cost=max_cost,
296
310
  )
297
311
 
298
312
 
@@ -537,6 +551,8 @@ def resume( # noqa: PLR0913
537
551
  ),
538
552
  ),
539
553
  pipeline: bool = OPT_PIPELINE,
554
+ max_turns: Optional[int] = OPT_MAX_TURNS,
555
+ max_cost: Optional[float] = OPT_MAX_COST,
540
556
  ):
541
557
  """
542
558
  Intelligently resumes the last turn of a session or starts a new one.
@@ -565,6 +581,8 @@ def resume( # noqa: PLR0913
565
581
  agent=agent,
566
582
  message=message,
567
583
  pipeline=pipeline,
584
+ max_turns=max_turns,
585
+ max_cost=max_cost,
568
586
  )
569
587
 
570
588
 
@@ -334,7 +334,7 @@ def _resolve_initial_turn(session_manager: ISessionManager, session_name: str) -
334
334
 
335
335
  def _emit_guard_termination(guard_reason: Optional[str]) -> None:
336
336
  """Prints a guardrail termination reason: first line red, remainder plain."""
337
- reason = guard_reason or "YOLO guardrail limit reached."
337
+ reason = guard_reason or "Guardrail limit reached."
338
338
  lines = reason.lstrip("\n").split("\n", 1)
339
339
  typer.secho("")
340
340
  typer.secho(lines[0], fg=typer.colors.RED)
@@ -356,6 +356,23 @@ def _should_exit_pipeline(pipeline: bool, report: Any) -> bool:
356
356
  )
357
357
 
358
358
 
359
+ def _is_communication_turn(report: Any) -> bool:
360
+ """True when the report carries a non-empty MESSAGE action.
361
+
362
+ A communication turn means the human is present and approves the
363
+ continuation, so the loop re-anchors the guard baseline before the limit
364
+ check. Mirrors the orchestrator's canonical predicate: a MESSAGE action
365
+ with non-empty details.
366
+ """
367
+ if not report.action_logs:
368
+ return False
369
+ return any(
370
+ (getattr(log_entry, "action_type", None) or "").upper() == "MESSAGE"
371
+ and (getattr(log_entry, "details", "") or "").strip()
372
+ for log_entry in report.action_logs
373
+ )
374
+
375
+
359
376
  def _orchestrate_session_loop( # noqa: PLR0913
360
377
  container: Container,
361
378
  session_name: str,
@@ -363,6 +380,8 @@ def _orchestrate_session_loop( # noqa: PLR0913
363
380
  no_copy: bool,
364
381
  pipeline: bool = False,
365
382
  message: Optional[str] = None,
383
+ max_turns: Optional[int] = None,
384
+ max_cost: Optional[float] = None,
366
385
  ) -> None:
367
386
  """Shared turn loop for start and resume commands."""
368
387
  from teddy_executor.adapters.inbound.cli_helpers import handle_report_output
@@ -378,7 +397,11 @@ def _orchestrate_session_loop( # noqa: PLR0913
378
397
  initial_cost = session_manager.get_cumulative_cost(session_name)
379
398
 
380
399
  loop_guard = container.resolve(
381
- ISessionLoopGuard, initial_turn=initial_turn, initial_cost=initial_cost
400
+ ISessionLoopGuard,
401
+ initial_turn=initial_turn,
402
+ initial_cost=initial_cost,
403
+ max_turns=max_turns,
404
+ max_cost=max_cost,
382
405
  )
383
406
 
384
407
  # Two-phase Ctrl+C interrupt (tracer bullet): the container shares ONE
@@ -431,6 +454,15 @@ def _orchestrate_session_loop( # noqa: PLR0913
431
454
  break
432
455
 
433
456
  cumulative_cost = float(report.metadata.get("cumulative_cost", 0.0))
457
+
458
+ # A communication turn means the human is present and approves the
459
+ # continuation, so re-anchor the budget BEFORE the limit check. The
460
+ # message turn therefore never trips the limit, and the next segment
461
+ # starts fresh. The guard itself gates the reset on
462
+ # guardrails.message_reset.
463
+ if _is_communication_turn(report):
464
+ loop_guard.reset_baseline(turn_count, cumulative_cost)
465
+
434
466
  should_continue, guard_reason = loop_guard.should_continue(
435
467
  turn_count, cumulative_cost, interactive
436
468
  )
@@ -628,6 +660,8 @@ def handle_new_session( # noqa: PLR0913
628
660
  api_key: Optional[str] = None,
629
661
  setup_editor: Optional[bool] = None,
630
662
  setup_api_key: Optional[bool] = None,
663
+ max_turns: Optional[int] = None,
664
+ max_cost: Optional[float] = None,
631
665
  ):
632
666
  """Logic for the 'start' command."""
633
667
  fired = _start_background_update_check(container)
@@ -681,6 +715,8 @@ def handle_new_session( # noqa: PLR0913
681
715
  interactive=interactive,
682
716
  no_copy=no_copy,
683
717
  pipeline=pipeline,
718
+ max_turns=max_turns,
719
+ max_cost=max_cost,
684
720
  )
685
721
 
686
722
  except Exception as e:
@@ -1145,6 +1181,8 @@ def handle_resume_session( # noqa: PLR0913
1145
1181
  pipeline: bool = False,
1146
1182
  setup_editor: Optional[bool] = None,
1147
1183
  setup_api_key: Optional[bool] = None,
1184
+ max_turns: Optional[int] = None,
1185
+ max_cost: Optional[float] = None,
1148
1186
  ):
1149
1187
  """Logic for the 'resume' command."""
1150
1188
  fired = _start_background_update_check(container)
@@ -1185,6 +1223,8 @@ def handle_resume_session( # noqa: PLR0913
1185
1223
  no_copy=no_copy,
1186
1224
  message=message,
1187
1225
  pipeline=pipeline,
1226
+ max_turns=max_turns,
1227
+ max_cost=max_cost,
1188
1228
  )
1189
1229
 
1190
1230
  except Exception as e:
@@ -17,3 +17,13 @@ class ISessionLoopGuard(Protocol):
17
17
  how to adjust the configuration.
18
18
  """
19
19
  ...
20
+
21
+ def reset_baseline(self, turn_count: int, cumulative_cost: float) -> None:
22
+ """
23
+ Re-anchors the turn-count and cost baselines to the given values.
24
+
25
+ A human-approved message turn re-anchors the baselines so the next
26
+ segment gets a fresh budget. Implementations measure every later
27
+ ``should_continue`` call as a delta from the new baselines.
28
+ """
29
+ ...
@@ -0,0 +1,133 @@
1
+ from typing import Any, Optional
2
+
3
+ from teddy_executor.core.ports.outbound import IConfigService
4
+ from teddy_executor.core.ports.outbound.session_loop_guard import ISessionLoopGuard
5
+ from teddy_executor.core.ports.outbound.system_environment import ISystemEnvironment
6
+
7
+
8
+ # Sentinel distinguishing "key absent" from a present falsy value, so the
9
+ # legacy `yolo_guardrails` namespace is consulted only when the renamed
10
+ # `guardrails` key is missing.
11
+ _UNSET = object()
12
+
13
+
14
+ class ProductionSessionLoopGuard(ISessionLoopGuard):
15
+ """
16
+ Production implementation: bounds a non-interactive run by turns and cost.
17
+ """
18
+
19
+ def __init__( # noqa: PLR0913 # Explicit DI: config, environment, baselines, and CLI overrides.
20
+ self,
21
+ config_service: IConfigService,
22
+ system_environment: ISystemEnvironment,
23
+ initial_turn: int,
24
+ initial_cost: float,
25
+ max_turns: Optional[int] = None,
26
+ max_cost: Optional[float] = None,
27
+ ) -> None:
28
+ self._config_service = config_service
29
+ self._system_environment = system_environment
30
+ self._initial_turn = initial_turn
31
+ self._initial_cost = initial_cost
32
+ # A CLI-supplied limit is the most specific source and wins outright.
33
+ self._max_turns_override = max_turns
34
+ self._max_cost_override = max_cost
35
+
36
+ def _read_config(self, key: str, default: Any) -> Any:
37
+ """Reads ``guardrails.<key>`` with a legacy ``yolo_guardrails`` fallback.
38
+
39
+ Existing user configs still use the ``yolo_guardrails`` namespace, so
40
+ when the renamed ``guardrails`` key is absent the legacy key is read
41
+ before the default applies.
42
+ """
43
+ value = self._config_service.get_setting(f"guardrails.{key}", _UNSET)
44
+ if value is _UNSET:
45
+ value = self._config_service.get_setting(f"yolo_guardrails.{key}", _UNSET)
46
+ return default if value is _UNSET else value
47
+
48
+ def _resolve_limit(
49
+ self,
50
+ override: Optional[float],
51
+ env_key: str,
52
+ config_key: str,
53
+ default: float,
54
+ ) -> Any:
55
+ """Resolves one limit through the precedence chain.
56
+
57
+ Order: an explicit CLI override, then the environment variable, then the
58
+ config value, then the default. The config value falls back to the
59
+ default when it is absent or falsy; an explicit override of 0 still wins.
60
+ """
61
+ if override is not None:
62
+ return override
63
+ env_value = self._system_environment.get_env(env_key)
64
+ if env_value:
65
+ return env_value
66
+ return self._read_config(config_key, default) or default
67
+
68
+ def _resolve_max_turns(self) -> int:
69
+ """Resolves the turn limit: CLI flag, then env var, then config, then 150."""
70
+ return int(
71
+ self._resolve_limit(
72
+ self._max_turns_override, "TEDDY_MAX_TURNS", "max_turns", 150
73
+ )
74
+ )
75
+
76
+ def _resolve_max_cost(self) -> float:
77
+ """Resolves the cost limit: CLI flag, then env var, then config, then 5.0."""
78
+ return float(
79
+ self._resolve_limit(
80
+ self._max_cost_override,
81
+ "TEDDY_MAX_SESSION_COST",
82
+ "max_session_cost",
83
+ 5.0,
84
+ )
85
+ )
86
+
87
+ def should_continue(
88
+ self, turn_count: int, cumulative_cost: float, interactive: bool
89
+ ) -> tuple[bool, Optional[str]]:
90
+ if interactive:
91
+ return True, None
92
+
93
+ if not bool(self._read_config("enabled", True)):
94
+ return True, None
95
+
96
+ max_turns = self._resolve_max_turns()
97
+ max_cost = self._resolve_max_cost()
98
+
99
+ turn_delta = turn_count - self._initial_turn
100
+ cost_delta = cumulative_cost - self._initial_cost
101
+
102
+ if turn_delta >= max_turns:
103
+ config_path = self._config_service.get_config_path()
104
+ import os as _os
105
+
106
+ rel_path = _os.path.relpath(config_path)
107
+ return False, (
108
+ f"Turn limit reached: {turn_delta}/{max_turns} turns in this run.\n"
109
+ f"To change this limit, set 'guardrails.max_turns' in {rel_path}."
110
+ )
111
+
112
+ if cost_delta >= max_cost:
113
+ config_path = self._config_service.get_config_path()
114
+ import os as _os
115
+
116
+ rel_path = _os.path.relpath(config_path)
117
+ return False, (
118
+ f"Cost limit reached: ${cost_delta:.2f}/${max_cost:.2f} in this run.\n"
119
+ f"To change this limit, set 'guardrails.max_session_cost' in {rel_path}."
120
+ )
121
+
122
+ return True, None
123
+
124
+ def reset_baseline(self, turn_count: int, cumulative_cost: float) -> None:
125
+ """Re-anchors both baselines after a message turn, when enabled.
126
+
127
+ The reset is gated by ``guardrails.message_reset`` (default true), so an
128
+ operator can keep the baselines fixed for the whole run.
129
+ """
130
+ if not bool(self._read_config("message_reset", True)):
131
+ return
132
+ self._initial_turn = turn_count
133
+ self._initial_cost = cumulative_cost
@@ -39,9 +39,9 @@ yolo_default: false
39
39
 
40
40
  # Safety limits enforced in non-interactive runs (--yolo and --pipeline).
41
41
  # Limits are per-run: `teddy resume` starts counting from 0 again.
42
- yolo_guardrails:
42
+ guardrails:
43
43
  enabled: true
44
- max_turns: 99
44
+ max_turns: 150
45
45
  max_session_cost: 5.00
46
46
  message_reset: true
47
47
 
@@ -12,6 +12,7 @@ The CI pipeline consists of two parallel jobs:
12
12
  - Runs on each push and pull request.
13
13
  - Executes across multiple OS targets (e.g., ubuntu-latest, windows-latest, macos-latest).
14
14
  - Runs the full test suite: `{runner} pytest`.
15
+ - Discovers tests via `testpaths` in `pyproject.toml`; the CI step passes no path so the config stays the single source of truth.
15
16
  - **Blocking:** If this job fails, the CI pipeline is marked as failed.
16
17
 
17
18
  ### Job 2: Non-Blocking Quality Checks
@@ -99,6 +99,8 @@ test:
99
99
 
100
100
  **Usage:** `make test`
101
101
 
102
+ **Test scope:** declare the tests directory once via `testpaths` in `pyproject.toml`. The `test` target passes no path to `pytest`, so the config stays the single source of truth.
103
+
102
104
  ## Commit Workflow
103
105
 
104
106
  `make commit` is **local-only**: it stages all local changes, runs the pre-commit hooks once (an advisory auto-fix pass that re-stages any auto-formatted files), and commits. It does **not** pull or push — the push is deferred to the session Conclusion via `make push` (see [Push (Deferred to Conclusion)](#push-deferred-to-conclusion)).
@@ -77,6 +77,8 @@ repos:
77
77
 
78
78
  **Tip:** Pin exact `rev` tags so every teammate runs identical checks.
79
79
 
80
+ **Line endings:** The whitespace hooks (`trailing-whitespace`, `end-of-file-fixer`) fix trailing spaces and the missing final newline. They do NOT normalize LF versus CRLF. Add a committed `.gitattributes` with the rule `* text=auto eol=lf`. Git then stores and checks out text as LF on every platform. This rule applies to every clone and to unstaged files, so it is more robust than a hook. TeDDy does NOT create this file. Create it yourself in the project root.
81
+
80
82
  ## 3. Install the hooks
81
83
 
82
84
  ```shell
@@ -1,62 +0,0 @@
1
- from typing import Optional
2
-
3
- from teddy_executor.core.ports.outbound import IConfigService
4
- from teddy_executor.core.ports.outbound.session_loop_guard import ISessionLoopGuard
5
-
6
-
7
- class ProductionSessionLoopGuard(ISessionLoopGuard):
8
- """
9
- Production implementation: enforces YOLO guardrails in non-interactive mode.
10
- """
11
-
12
- def __init__(
13
- self,
14
- config_service: IConfigService,
15
- initial_turn: int,
16
- initial_cost: float,
17
- ) -> None:
18
- self._config_service = config_service
19
- self._initial_turn = initial_turn
20
- self._initial_cost = initial_cost
21
-
22
- def should_continue(
23
- self, turn_count: int, cumulative_cost: float, interactive: bool
24
- ) -> tuple[bool, Optional[str]]:
25
- if interactive:
26
- return True, None
27
-
28
- if not self._config_service.get_setting("yolo_guardrails.enabled", True):
29
- return True, None
30
-
31
- max_turns = int(
32
- self._config_service.get_setting("yolo_guardrails.max_turns", 99) or 99
33
- )
34
- max_cost = float(
35
- self._config_service.get_setting("yolo_guardrails.max_session_cost", 5.0)
36
- or 5.0
37
- )
38
-
39
- turn_delta = turn_count - self._initial_turn
40
- cost_delta = cumulative_cost - self._initial_cost
41
-
42
- if turn_delta >= max_turns:
43
- config_path = self._config_service.get_config_path()
44
- import os as _os
45
-
46
- rel_path = _os.path.relpath(config_path)
47
- return False, (
48
- f"YOLO turn limit reached: {turn_delta}/{max_turns} turns in this run.\n"
49
- f"To change this limit, set 'yolo_guardrails.max_turns' in {rel_path}."
50
- )
51
-
52
- if cost_delta >= max_cost:
53
- config_path = self._config_service.get_config_path()
54
- import os as _os
55
-
56
- rel_path = _os.path.relpath(config_path)
57
- return False, (
58
- f"YOLO cost limit reached: ${cost_delta:.2f}/${max_cost:.2f} in this run.\n"
59
- f"To change this limit, set 'yolo_guardrails.max_session_cost' in {rel_path}."
60
- )
61
-
62
- return True, None