pdd-cli 0.0.45__py3-none-any.whl → 0.0.118__py3-none-any.whl
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.
- pdd/__init__.py +40 -8
- pdd/agentic_bug.py +323 -0
- pdd/agentic_bug_orchestrator.py +497 -0
- pdd/agentic_change.py +231 -0
- pdd/agentic_change_orchestrator.py +526 -0
- pdd/agentic_common.py +598 -0
- pdd/agentic_crash.py +534 -0
- pdd/agentic_e2e_fix.py +319 -0
- pdd/agentic_e2e_fix_orchestrator.py +426 -0
- pdd/agentic_fix.py +1294 -0
- pdd/agentic_langtest.py +162 -0
- pdd/agentic_update.py +387 -0
- pdd/agentic_verify.py +183 -0
- pdd/architecture_sync.py +565 -0
- pdd/auth_service.py +210 -0
- pdd/auto_deps_main.py +71 -51
- pdd/auto_include.py +245 -5
- pdd/auto_update.py +125 -47
- pdd/bug_main.py +196 -23
- pdd/bug_to_unit_test.py +2 -0
- pdd/change_main.py +11 -4
- pdd/cli.py +22 -1181
- pdd/cmd_test_main.py +350 -150
- pdd/code_generator.py +60 -18
- pdd/code_generator_main.py +790 -57
- pdd/commands/__init__.py +48 -0
- pdd/commands/analysis.py +306 -0
- pdd/commands/auth.py +309 -0
- pdd/commands/connect.py +290 -0
- pdd/commands/fix.py +163 -0
- pdd/commands/generate.py +257 -0
- pdd/commands/maintenance.py +175 -0
- pdd/commands/misc.py +87 -0
- pdd/commands/modify.py +256 -0
- pdd/commands/report.py +144 -0
- pdd/commands/sessions.py +284 -0
- pdd/commands/templates.py +215 -0
- pdd/commands/utility.py +110 -0
- pdd/config_resolution.py +58 -0
- pdd/conflicts_main.py +8 -3
- pdd/construct_paths.py +589 -111
- pdd/context_generator.py +10 -2
- pdd/context_generator_main.py +175 -76
- pdd/continue_generation.py +53 -10
- pdd/core/__init__.py +33 -0
- pdd/core/cli.py +527 -0
- pdd/core/cloud.py +237 -0
- pdd/core/dump.py +554 -0
- pdd/core/errors.py +67 -0
- pdd/core/remote_session.py +61 -0
- pdd/core/utils.py +90 -0
- pdd/crash_main.py +262 -33
- pdd/data/language_format.csv +71 -63
- pdd/data/llm_model.csv +20 -18
- pdd/detect_change_main.py +5 -4
- pdd/docs/prompting_guide.md +864 -0
- pdd/docs/whitepaper_with_benchmarks/data_and_functions/benchmark_analysis.py +495 -0
- pdd/docs/whitepaper_with_benchmarks/data_and_functions/creation_compare.py +528 -0
- pdd/fix_code_loop.py +523 -95
- pdd/fix_code_module_errors.py +6 -2
- pdd/fix_error_loop.py +491 -92
- pdd/fix_errors_from_unit_tests.py +4 -3
- pdd/fix_main.py +278 -21
- pdd/fix_verification_errors.py +12 -100
- pdd/fix_verification_errors_loop.py +529 -286
- pdd/fix_verification_main.py +294 -89
- pdd/frontend/dist/assets/index-B5DZHykP.css +1 -0
- pdd/frontend/dist/assets/index-DQ3wkeQ2.js +449 -0
- pdd/frontend/dist/index.html +376 -0
- pdd/frontend/dist/logo.svg +33 -0
- pdd/generate_output_paths.py +139 -15
- pdd/generate_test.py +218 -146
- pdd/get_comment.py +19 -44
- pdd/get_extension.py +8 -9
- pdd/get_jwt_token.py +318 -22
- pdd/get_language.py +8 -7
- pdd/get_run_command.py +75 -0
- pdd/get_test_command.py +68 -0
- pdd/git_update.py +70 -19
- pdd/incremental_code_generator.py +2 -2
- pdd/insert_includes.py +13 -4
- pdd/llm_invoke.py +1711 -181
- pdd/load_prompt_template.py +19 -12
- pdd/path_resolution.py +140 -0
- pdd/pdd_completion.fish +25 -2
- pdd/pdd_completion.sh +30 -4
- pdd/pdd_completion.zsh +79 -4
- pdd/postprocess.py +14 -4
- pdd/preprocess.py +293 -24
- pdd/preprocess_main.py +41 -6
- pdd/prompts/agentic_bug_step10_pr_LLM.prompt +182 -0
- pdd/prompts/agentic_bug_step1_duplicate_LLM.prompt +73 -0
- pdd/prompts/agentic_bug_step2_docs_LLM.prompt +129 -0
- pdd/prompts/agentic_bug_step3_triage_LLM.prompt +95 -0
- pdd/prompts/agentic_bug_step4_reproduce_LLM.prompt +97 -0
- pdd/prompts/agentic_bug_step5_root_cause_LLM.prompt +123 -0
- pdd/prompts/agentic_bug_step6_test_plan_LLM.prompt +107 -0
- pdd/prompts/agentic_bug_step7_generate_LLM.prompt +172 -0
- pdd/prompts/agentic_bug_step8_verify_LLM.prompt +119 -0
- pdd/prompts/agentic_bug_step9_e2e_test_LLM.prompt +289 -0
- pdd/prompts/agentic_change_step10_identify_issues_LLM.prompt +1006 -0
- pdd/prompts/agentic_change_step11_fix_issues_LLM.prompt +984 -0
- pdd/prompts/agentic_change_step12_create_pr_LLM.prompt +131 -0
- pdd/prompts/agentic_change_step1_duplicate_LLM.prompt +73 -0
- pdd/prompts/agentic_change_step2_docs_LLM.prompt +101 -0
- pdd/prompts/agentic_change_step3_research_LLM.prompt +126 -0
- pdd/prompts/agentic_change_step4_clarify_LLM.prompt +164 -0
- pdd/prompts/agentic_change_step5_docs_change_LLM.prompt +981 -0
- pdd/prompts/agentic_change_step6_devunits_LLM.prompt +1005 -0
- pdd/prompts/agentic_change_step7_architecture_LLM.prompt +1044 -0
- pdd/prompts/agentic_change_step8_analyze_LLM.prompt +1027 -0
- pdd/prompts/agentic_change_step9_implement_LLM.prompt +1077 -0
- pdd/prompts/agentic_crash_explore_LLM.prompt +49 -0
- pdd/prompts/agentic_e2e_fix_step1_unit_tests_LLM.prompt +90 -0
- pdd/prompts/agentic_e2e_fix_step2_e2e_tests_LLM.prompt +91 -0
- pdd/prompts/agentic_e2e_fix_step3_root_cause_LLM.prompt +89 -0
- pdd/prompts/agentic_e2e_fix_step4_fix_e2e_tests_LLM.prompt +96 -0
- pdd/prompts/agentic_e2e_fix_step5_identify_devunits_LLM.prompt +91 -0
- pdd/prompts/agentic_e2e_fix_step6_create_unit_tests_LLM.prompt +106 -0
- pdd/prompts/agentic_e2e_fix_step7_verify_tests_LLM.prompt +116 -0
- pdd/prompts/agentic_e2e_fix_step8_run_pdd_fix_LLM.prompt +120 -0
- pdd/prompts/agentic_e2e_fix_step9_verify_all_LLM.prompt +146 -0
- pdd/prompts/agentic_fix_explore_LLM.prompt +45 -0
- pdd/prompts/agentic_fix_harvest_only_LLM.prompt +48 -0
- pdd/prompts/agentic_fix_primary_LLM.prompt +85 -0
- pdd/prompts/agentic_update_LLM.prompt +925 -0
- pdd/prompts/agentic_verify_explore_LLM.prompt +45 -0
- pdd/prompts/auto_include_LLM.prompt +122 -905
- pdd/prompts/change_LLM.prompt +3093 -1
- pdd/prompts/detect_change_LLM.prompt +686 -27
- pdd/prompts/example_generator_LLM.prompt +22 -1
- pdd/prompts/extract_code_LLM.prompt +5 -1
- pdd/prompts/extract_program_code_fix_LLM.prompt +7 -1
- pdd/prompts/extract_prompt_update_LLM.prompt +7 -8
- pdd/prompts/extract_promptline_LLM.prompt +17 -11
- pdd/prompts/find_verification_errors_LLM.prompt +6 -0
- pdd/prompts/fix_code_module_errors_LLM.prompt +12 -2
- pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +9 -0
- pdd/prompts/fix_verification_errors_LLM.prompt +22 -0
- pdd/prompts/generate_test_LLM.prompt +41 -7
- pdd/prompts/generate_test_from_example_LLM.prompt +115 -0
- pdd/prompts/increase_tests_LLM.prompt +1 -5
- pdd/prompts/insert_includes_LLM.prompt +316 -186
- pdd/prompts/prompt_code_diff_LLM.prompt +119 -0
- pdd/prompts/prompt_diff_LLM.prompt +82 -0
- pdd/prompts/trace_LLM.prompt +25 -22
- pdd/prompts/unfinished_prompt_LLM.prompt +85 -1
- pdd/prompts/update_prompt_LLM.prompt +22 -1
- pdd/pytest_output.py +127 -12
- pdd/remote_session.py +876 -0
- pdd/render_mermaid.py +236 -0
- pdd/server/__init__.py +52 -0
- pdd/server/app.py +335 -0
- pdd/server/click_executor.py +587 -0
- pdd/server/executor.py +338 -0
- pdd/server/jobs.py +661 -0
- pdd/server/models.py +241 -0
- pdd/server/routes/__init__.py +31 -0
- pdd/server/routes/architecture.py +451 -0
- pdd/server/routes/auth.py +364 -0
- pdd/server/routes/commands.py +929 -0
- pdd/server/routes/config.py +42 -0
- pdd/server/routes/files.py +603 -0
- pdd/server/routes/prompts.py +1322 -0
- pdd/server/routes/websocket.py +473 -0
- pdd/server/security.py +243 -0
- pdd/server/terminal_spawner.py +209 -0
- pdd/server/token_counter.py +222 -0
- pdd/setup_tool.py +648 -0
- pdd/simple_math.py +2 -0
- pdd/split_main.py +3 -2
- pdd/summarize_directory.py +237 -195
- pdd/sync_animation.py +8 -4
- pdd/sync_determine_operation.py +839 -112
- pdd/sync_main.py +351 -57
- pdd/sync_orchestration.py +1400 -756
- pdd/sync_tui.py +848 -0
- pdd/template_expander.py +161 -0
- pdd/template_registry.py +264 -0
- pdd/templates/architecture/architecture_json.prompt +237 -0
- pdd/templates/generic/generate_prompt.prompt +174 -0
- pdd/trace.py +168 -12
- pdd/trace_main.py +4 -3
- pdd/track_cost.py +140 -63
- pdd/unfinished_prompt.py +51 -4
- pdd/update_main.py +567 -67
- pdd/update_model_costs.py +2 -2
- pdd/update_prompt.py +19 -4
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/METADATA +29 -11
- pdd_cli-0.0.118.dist-info/RECORD +227 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/licenses/LICENSE +1 -1
- pdd_cli-0.0.45.dist-info/RECORD +0 -116
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/WHEEL +0 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/top_level.txt +0 -0
pdd/server/executor.py
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import sys
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any, Callable, Dict, Optional
|
|
7
|
+
from unittest.mock import MagicMock
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
# Attempt to import global constants, falling back to safe defaults if package structure varies
|
|
13
|
+
try:
|
|
14
|
+
from .. import DEFAULT_STRENGTH, DEFAULT_TIME
|
|
15
|
+
except ImportError:
|
|
16
|
+
DEFAULT_STRENGTH = 0.5
|
|
17
|
+
DEFAULT_TIME = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class CapturedOutput:
|
|
22
|
+
"""
|
|
23
|
+
Container for captured command output and execution results.
|
|
24
|
+
"""
|
|
25
|
+
stdout: str
|
|
26
|
+
stderr: str
|
|
27
|
+
exit_code: int
|
|
28
|
+
exception: Optional[Exception] = None
|
|
29
|
+
result: Optional[Any] = None
|
|
30
|
+
cost: float = 0.0
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class StreamingWriter:
|
|
34
|
+
"""
|
|
35
|
+
Writer that both buffers output to a StringIO and calls a callback for real-time streaming.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
buffer: io.StringIO,
|
|
41
|
+
callback: Optional[Callable[[str, str], None]],
|
|
42
|
+
stream_type: str,
|
|
43
|
+
):
|
|
44
|
+
self._buffer = buffer
|
|
45
|
+
self._callback = callback
|
|
46
|
+
self._stream_type = stream_type
|
|
47
|
+
|
|
48
|
+
def write(self, text: str) -> int:
|
|
49
|
+
"""Write text to buffer and trigger callback."""
|
|
50
|
+
self._buffer.write(text)
|
|
51
|
+
if self._callback and text:
|
|
52
|
+
self._callback(self._stream_type, text)
|
|
53
|
+
return len(text)
|
|
54
|
+
|
|
55
|
+
def flush(self) -> None:
|
|
56
|
+
"""Flush the underlying buffer."""
|
|
57
|
+
self._buffer.flush()
|
|
58
|
+
|
|
59
|
+
def isatty(self) -> bool:
|
|
60
|
+
"""Return False to indicate this is not a terminal."""
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class OutputCapture:
|
|
65
|
+
"""
|
|
66
|
+
Context manager that captures stdout and stderr during command execution.
|
|
67
|
+
Supports real-time streaming via a callback.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __init__(self, callback: Optional[Callable[[str, str], None]] = None):
|
|
71
|
+
"""
|
|
72
|
+
Initialize output capture.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
callback: Optional callback(stream_type, text) for real-time streaming.
|
|
76
|
+
stream_type will be "stdout" or "stderr".
|
|
77
|
+
"""
|
|
78
|
+
self._callback = callback
|
|
79
|
+
self._stdout_buffer = io.StringIO()
|
|
80
|
+
self._stderr_buffer = io.StringIO()
|
|
81
|
+
self._original_stdout = sys.stdout
|
|
82
|
+
self._original_stderr = sys.stderr
|
|
83
|
+
|
|
84
|
+
def __enter__(self) -> "OutputCapture":
|
|
85
|
+
# Redirect streams
|
|
86
|
+
sys.stdout = StreamingWriter(self._stdout_buffer, self._callback, "stdout") # type: ignore
|
|
87
|
+
sys.stderr = StreamingWriter(self._stderr_buffer, self._callback, "stderr") # type: ignore
|
|
88
|
+
return self
|
|
89
|
+
|
|
90
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> bool:
|
|
91
|
+
# Restore streams
|
|
92
|
+
sys.stdout = self._original_stdout
|
|
93
|
+
sys.stderr = self._original_stderr
|
|
94
|
+
return False # Propagate exceptions
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def stdout(self) -> str:
|
|
98
|
+
"""Get captured stdout content."""
|
|
99
|
+
return self._stdout_buffer.getvalue()
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def stderr(self) -> str:
|
|
103
|
+
"""Get captured stderr content."""
|
|
104
|
+
return self._stderr_buffer.getvalue()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def create_isolated_context(
|
|
108
|
+
command: click.Command,
|
|
109
|
+
obj: Optional[Dict[str, Any]] = None,
|
|
110
|
+
color: bool = False,
|
|
111
|
+
) -> click.Context:
|
|
112
|
+
"""
|
|
113
|
+
Create an isolated Click context for programmatic command execution.
|
|
114
|
+
|
|
115
|
+
This sets up the context object (ctx.obj) with PDD global defaults and
|
|
116
|
+
mocks parameter sources to ensure smooth execution outside the CLI loop.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
command: The Click command to create context for.
|
|
120
|
+
obj: Optional dictionary to populate ctx.obj (merged with defaults).
|
|
121
|
+
color: Whether to enable ANSI colors in output.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Configured Click context.
|
|
125
|
+
"""
|
|
126
|
+
ctx = click.Context(command, color=color)
|
|
127
|
+
|
|
128
|
+
# Default PDD global options
|
|
129
|
+
default_obj = {
|
|
130
|
+
"strength": DEFAULT_STRENGTH,
|
|
131
|
+
"temperature": 0.0,
|
|
132
|
+
"time": DEFAULT_TIME,
|
|
133
|
+
"verbose": False,
|
|
134
|
+
"force": False,
|
|
135
|
+
"quiet": False,
|
|
136
|
+
"output_cost": None,
|
|
137
|
+
"review_examples": False,
|
|
138
|
+
"local": False,
|
|
139
|
+
"context": None,
|
|
140
|
+
"confirm_callback": None,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Merge provided obj with defaults
|
|
144
|
+
ctx.obj = {**default_obj, **(obj or {})}
|
|
145
|
+
|
|
146
|
+
# Mock parameter source checking to return DEFAULT.
|
|
147
|
+
# This prevents Click from erroring when checking how parameters were supplied.
|
|
148
|
+
mock_source = MagicMock()
|
|
149
|
+
mock_source.name = "DEFAULT"
|
|
150
|
+
ctx.get_parameter_source = MagicMock(return_value=mock_source)
|
|
151
|
+
|
|
152
|
+
return ctx
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class ClickCommandExecutor:
|
|
156
|
+
"""
|
|
157
|
+
Executes Click commands programmatically with output capture and error handling.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
def __init__(
|
|
161
|
+
self,
|
|
162
|
+
base_context_obj: Optional[Dict[str, Any]] = None,
|
|
163
|
+
output_callback: Optional[Callable[[str, str], None]] = None,
|
|
164
|
+
):
|
|
165
|
+
"""
|
|
166
|
+
Initialize the executor.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
base_context_obj: Base context object to be merged into every execution.
|
|
170
|
+
output_callback: Callback for real-time output streaming.
|
|
171
|
+
"""
|
|
172
|
+
self._base_context_obj = base_context_obj or {}
|
|
173
|
+
self._output_callback = output_callback
|
|
174
|
+
|
|
175
|
+
def execute(
|
|
176
|
+
self,
|
|
177
|
+
command: click.Command,
|
|
178
|
+
params: Optional[Dict[str, Any]] = None,
|
|
179
|
+
context_obj: Optional[Dict[str, Any]] = None,
|
|
180
|
+
) -> CapturedOutput:
|
|
181
|
+
"""
|
|
182
|
+
Execute a Click command with the given parameters.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
command: Click command to execute.
|
|
186
|
+
params: Parameters to pass to the command (arguments and options).
|
|
187
|
+
context_obj: Optional context object overrides for this specific execution.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
CapturedOutput object containing results and logs.
|
|
191
|
+
"""
|
|
192
|
+
# Merge context objects
|
|
193
|
+
obj = {**self._base_context_obj, **(context_obj or {})}
|
|
194
|
+
|
|
195
|
+
# Create isolated context
|
|
196
|
+
ctx = create_isolated_context(command, obj)
|
|
197
|
+
|
|
198
|
+
# Capture output
|
|
199
|
+
capture = OutputCapture(callback=self._output_callback)
|
|
200
|
+
|
|
201
|
+
result_val = None
|
|
202
|
+
cost = 0.0
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
with capture:
|
|
206
|
+
with ctx:
|
|
207
|
+
# Invoke the command with parameters
|
|
208
|
+
# Note: standalone_mode=False prevents Click from handling exceptions (sys.exit)
|
|
209
|
+
# but ctx.invoke doesn't use standalone_mode. It just calls the callback.
|
|
210
|
+
result_val = ctx.invoke(command, **(params or {}))
|
|
211
|
+
|
|
212
|
+
# Attempt to extract cost from result if available
|
|
213
|
+
# PDD commands often return a tuple where the second element is cost,
|
|
214
|
+
# or a dict with a 'cost' key.
|
|
215
|
+
if isinstance(result_val, tuple) and len(result_val) >= 2:
|
|
216
|
+
# Common pattern: (result_str, cost, model_name)
|
|
217
|
+
if isinstance(result_val[1], (int, float)):
|
|
218
|
+
cost = float(result_val[1])
|
|
219
|
+
elif isinstance(result_val, dict) and "cost" in result_val:
|
|
220
|
+
cost = float(result_val["cost"])
|
|
221
|
+
elif hasattr(result_val, "cost"):
|
|
222
|
+
cost = float(result_val.cost)
|
|
223
|
+
|
|
224
|
+
return CapturedOutput(
|
|
225
|
+
stdout=capture.stdout,
|
|
226
|
+
stderr=capture.stderr,
|
|
227
|
+
exit_code=0,
|
|
228
|
+
result=result_val,
|
|
229
|
+
cost=cost,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
except click.Abort:
|
|
233
|
+
return CapturedOutput(
|
|
234
|
+
stdout=capture.stdout,
|
|
235
|
+
stderr=capture.stderr,
|
|
236
|
+
exit_code=1,
|
|
237
|
+
exception=click.Abort(),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
except click.ClickException as e:
|
|
241
|
+
return CapturedOutput(
|
|
242
|
+
stdout=capture.stdout,
|
|
243
|
+
stderr=capture.stderr + f"\nError: {e.format_message()}",
|
|
244
|
+
exit_code=e.exit_code,
|
|
245
|
+
exception=e,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
except Exception as e:
|
|
249
|
+
return CapturedOutput(
|
|
250
|
+
stdout=capture.stdout,
|
|
251
|
+
stderr=capture.stderr + f"\nException: {str(e)}",
|
|
252
|
+
exit_code=1,
|
|
253
|
+
exception=e,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def get_pdd_command(command_name: str) -> Optional[click.Command]:
|
|
258
|
+
"""
|
|
259
|
+
Get a PDD Click command object by name.
|
|
260
|
+
Uses lazy imports to avoid circular dependencies.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
command_name: Name of the command (e.g., "sync", "generate").
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
The Click command object or None if not found.
|
|
267
|
+
"""
|
|
268
|
+
# Lazy imports to avoid circular dependencies with the main CLI module
|
|
269
|
+
try:
|
|
270
|
+
from ..commands.sync import sync
|
|
271
|
+
from ..commands.update import update
|
|
272
|
+
from ..commands.bug import bug
|
|
273
|
+
from ..commands.generate import generate
|
|
274
|
+
from ..commands.test import test
|
|
275
|
+
from ..commands.fix import fix
|
|
276
|
+
from ..commands.example import example
|
|
277
|
+
from ..commands.preprocess import preprocess
|
|
278
|
+
from ..commands.split import split
|
|
279
|
+
from ..commands.change import change
|
|
280
|
+
from ..commands.detect import detect
|
|
281
|
+
from ..commands.conflicts import conflicts
|
|
282
|
+
from ..commands.crash import crash
|
|
283
|
+
except ImportError:
|
|
284
|
+
# Fallback for testing or incomplete environments
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
commands_map = {
|
|
288
|
+
"sync": sync,
|
|
289
|
+
"update": update,
|
|
290
|
+
"bug": bug,
|
|
291
|
+
"generate": generate,
|
|
292
|
+
"test": test,
|
|
293
|
+
"fix": fix,
|
|
294
|
+
"example": example,
|
|
295
|
+
"preprocess": preprocess,
|
|
296
|
+
"split": split,
|
|
297
|
+
"change": change,
|
|
298
|
+
"detect": detect,
|
|
299
|
+
"conflicts": conflicts,
|
|
300
|
+
"crash": crash,
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return commands_map.get(command_name)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def execute_pdd_command(
|
|
307
|
+
command_name: str,
|
|
308
|
+
args: Optional[Dict[str, Any]] = None,
|
|
309
|
+
options: Optional[Dict[str, Any]] = None,
|
|
310
|
+
callback: Optional[Callable[[str, str], None]] = None,
|
|
311
|
+
) -> CapturedOutput:
|
|
312
|
+
"""
|
|
313
|
+
High-level helper to execute a PDD command by name.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
command_name: The name of the command to run (e.g., 'generate').
|
|
317
|
+
args: Dictionary of arguments/options to pass to the command.
|
|
318
|
+
options: Dictionary of global options (ctx.obj overrides).
|
|
319
|
+
callback: Optional callback for output streaming.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
CapturedOutput object.
|
|
323
|
+
"""
|
|
324
|
+
command = get_pdd_command(command_name)
|
|
325
|
+
if not command:
|
|
326
|
+
return CapturedOutput(
|
|
327
|
+
stdout="",
|
|
328
|
+
stderr=f"Error: Command '{command_name}' not found.",
|
|
329
|
+
exit_code=1,
|
|
330
|
+
exception=ValueError(f"Unknown command: {command_name}"),
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
executor = ClickCommandExecutor(
|
|
334
|
+
base_context_obj=options,
|
|
335
|
+
output_callback=callback,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
return executor.execute(command, params=args)
|