teddy-cli 0.1.5__tar.gz → 0.1.7__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.
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/PKG-INFO +1 -1
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/pyproject.toml +1 -1
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/__main__.py +52 -15
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/session_cli_handlers.py +91 -4
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_execution.py +3 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/system_environment_inspector.py +17 -1
- teddy_cli-0.1.7/src/teddy_executor/core/ports/inbound/init.py +47 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/environment_inspector.py +10 -1
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/context_service.py +7 -10
- teddy_cli-0.1.7/src/teddy_executor/core/services/init_service.py +138 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/markdown_plan_parser.py +5 -3
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/parser_infrastructure.py +3 -1
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/helpers.py +1 -1
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/config.yaml +0 -5
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/architect.xml +2 -5
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/assistant.xml +0 -3
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/debugger.xml +1 -4
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/developer.xml +2 -5
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/pathfinder.xml +2 -5
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/prototyper.xml +22 -20
- teddy_cli-0.1.5/src/teddy_executor/core/ports/inbound/init.py +0 -15
- teddy_cli-0.1.5/src/teddy_executor/core/services/init_service.py +0 -80
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/LICENSE +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/cli_formatter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/cli_helpers.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/console_plan_reviewer.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_app.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_editor.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_helpers.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_logic.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_previews.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_widgets.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/console_interactor.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/console_interactor_ask_loop.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/console_interactor_helpers.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/console_tooling.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/filesystem_helpers.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/litellm_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/local_file_system_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/local_repo_tree_generator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/openrouter_hydrator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/shell_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/shell_command_builder.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/system_environment_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/system_time_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/web_scraper_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/web_searcher_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/outbound/yaml_config_adapter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/container.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/action_ports.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/change_set.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/exceptions.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/execution_report.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/orchestrator_ports.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/plan.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/planning_ports.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/project_context.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/report_assembly_data.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/session.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/shell_output.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/domain/models/web_search_results.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/edit_simulator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/get_context_use_case.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/plan_parser.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/plan_reviewer.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/plan_validator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/planning_use_case.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/inbound/run_plan_use_case.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/config_service.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/execution_report_assembler.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/file_system_manager.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/llm_client.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/markdown_report_formatter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/prompt_manager.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/repo_tree_generator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/session_loop_guard.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/session_manager.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/session_repository.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/shell_executor.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/system_environment.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/time_service.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/user_interactor.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/web_scraper.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/web_searcher.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/action_changeset_builder.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/action_diff_manager.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/action_dispatcher.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/action_executor.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/action_factory.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/action_parser_complex.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/action_parser_strategies.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/edit_simulator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/execution_orchestrator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/execution_report_assembler.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/markdown_report_formatter.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/parser_metadata.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/parser_reporting.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/plan_validator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/planning_service.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/prompt_manager.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_lifecycle_manager.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_loop_guard.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_orchestrator.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_planner.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_pruning_service.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_replanner.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_repository.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/session_service.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/templates/execution_report.md.j2 +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/update_checker.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/edit.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/edit_matcher.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/edit_matcher_heuristics.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/execute.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/filesystem.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/message.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/utils/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/utils/diff.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/utils/io.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/utils/markdown.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/utils/serialization.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/utils/string.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/prompts.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/registries/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/registries/infrastructure.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/registries/reviewer.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/registries/validators.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/.gitignore +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/__init__.py +0 -0
- {teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/init.context +0 -0
|
@@ -172,18 +172,61 @@ def start( # noqa: PLR0913
|
|
|
172
172
|
)
|
|
173
173
|
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
init_app = typer.Typer()
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@init_app.callback(invoke_without_command=True)
|
|
179
|
+
def init_callback(ctx: typer.Context):
|
|
177
180
|
"""
|
|
178
181
|
Initializes the .teddy directory and pre-warms heavy imports for faster startup.
|
|
179
182
|
"""
|
|
180
183
|
from teddy_executor.adapters.inbound.cli_helpers import prewarm_imports
|
|
184
|
+
from teddy_executor.core.ports.inbound.init import IInitUseCase
|
|
181
185
|
|
|
182
186
|
container = get_container()
|
|
183
187
|
_ensure_project_initialized(container, root_dir=str(Path.cwd()))
|
|
184
188
|
prewarm_imports()
|
|
185
189
|
# Auto-login would trigger here once `teddy login` is implemented (no-op for now)
|
|
186
|
-
|
|
190
|
+
if ctx.invoked_subcommand is not None:
|
|
191
|
+
# A subcommand (e.g., prompts, config) will handle its own initialization
|
|
192
|
+
# and output. Skip the full summary to avoid conflicting messages.
|
|
193
|
+
return
|
|
194
|
+
init_use_case = container.resolve(IInitUseCase)
|
|
195
|
+
summary = init_use_case.ensure_initialized()
|
|
196
|
+
typer.echo(f"TeDDy initialized in .teddy folder. {summary}")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@init_app.command()
|
|
200
|
+
def prompts():
|
|
201
|
+
"""
|
|
202
|
+
Overwrites bundled prompt XMLs in .teddy/prompts/ with defaults.
|
|
203
|
+
"""
|
|
204
|
+
from teddy_executor.core.ports.inbound.init import IInitUseCase
|
|
205
|
+
|
|
206
|
+
container = get_container()
|
|
207
|
+
init_use_case = container.resolve(IInitUseCase)
|
|
208
|
+
status = init_use_case.ensure_prompts_initialized(overwrite=True)
|
|
209
|
+
typer.echo(status)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@init_app.command()
|
|
213
|
+
def config():
|
|
214
|
+
"""
|
|
215
|
+
Overwrites config.yaml, .gitignore, and init.context with defaults.
|
|
216
|
+
"""
|
|
217
|
+
from teddy_executor.core.ports.inbound.init import IInitUseCase
|
|
218
|
+
|
|
219
|
+
container = get_container()
|
|
220
|
+
init_use_case = container.resolve(IInitUseCase)
|
|
221
|
+
status = init_use_case.ensure_config_initialized(overwrite=True)
|
|
222
|
+
typer.echo(status)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
app.add_typer(
|
|
226
|
+
init_app,
|
|
227
|
+
name="init",
|
|
228
|
+
help="Initialize .teddy directory, prompts, or configuration.",
|
|
229
|
+
)
|
|
187
230
|
|
|
188
231
|
|
|
189
232
|
@app.command()
|
|
@@ -239,25 +282,19 @@ def update(
|
|
|
239
282
|
if is_channel_switch:
|
|
240
283
|
typer.echo(f"You are running the latest experimental version ({current}).")
|
|
241
284
|
typer.echo(
|
|
242
|
-
"To switch to the stable release, run:
|
|
243
|
-
)
|
|
244
|
-
typer.echo(
|
|
245
|
-
"To apply prompt updates: delete .teddy/prompts/ and run 'teddy init'"
|
|
285
|
+
"To switch to the stable release, run: pipx uninstall teddy-cli && pipx install teddy-cli"
|
|
246
286
|
)
|
|
287
|
+
typer.echo("To apply prompt updates, run: teddy init prompts")
|
|
247
288
|
elif experimental:
|
|
248
289
|
typer.echo(f"A new experimental version {latest} is available.")
|
|
249
290
|
typer.echo(
|
|
250
|
-
"To upgrade, run:
|
|
251
|
-
)
|
|
252
|
-
typer.echo(
|
|
253
|
-
"To apply prompt updates: delete .teddy/prompts/ and run 'teddy init'"
|
|
291
|
+
"To upgrade, run: pipx upgrade teddy-cli --pip-args '--index-url https://test.pypi.org/simple/'"
|
|
254
292
|
)
|
|
293
|
+
typer.echo("To apply prompt updates, run: teddy init prompts")
|
|
255
294
|
else:
|
|
256
295
|
typer.echo(f"A new version {latest} is available.")
|
|
257
|
-
typer.echo("To upgrade, run:
|
|
258
|
-
typer.echo(
|
|
259
|
-
"To apply prompt updates: delete .teddy/prompts/ and run 'teddy init'"
|
|
260
|
-
)
|
|
296
|
+
typer.echo("To upgrade, run: pipx upgrade teddy-cli")
|
|
297
|
+
typer.echo("To apply prompt updates, run: teddy init prompts")
|
|
261
298
|
|
|
262
299
|
|
|
263
300
|
@app.command()
|
{teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/adapters/inbound/session_cli_handlers.py
RENAMED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess # nosec B404
|
|
1
4
|
from pathlib import Path
|
|
2
5
|
from typing import Dict, Optional, Sequence
|
|
6
|
+
|
|
3
7
|
import typer
|
|
4
8
|
from punq import Container
|
|
5
9
|
|
|
@@ -27,6 +31,84 @@ from teddy_executor.core.services.update_checker import (
|
|
|
27
31
|
)
|
|
28
32
|
|
|
29
33
|
|
|
34
|
+
logger = logging.getLogger(__name__)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _ensure_commit_hooks() -> None:
|
|
38
|
+
"""Install pre-commit hooks if config exists and CLI is available.
|
|
39
|
+
Shows green notification on success, yellow warning if config missing
|
|
40
|
+
or CLI not found."""
|
|
41
|
+
config_path = Path.cwd() / ".pre-commit-config.yaml"
|
|
42
|
+
if not config_path.exists():
|
|
43
|
+
typer.secho(
|
|
44
|
+
"⚠ No pre-commit hooks configured",
|
|
45
|
+
fg=typer.colors.YELLOW,
|
|
46
|
+
err=True,
|
|
47
|
+
)
|
|
48
|
+
return
|
|
49
|
+
if not shutil.which("pre-commit"):
|
|
50
|
+
typer.secho(
|
|
51
|
+
"⚠ pre-commit CLI not found",
|
|
52
|
+
fg=typer.colors.YELLOW,
|
|
53
|
+
err=True,
|
|
54
|
+
)
|
|
55
|
+
return
|
|
56
|
+
try:
|
|
57
|
+
subprocess.run( # nosec B603 B607
|
|
58
|
+
["pre-commit", "install", "-t", "pre-commit", "-t", "post-commit"],
|
|
59
|
+
check=True,
|
|
60
|
+
capture_output=True,
|
|
61
|
+
)
|
|
62
|
+
except subprocess.CalledProcessError:
|
|
63
|
+
logger.debug("pre-commit install failed", exc_info=True)
|
|
64
|
+
return
|
|
65
|
+
typer.secho(
|
|
66
|
+
"✓ pre-commit hooks installed",
|
|
67
|
+
fg=typer.colors.GREEN,
|
|
68
|
+
err=True,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _check_git_initialized() -> None:
|
|
73
|
+
"""Verify git repository status. Auto-initializes if not a repo.
|
|
74
|
+
Shows green notification if already a repo or freshly initialized,
|
|
75
|
+
yellow warning if git CLI not found.
|
|
76
|
+
Only checks the current working directory for a `.git` marker.
|
|
77
|
+
Does NOT walk up parent directories."""
|
|
78
|
+
if not shutil.which("git"):
|
|
79
|
+
typer.secho(
|
|
80
|
+
"⚠ Git CLI not found",
|
|
81
|
+
fg=typer.colors.YELLOW,
|
|
82
|
+
err=True,
|
|
83
|
+
)
|
|
84
|
+
return
|
|
85
|
+
# Check if CWD itself contains a .git marker (directory or file)
|
|
86
|
+
if (Path.cwd() / ".git").exists():
|
|
87
|
+
typer.secho(
|
|
88
|
+
"✓ Git repository detected",
|
|
89
|
+
fg=typer.colors.GREEN,
|
|
90
|
+
err=True,
|
|
91
|
+
)
|
|
92
|
+
return
|
|
93
|
+
# No local .git found – auto-initialize
|
|
94
|
+
try:
|
|
95
|
+
subprocess.run(["git", "init"], check=True, capture_output=True) # nosec B603 B607
|
|
96
|
+
except subprocess.CalledProcessError:
|
|
97
|
+
logger.debug("git init failed", exc_info=True)
|
|
98
|
+
return
|
|
99
|
+
typer.secho(
|
|
100
|
+
"✓ Git repository initialized",
|
|
101
|
+
fg=typer.colors.GREEN,
|
|
102
|
+
err=True,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _run_health_checks() -> None:
|
|
107
|
+
"""Run all startup health checks and display notifications if needed."""
|
|
108
|
+
_ensure_commit_hooks()
|
|
109
|
+
_check_git_initialized()
|
|
110
|
+
|
|
111
|
+
|
|
30
112
|
def _determine_session_name(name: Optional[str], message: Optional[str]) -> str:
|
|
31
113
|
"""Determine session name (slugify message if name is missing)."""
|
|
32
114
|
if name:
|
|
@@ -101,8 +183,7 @@ def _display_update_notification(cache_path: Path) -> None:
|
|
|
101
183
|
typer.echo(
|
|
102
184
|
typer.style(
|
|
103
185
|
f"ℹ A new version {latest} is available. "
|
|
104
|
-
"To upgrade, run:
|
|
105
|
-
" To apply prompt updates: delete .teddy/prompts/ and run 'teddy init'",
|
|
186
|
+
"To upgrade, run: pipx upgrade teddy-cli\n",
|
|
106
187
|
fg=typer.colors.YELLOW,
|
|
107
188
|
)
|
|
108
189
|
)
|
|
@@ -142,7 +223,10 @@ def handle_new_session( # noqa: PLR0913
|
|
|
142
223
|
# 0. Ensure project is initialized
|
|
143
224
|
container.resolve(IInitUseCase).ensure_initialized()
|
|
144
225
|
|
|
145
|
-
# 1.
|
|
226
|
+
# 1. Health checks (advisory, non-blocking)
|
|
227
|
+
_run_health_checks()
|
|
228
|
+
|
|
229
|
+
# 2. Pre-flight checks (Fail-fast before user interaction)
|
|
146
230
|
typer.echo("Checking configurations...", err=True)
|
|
147
231
|
_run_cli_preflight_check(container, agent=agent)
|
|
148
232
|
_echo_config_success(container, agent, model=model)
|
|
@@ -386,7 +470,10 @@ def handle_resume_session( # noqa: PLR0913
|
|
|
386
470
|
_display_update_notification(cache_path)
|
|
387
471
|
|
|
388
472
|
try:
|
|
389
|
-
# 1.
|
|
473
|
+
# 1. Health checks (advisory, non-blocking)
|
|
474
|
+
_run_health_checks()
|
|
475
|
+
|
|
476
|
+
# 2. Pre-flight checks
|
|
390
477
|
typer.echo("Checking configurations...", err=True)
|
|
391
478
|
_run_cli_preflight_check(container)
|
|
392
479
|
|
|
@@ -154,6 +154,9 @@ async def orchestrate_execution(app: ReviewerApp, node: Any, update_fn: Any) ->
|
|
|
154
154
|
action.state = ExecutionStatus.RUNNING
|
|
155
155
|
app._refresh_node(node)
|
|
156
156
|
|
|
157
|
+
# Harvest modified content from pending_temp_file before execution
|
|
158
|
+
harvest_action_content(action, app.INSTRUCTION_MARKER)
|
|
159
|
+
|
|
157
160
|
try:
|
|
158
161
|
import anyio
|
|
159
162
|
|
|
@@ -39,7 +39,7 @@ class SystemEnvironmentInspector(IEnvironmentInspector):
|
|
|
39
39
|
|
|
40
40
|
def get_git_status(self) -> Optional[str]:
|
|
41
41
|
"""
|
|
42
|
-
Gathers the current Git status of the working directory.
|
|
42
|
+
Gathers the current Git status of the working directory (short format).
|
|
43
43
|
"""
|
|
44
44
|
try:
|
|
45
45
|
result = self._run_func( # nosec B603 B607
|
|
@@ -52,3 +52,19 @@ class SystemEnvironmentInspector(IEnvironmentInspector):
|
|
|
52
52
|
return result.stdout.rstrip() if result.stdout else ""
|
|
53
53
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
54
54
|
return None
|
|
55
|
+
|
|
56
|
+
def get_full_git_status(self) -> Optional[str]:
|
|
57
|
+
"""
|
|
58
|
+
Gathers the full Git status of the working directory (including branch info).
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
result = self._run_func( # nosec B603 B607
|
|
62
|
+
["git", "status"],
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True,
|
|
65
|
+
check=True,
|
|
66
|
+
stdin=subprocess.DEVNULL,
|
|
67
|
+
)
|
|
68
|
+
return result.stdout.rstrip() if result.stdout else ""
|
|
69
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
70
|
+
return None
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class IInitUseCase(ABC):
|
|
5
|
+
"""
|
|
6
|
+
Inbound port for project initialization.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def ensure_initialized(self) -> str:
|
|
11
|
+
"""
|
|
12
|
+
Ensures the .teddy/ directory and its essential configuration
|
|
13
|
+
files are present in the current project root.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
A human-readable summary string (e.g., "Config: unchanged. Prompts: updated (3 files).").
|
|
17
|
+
"""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def ensure_prompts_initialized(self, overwrite: bool = False) -> str:
|
|
22
|
+
"""
|
|
23
|
+
Ensures prompt XML files are present in the .teddy/prompts/ directory.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
overwrite: If True, always overwrite existing prompt files with defaults.
|
|
27
|
+
If False (default), only write missing files.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
A human-readable status string (e.g., "Prompts overwritten (6 files).").
|
|
31
|
+
"""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def ensure_config_initialized(self, overwrite: bool = False) -> str:
|
|
36
|
+
"""
|
|
37
|
+
Ensures configuration files (config.yaml, .gitignore, init.context) are present
|
|
38
|
+
in the .teddy/ directory.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
overwrite: If True, always overwrite existing config files with defaults.
|
|
42
|
+
If False (default), only write missing files.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
A human-readable status string (e.g., "Configuration files overwritten (3 files).").
|
|
46
|
+
"""
|
|
47
|
+
pass
|
{teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/ports/outbound/environment_inspector.py
RENAMED
|
@@ -22,9 +22,18 @@ class IEnvironmentInspector(Protocol):
|
|
|
22
22
|
|
|
23
23
|
def get_git_status(self) -> Optional[str]:
|
|
24
24
|
"""
|
|
25
|
-
Gathers the current Git status of the working directory.
|
|
25
|
+
Gathers the current Git status of the working directory (short format).
|
|
26
26
|
|
|
27
27
|
Returns:
|
|
28
28
|
Optional[str]: The output of 'git status -s' or None if not a git repo.
|
|
29
29
|
"""
|
|
30
30
|
...
|
|
31
|
+
|
|
32
|
+
def get_full_git_status(self) -> Optional[str]:
|
|
33
|
+
"""
|
|
34
|
+
Gathers the full Git status of the working directory (including branch info).
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Optional[str]: The output of 'git status' or None if not a git repo.
|
|
38
|
+
"""
|
|
39
|
+
...
|
|
@@ -39,7 +39,7 @@ class ContextService(IGetContextUseCase):
|
|
|
39
39
|
self._llm_client = llm_client
|
|
40
40
|
self._web_scraper = web_scraper
|
|
41
41
|
|
|
42
|
-
def get_context(
|
|
42
|
+
def get_context( # noqa: PLR0913
|
|
43
43
|
self,
|
|
44
44
|
context_files: Optional[Dict[str, Sequence[str]]] = None,
|
|
45
45
|
include_tokens: bool = True,
|
|
@@ -53,7 +53,8 @@ class ContextService(IGetContextUseCase):
|
|
|
53
53
|
Gathers all project context information by orchestrating its dependencies.
|
|
54
54
|
"""
|
|
55
55
|
system_info = self._environment_inspector.get_environment_info()
|
|
56
|
-
|
|
56
|
+
short_git_status = self._environment_inspector.get_git_status()
|
|
57
|
+
full_git_status = self._environment_inspector.get_full_git_status()
|
|
57
58
|
repo_tree = self._repo_tree_generator.generate_tree()
|
|
58
59
|
|
|
59
60
|
scoped_paths, all_resolved_paths = self._resolve_scoped_paths(context_files)
|
|
@@ -79,7 +80,7 @@ class ContextService(IGetContextUseCase):
|
|
|
79
80
|
file_contents[url] = None
|
|
80
81
|
|
|
81
82
|
content = self._format_content(
|
|
82
|
-
repo_tree, scoped_paths, file_contents,
|
|
83
|
+
repo_tree, scoped_paths, file_contents, full_git_status
|
|
83
84
|
)
|
|
84
85
|
content_tokens = (
|
|
85
86
|
self._llm_client.get_text_token_count(content) if include_tokens else 0
|
|
@@ -89,9 +90,9 @@ class ContextService(IGetContextUseCase):
|
|
|
89
90
|
header=self._format_header(system_info, current_turn),
|
|
90
91
|
content=content,
|
|
91
92
|
scoped_paths=scoped_paths,
|
|
92
|
-
git_status=
|
|
93
|
+
git_status=full_git_status,
|
|
93
94
|
items=self._collect_items(
|
|
94
|
-
scoped_paths, file_contents,
|
|
95
|
+
scoped_paths, file_contents, short_git_status, include_tokens
|
|
95
96
|
),
|
|
96
97
|
agent_name=agent_name,
|
|
97
98
|
total_window=total_window,
|
|
@@ -303,10 +304,6 @@ class ContextService(IGetContextUseCase):
|
|
|
303
304
|
git_status: Optional[str] = None,
|
|
304
305
|
) -> str:
|
|
305
306
|
"""Formats the main content section of the context report."""
|
|
306
|
-
display_status = git_status
|
|
307
|
-
if git_status == "":
|
|
308
|
-
display_status = "nothing to commit, working tree clean"
|
|
309
|
-
|
|
310
307
|
# Gather all unique paths
|
|
311
308
|
all_paths: List[str] = []
|
|
312
309
|
for paths in scoped_paths.values():
|
|
@@ -320,7 +317,7 @@ class ContextService(IGetContextUseCase):
|
|
|
320
317
|
|
|
321
318
|
content_parts = [
|
|
322
319
|
"\n## Git Status",
|
|
323
|
-
|
|
320
|
+
git_status if isinstance(git_status, str) else "",
|
|
324
321
|
"\n## Project Structure",
|
|
325
322
|
f"```\n{repo_tree}\n```",
|
|
326
323
|
]
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from importlib import resources
|
|
4
|
+
|
|
5
|
+
import yaml
|
|
6
|
+
|
|
7
|
+
from teddy_executor.core.ports.inbound.init import IInitUseCase
|
|
8
|
+
from teddy_executor.core.ports.outbound.file_system_manager import IFileSystemManager
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class InitService(IInitUseCase):
|
|
12
|
+
"""
|
|
13
|
+
Service for initializing projects.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, file_system: IFileSystemManager, config_dir: str | None = None):
|
|
17
|
+
self._file_system = file_system
|
|
18
|
+
# Find the config directory relative to the package root if not provided
|
|
19
|
+
if config_dir:
|
|
20
|
+
self._config_dir = config_dir
|
|
21
|
+
else:
|
|
22
|
+
# Use importlib.resources to find the bundled config templates
|
|
23
|
+
resource_path = resources.files("teddy_executor.resources.config")
|
|
24
|
+
# Ensure we resolve to an absolute string for compatibility with the FileSystem port
|
|
25
|
+
self._config_dir = os.path.abspath(str(resource_path))
|
|
26
|
+
|
|
27
|
+
def _get_default_content(self, filename: str) -> str | None:
|
|
28
|
+
"""Loads default content from the config directory using the file system port."""
|
|
29
|
+
try:
|
|
30
|
+
target_path = os.path.join(self._config_dir, filename)
|
|
31
|
+
if self._file_system.path_exists(target_path):
|
|
32
|
+
return self._file_system.read_file(target_path)
|
|
33
|
+
except (OSError, yaml.YAMLError, ImportError, AttributeError):
|
|
34
|
+
logging.getLogger(__name__).debug(
|
|
35
|
+
"Failed to load default content for %s", filename
|
|
36
|
+
)
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
def _init_config_dir(self, overwrite: bool = False) -> str:
|
|
40
|
+
"""Copies bundled config files (config.yaml, .gitignore, init.context) to .teddy/.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
overwrite: If True, always overwrite existing files. If False, only write missing ones.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
A status string: "unchanged", "updated (N files)", or "overwritten (N files)".
|
|
47
|
+
"""
|
|
48
|
+
config_files = ["config.yaml", ".gitignore", "init.context"]
|
|
49
|
+
count = 0
|
|
50
|
+
for fname in config_files:
|
|
51
|
+
target_path = f".teddy/{fname}"
|
|
52
|
+
if overwrite or not self._file_system.path_exists(target_path):
|
|
53
|
+
content = self._get_default_content(fname)
|
|
54
|
+
if content is not None:
|
|
55
|
+
self._file_system.write_file(target_path, content)
|
|
56
|
+
count += 1
|
|
57
|
+
if count == 0:
|
|
58
|
+
return "unchanged"
|
|
59
|
+
if overwrite:
|
|
60
|
+
return f"overwritten ({count} files)"
|
|
61
|
+
return f"updated ({count} files)"
|
|
62
|
+
|
|
63
|
+
def _init_prompts(self, overwrite: bool = False) -> str:
|
|
64
|
+
"""Copies bundled prompt XMLs to .teddy/prompts/.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
overwrite: If True, always overwrite existing files. If False, only write missing ones.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
A status string: "unchanged", "updated (N files)", or "overwritten (N files)".
|
|
71
|
+
"""
|
|
72
|
+
prompts_dir = ".teddy/prompts"
|
|
73
|
+
if not self._file_system.path_exists(prompts_dir):
|
|
74
|
+
self._file_system.create_directory(prompts_dir)
|
|
75
|
+
|
|
76
|
+
prompt_files = [
|
|
77
|
+
"architect.xml",
|
|
78
|
+
"assistant.xml",
|
|
79
|
+
"debugger.xml",
|
|
80
|
+
"developer.xml",
|
|
81
|
+
"pathfinder.xml",
|
|
82
|
+
"prototyper.xml",
|
|
83
|
+
]
|
|
84
|
+
count = 0
|
|
85
|
+
for fname in prompt_files:
|
|
86
|
+
target_path = f"{prompts_dir}/{fname}"
|
|
87
|
+
if overwrite or not self._file_system.path_exists(target_path):
|
|
88
|
+
content = self._get_default_content(f"prompts/{fname}")
|
|
89
|
+
if content is not None:
|
|
90
|
+
self._file_system.write_file(target_path, content)
|
|
91
|
+
count += 1
|
|
92
|
+
if count == 0:
|
|
93
|
+
return "unchanged"
|
|
94
|
+
if overwrite:
|
|
95
|
+
return f"overwritten ({count} files)"
|
|
96
|
+
return f"updated ({count} files)"
|
|
97
|
+
|
|
98
|
+
def ensure_initialized(self) -> str:
|
|
99
|
+
"""
|
|
100
|
+
Ensures the .teddy directory and default files are present.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
A human-readable summary string (e.g., "Config: unchanged. Prompts: updated (3 files).").
|
|
104
|
+
"""
|
|
105
|
+
if not self._file_system.path_exists(".teddy"):
|
|
106
|
+
self._file_system.create_directory(".teddy")
|
|
107
|
+
|
|
108
|
+
config_status = self._init_config_dir(overwrite=False)
|
|
109
|
+
prompts_status = self._init_prompts(overwrite=False)
|
|
110
|
+
return f"Config: {config_status}. Prompts: {prompts_status}."
|
|
111
|
+
|
|
112
|
+
def ensure_prompts_initialized(self, overwrite: bool = True) -> str:
|
|
113
|
+
"""
|
|
114
|
+
Ensures prompt XML files are present in the .teddy/prompts/ directory.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
overwrite: If True, always overwrite existing prompt files with defaults.
|
|
118
|
+
If False (default), only write missing files.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
A human-readable status string (e.g., "Prompts overwritten (6 files).").
|
|
122
|
+
"""
|
|
123
|
+
status = self._init_prompts(overwrite=overwrite)
|
|
124
|
+
return f"Prompts {status}."
|
|
125
|
+
|
|
126
|
+
def ensure_config_initialized(self, overwrite: bool = True) -> str:
|
|
127
|
+
"""
|
|
128
|
+
Ensures configuration files (config.yaml, .gitignore, init.context) are present in the .teddy/ directory.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
overwrite: If True, always overwrite existing config files with defaults.
|
|
132
|
+
If False (default), only write missing files.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
A human-readable status string (e.g., "Configuration files overwritten (3 files).").
|
|
136
|
+
"""
|
|
137
|
+
status = self._init_config_dir(overwrite=overwrite)
|
|
138
|
+
return f"Configuration files {status}."
|
{teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/markdown_plan_parser.py
RENAMED
|
@@ -286,22 +286,24 @@ class MarkdownPlanParser(IPlanParser):
|
|
|
286
286
|
|
|
287
287
|
stream.next() # Consume action heading
|
|
288
288
|
action_type_str = get_child_text(action_heading).strip().replace("`", "")
|
|
289
|
+
# Normalize: strip non-alphabetic characters so "READ**" matches "READ"
|
|
290
|
+
cleaned_action_type = re.sub(r"[^A-Za-z]", "", action_type_str)
|
|
289
291
|
|
|
290
292
|
# Guard: MESSAGE under ## Action Plan must produce a clear mutual exclusivity error
|
|
291
|
-
if
|
|
293
|
+
if cleaned_action_type == "MESSAGE":
|
|
292
294
|
raise InvalidPlanError(
|
|
293
295
|
"MESSAGE action is not allowed under '## Action Plan'. "
|
|
294
296
|
"Use '## Message' section instead. Mutual exclusivity is required.",
|
|
295
297
|
offending_nodes=[action_heading],
|
|
296
298
|
)
|
|
297
299
|
|
|
298
|
-
if
|
|
300
|
+
if cleaned_action_type not in self._dispatch_map:
|
|
299
301
|
raise InvalidPlanError(
|
|
300
302
|
f"Unknown action type: {action_type_str}",
|
|
301
303
|
offending_nodes=[action_heading],
|
|
302
304
|
)
|
|
303
305
|
|
|
304
|
-
parse_method = self._dispatch_map[
|
|
306
|
+
parse_method = self._dispatch_map[cleaned_action_type]
|
|
305
307
|
actions.append(parse_method(stream, node=action_heading))
|
|
306
308
|
|
|
307
309
|
return actions
|
{teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/parser_infrastructure.py
RENAMED
|
@@ -142,7 +142,9 @@ def get_action_heading(node: Any, valid_actions: set[str]) -> "Optional[Heading]
|
|
|
142
142
|
if isinstance(node, Heading) and node.level == H3_LEVEL:
|
|
143
143
|
text = get_child_text(node).strip()
|
|
144
144
|
potential_type = text.split(":")[0].strip().replace("`", "")
|
|
145
|
-
|
|
145
|
+
# Normalize: strip non-alphabetic characters so "READ**" matches "READ"
|
|
146
|
+
cleaned_type = re.sub(r"[^A-Za-z]", "", potential_type)
|
|
147
|
+
if cleaned_type in valid_actions:
|
|
146
148
|
return node
|
|
147
149
|
# Allow unknown actions if they are formatted like `ACTION` to fail later
|
|
148
150
|
children = list(node.children) if node.children else []
|
{teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/core/services/validation_rules/helpers.py
RENAMED
|
@@ -112,7 +112,7 @@ def validate_path_is_safe(path_str: str, action_type: str):
|
|
|
112
112
|
Ensures a file path is safe by checking for absolute paths and
|
|
113
113
|
directory traversal attempts.
|
|
114
114
|
"""
|
|
115
|
-
if os.path.isabs(path_str):
|
|
115
|
+
if path_str.startswith("/") or os.path.isabs(path_str):
|
|
116
116
|
raise PlanValidationError(
|
|
117
117
|
f"Action `{action_type}` contains an absolute path, which is not allowed: {path_str}"
|
|
118
118
|
)
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
# TeDDy Configuration
|
|
2
2
|
|
|
3
|
-
# UI Settings
|
|
4
|
-
# Supported modes: "tui" (Interactive Terminal UI), "console" (Sequential CLI prompts)
|
|
5
|
-
ui_mode: "tui"
|
|
6
|
-
|
|
7
3
|
# The preferred external editor for reviewing and modifying plans/messages.
|
|
8
4
|
# Supports arbitrary command strings (e.g., "code --wait", "nvim -R", "zed").
|
|
9
5
|
# Fallback chain: Config -> VISUAL/EDITOR env vars -> code -> nano.
|
|
10
6
|
editor: "code"
|
|
11
7
|
|
|
12
|
-
|
|
13
8
|
# Execution Settings
|
|
14
9
|
execution:
|
|
15
10
|
default_timeout_seconds: 60
|
{teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/architect.xml
RENAMED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
<step n="6" name="Architecture Maintenance">Update `docs/architecture/ARCHITECTURE.md`'s `Component & Boundary Map` and `Key Architectural Decisions` if needed to align.</step>
|
|
34
34
|
<step n="7" name="Delta Analysis">Use `EXECUTE git grep` and `READ` on all targeted components, contracts, interfaces, and DTOs referenced in the design. Verify implementation status of every piece the design calls for. Catalog the delta: what already exists (skip — do NOT include as a deliverable), what is partially implemented (note remaining work), and what is entirely missing (add as pending). Only truly unimplemented or incomplete work SHALL appear in the slice deliverables. Do NOT create entries for work that demonstrably exists.</step>
|
|
35
35
|
<step n="8" name="Create Slice">`CREATE` exactly ONE Vertical Slice following these rules:
|
|
36
|
-
1. Type & Status: Must be single-purpose (Do NOT mix Feature/Tweak/Refactor). Bugfixes are only created by the Debugger. If Type is Feature, initial Status MUST be `
|
|
36
|
+
1. Type & Status: Must be single-purpose (Do NOT mix Feature/Tweak/Refactor). Bugfixes are only created by the Debugger. If Type is Feature, initial Status MUST be `Pending Prototype`. For Tweak and Refactor, initial Status SHOULD be `Planned`.
|
|
37
37
|
2. Content: MUST include linked Component Docs. If Type is Feature, it MUST include Gherkin scenarios and a final `Wiring` behavioral gate. For Tweak and Refactor, these are omitted or optional.
|
|
38
38
|
3. Debt: Inject `Refactor`/`Cleanup` deliverables for audit findings, and `Harness` deliverables to patch preventable static analysis gaps.</step>
|
|
39
39
|
<step n="9" name="Impact Audit & Consistency Check">Use `EXECUTE git grep` on target components. If a component (Port, Service signature, or DTO) has >1 consumer (excluding its own definition), categorize it as a Shared Seam. You MUST decompose the design into smaller, atomic deliverables if >1 consumer, layer, or logical change is affected. For Shared Seams, you MUST partition the plan into a non-breaking sequence (Contract/Expansion -> Migration -> Cleanup/Contraction). Ensure the design follows the Deliverable Dependency Sequence. Resolve hits for deleted/renamed components in documentation and ensure all Contract/Seam changes have matching Harness deliverables.</step>
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
<description>A cohesive feature that delivers a set of correlated and testable behaviors.</description>
|
|
131
131
|
<section n="1" name="Metadata">
|
|
132
132
|
<item name="Heading"># Slice: {{feature_name}}</item>
|
|
133
|
-
<item name="Status">- **Status:** [Draft |
|
|
133
|
+
<item name="Status">- **Status:** [Draft | Pending Prototype | Planned | In Progress | Completed]</item>
|
|
134
134
|
<item name="Type">- **Type:** [Feature | Tweak | Refactor | Bugfix]</item>
|
|
135
135
|
<item name="Milestone">- **Milestone:** [link]</item>
|
|
136
136
|
<item name="Specs">- **Specs:** [links]</item>
|
|
@@ -258,9 +258,6 @@ WIP & REMINDERS:
|
|
|
258
258
|
2. Commit Message: Use Conventional Commits '<type>(<scope>): <description>' wrapped in single quotes. Use imperative mood. Append ! for breaking changes.
|
|
259
259
|
3. Execution: You MUST test, stage, commit locally, pull safely with rebase, and push by executing exactly this codeblock:
|
|
260
260
|
```shell
|
|
261
|
-
# 0. Ensure commit hooks are installed
|
|
262
|
-
pre-commit install -t pre-commit -t post-commit
|
|
263
|
-
|
|
264
261
|
# 1. Stage changes and run pre-commit
|
|
265
262
|
git add .
|
|
266
263
|
pre-commit run || true
|
{teddy_cli-0.1.5 → teddy_cli-0.1.7}/src/teddy_executor/resources/config/prompts/assistant.xml
RENAMED
|
@@ -90,9 +90,6 @@ WIP & REMINDERS:
|
|
|
90
90
|
2. Commit Message: Use Conventional Commits '<type>(<scope>): <description>' wrapped in single quotes. Use imperative mood. Append ! for breaking changes.
|
|
91
91
|
3. Execution: You MUST test, stage, commit locally, pull safely with rebase, and push by executing exactly this codeblock:
|
|
92
92
|
```shell
|
|
93
|
-
# 0. Ensure commit hooks are installed
|
|
94
|
-
pre-commit install -t pre-commit -t post-commit
|
|
95
|
-
|
|
96
93
|
# 1. Stage changes and run pre-commit
|
|
97
94
|
git add .
|
|
98
95
|
pre-commit run || true
|