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/cli.py
CHANGED
|
@@ -7,1196 +7,37 @@ generating code, tests, fixing issues, and managing prompts.
|
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
import
|
|
11
|
-
from
|
|
12
|
-
from pathlib import Path # Import Path
|
|
10
|
+
from .core.cli import cli
|
|
11
|
+
from .commands import register_commands
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
from rich.theme import Theme
|
|
17
|
-
from rich.markup import MarkupError, escape
|
|
13
|
+
# Register all commands
|
|
14
|
+
register_commands(cli)
|
|
18
15
|
|
|
19
|
-
#
|
|
20
|
-
from . import
|
|
21
|
-
from .auto_deps_main import auto_deps_main
|
|
16
|
+
# Re-export commonly used items for backward compatibility
|
|
17
|
+
from .commands.templates import templates_group
|
|
22
18
|
from .auto_update import auto_update
|
|
23
|
-
from .bug_main import bug_main
|
|
24
|
-
from .change_main import change_main
|
|
25
|
-
from .cmd_test_main import cmd_test_main
|
|
26
19
|
from .code_generator_main import code_generator_main
|
|
27
|
-
from .conflicts_main import conflicts_main
|
|
28
|
-
# Need to import construct_paths for tests patching pdd.cli.construct_paths
|
|
29
|
-
from .construct_paths import construct_paths
|
|
30
20
|
from .context_generator_main import context_generator_main
|
|
31
|
-
from .
|
|
32
|
-
from .detect_change_main import detect_change_main
|
|
21
|
+
from .cmd_test_main import cmd_test_main
|
|
33
22
|
from .fix_main import fix_main
|
|
34
|
-
from .fix_verification_main import fix_verification_main
|
|
35
|
-
from .install_completion import install_completion, get_local_pdd_path
|
|
36
|
-
from .preprocess_main import preprocess_main
|
|
37
23
|
from .split_main import split_main
|
|
24
|
+
from .change_main import change_main
|
|
25
|
+
from .update_main import update_main
|
|
38
26
|
from .sync_main import sync_main
|
|
27
|
+
from .auto_deps_main import auto_deps_main
|
|
28
|
+
from .detect_change_main import detect_change_main
|
|
29
|
+
from .conflicts_main import conflicts_main
|
|
30
|
+
from .bug_main import bug_main
|
|
31
|
+
from .crash_main import crash_main
|
|
39
32
|
from .trace_main import trace_main
|
|
40
|
-
from .
|
|
41
|
-
from .
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"warning": "yellow",
|
|
49
|
-
"error": "bold red",
|
|
50
|
-
"success": "green",
|
|
51
|
-
"path": "dim blue",
|
|
52
|
-
"command": "bold magenta",
|
|
53
|
-
})
|
|
54
|
-
console = Console(theme=custom_theme)
|
|
55
|
-
|
|
56
|
-
# --- Helper Function for Error Handling ---
|
|
57
|
-
def handle_error(exception: Exception, command_name: str, quiet: bool):
|
|
58
|
-
"""Prints error messages using Rich console.""" # Modified docstring
|
|
59
|
-
if not quiet:
|
|
60
|
-
console.print(f"[error]Error during '{command_name}' command:[/error]", style="error")
|
|
61
|
-
if isinstance(exception, FileNotFoundError):
|
|
62
|
-
console.print(f" [error]File not found:[/error] {exception}", style="error")
|
|
63
|
-
elif isinstance(exception, (ValueError, IOError)):
|
|
64
|
-
console.print(f" [error]Input/Output Error:[/error] {exception}", style="error")
|
|
65
|
-
elif isinstance(exception, click.UsageError): # Handle Click usage errors explicitly if needed
|
|
66
|
-
console.print(f" [error]Usage Error:[/error] {exception}", style="error")
|
|
67
|
-
# click.UsageError should typically exit with 2, but we are handling it.
|
|
68
|
-
elif isinstance(exception, MarkupError):
|
|
69
|
-
console.print(" [error]Markup Error:[/error] Invalid Rich markup encountered.", style="error")
|
|
70
|
-
# Print the error message safely escaped
|
|
71
|
-
console.print(escape(str(exception)))
|
|
72
|
-
else:
|
|
73
|
-
console.print(f" [error]An unexpected error occurred:[/error] {exception}", style="error")
|
|
74
|
-
# Do NOT re-raise e here. Let the command function return None.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# --- Main CLI Group ---
|
|
78
|
-
@click.group(chain=True, help="PDD (Prompt-Driven Development) Command Line Interface.")
|
|
79
|
-
@click.option(
|
|
80
|
-
"--force",
|
|
81
|
-
is_flag=True,
|
|
82
|
-
default=False,
|
|
83
|
-
help="Overwrite existing files without asking for confirmation.",
|
|
84
|
-
)
|
|
85
|
-
@click.option(
|
|
86
|
-
"--strength",
|
|
87
|
-
type=click.FloatRange(0.0, 1.0),
|
|
88
|
-
default=DEFAULT_STRENGTH,
|
|
89
|
-
show_default=True,
|
|
90
|
-
help="Set the strength of the AI model (0.0 to 1.0).",
|
|
91
|
-
)
|
|
92
|
-
@click.option(
|
|
93
|
-
"--temperature",
|
|
94
|
-
type=click.FloatRange(0.0, 2.0), # Allow higher temperatures if needed
|
|
95
|
-
default=0.0,
|
|
96
|
-
show_default=True,
|
|
97
|
-
help="Set the temperature of the AI model.",
|
|
98
|
-
)
|
|
99
|
-
@click.option(
|
|
100
|
-
"--time",
|
|
101
|
-
type=click.FloatRange(0.0, 1.0),
|
|
102
|
-
default=None,
|
|
103
|
-
show_default=True,
|
|
104
|
-
help="Controls reasoning allocation for LLMs (0.0-1.0). Uses DEFAULT_TIME if None.",
|
|
105
|
-
)
|
|
106
|
-
@click.option(
|
|
107
|
-
"--verbose",
|
|
108
|
-
is_flag=True,
|
|
109
|
-
default=False,
|
|
110
|
-
help="Increase output verbosity for more detailed information.",
|
|
111
|
-
)
|
|
112
|
-
@click.option(
|
|
113
|
-
"--quiet",
|
|
114
|
-
is_flag=True,
|
|
115
|
-
default=False,
|
|
116
|
-
help="Decrease output verbosity for minimal information.",
|
|
117
|
-
)
|
|
118
|
-
@click.option(
|
|
119
|
-
"--output-cost",
|
|
120
|
-
type=click.Path(dir_okay=False, writable=True),
|
|
121
|
-
default=None,
|
|
122
|
-
help="Enable cost tracking and output a CSV file with usage details.",
|
|
123
|
-
)
|
|
124
|
-
@click.option(
|
|
125
|
-
"--review-examples",
|
|
126
|
-
is_flag=True,
|
|
127
|
-
default=False,
|
|
128
|
-
help="Review and optionally exclude few-shot examples before command execution.",
|
|
129
|
-
)
|
|
130
|
-
@click.option(
|
|
131
|
-
"--local",
|
|
132
|
-
is_flag=True,
|
|
133
|
-
default=False,
|
|
134
|
-
help="Run commands locally instead of in the cloud.",
|
|
135
|
-
)
|
|
136
|
-
@click.version_option(version=__version__, package_name="pdd-cli")
|
|
137
|
-
@click.pass_context
|
|
138
|
-
def cli(
|
|
139
|
-
ctx: click.Context,
|
|
140
|
-
force: bool,
|
|
141
|
-
strength: float,
|
|
142
|
-
temperature: float,
|
|
143
|
-
verbose: bool,
|
|
144
|
-
quiet: bool,
|
|
145
|
-
output_cost: Optional[str],
|
|
146
|
-
review_examples: bool,
|
|
147
|
-
local: bool,
|
|
148
|
-
time: Optional[float], # Type hint is Optional[float]
|
|
149
|
-
):
|
|
150
|
-
"""
|
|
151
|
-
Main entry point for the PDD CLI. Handles global options and initializes context.
|
|
152
|
-
Supports multi-command chaining.
|
|
153
|
-
"""
|
|
154
|
-
# Ensure PDD_PATH is set before any commands run
|
|
155
|
-
get_local_pdd_path()
|
|
156
|
-
|
|
157
|
-
ctx.ensure_object(dict)
|
|
158
|
-
ctx.obj["force"] = force
|
|
159
|
-
ctx.obj["strength"] = strength
|
|
160
|
-
ctx.obj["temperature"] = temperature
|
|
161
|
-
ctx.obj["verbose"] = verbose
|
|
162
|
-
ctx.obj["quiet"] = quiet
|
|
163
|
-
ctx.obj["output_cost"] = output_cost
|
|
164
|
-
ctx.obj["review_examples"] = review_examples
|
|
165
|
-
ctx.obj["local"] = local
|
|
166
|
-
# Use DEFAULT_TIME if time is not provided
|
|
167
|
-
ctx.obj["time"] = time if time is not None else DEFAULT_TIME
|
|
168
|
-
|
|
169
|
-
# Suppress verbose if quiet is enabled
|
|
170
|
-
if quiet:
|
|
171
|
-
ctx.obj["verbose"] = False
|
|
172
|
-
|
|
173
|
-
# Perform auto-update check unless disabled
|
|
174
|
-
if os.getenv("PDD_AUTO_UPDATE", "true").lower() != "false":
|
|
175
|
-
try:
|
|
176
|
-
if not quiet:
|
|
177
|
-
console.print("[info]Checking for updates...[/info]")
|
|
178
|
-
# Removed quiet=quiet argument as it caused TypeError
|
|
179
|
-
auto_update()
|
|
180
|
-
except Exception as exception: # Using more descriptive name
|
|
181
|
-
if not quiet:
|
|
182
|
-
console.print(
|
|
183
|
-
f"[warning]Auto-update check failed:[/warning] {exception}",
|
|
184
|
-
style="warning"
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
# --- Result Callback for Chained Commands ---
|
|
188
|
-
@cli.result_callback()
|
|
189
|
-
@click.pass_context
|
|
190
|
-
def process_commands(ctx: click.Context, results: List[Optional[Tuple[Any, float, str]]], **kwargs):
|
|
191
|
-
"""
|
|
192
|
-
Processes the results from chained commands.
|
|
193
|
-
|
|
194
|
-
Receives a list of tuples, typically (result, cost, model_name),
|
|
195
|
-
or None from each command function.
|
|
196
|
-
"""
|
|
197
|
-
total_chain_cost = 0.0
|
|
198
|
-
# Get invoked subcommands directly from the group context if available (safer for testing)
|
|
199
|
-
# Note: This might yield "Unknown Command" during tests with CliRunner
|
|
200
|
-
invoked_subcommands = getattr(ctx, 'invoked_subcommands', [])
|
|
201
|
-
num_commands = len(invoked_subcommands)
|
|
202
|
-
num_results = len(results) # Number of results actually received
|
|
203
|
-
|
|
204
|
-
if not ctx.obj.get("quiet"):
|
|
205
|
-
console.print("\n[info]--- Command Chain Execution Summary ---[/info]")
|
|
206
|
-
|
|
207
|
-
for i, result_tuple in enumerate(results):
|
|
208
|
-
# Use the retrieved subcommand name (might be "Unknown Command X" in tests)
|
|
209
|
-
command_name = invoked_subcommands[i] if i < num_commands else f"Unknown Command {i+1}"
|
|
210
|
-
|
|
211
|
-
# Check if the command failed (returned None)
|
|
212
|
-
if result_tuple is None:
|
|
213
|
-
if not ctx.obj.get("quiet"):
|
|
214
|
-
# Check if it was install_completion (which normally returns None)
|
|
215
|
-
if command_name == "install_completion":
|
|
216
|
-
console.print(f" [info]Step {i+1} ({command_name}):[/info] Command completed.")
|
|
217
|
-
# If command name is unknown, and it might be install_completion which prints its own status
|
|
218
|
-
elif command_name.startswith("Unknown Command"):
|
|
219
|
-
console.print(f" [info]Step {i+1} ({command_name}):[/info] Command executed (see output above for status details).")
|
|
220
|
-
# Check if it was preprocess (which returns a dummy tuple on success)
|
|
221
|
-
# This case handles actual failure for preprocess
|
|
222
|
-
elif command_name == "preprocess":
|
|
223
|
-
console.print(f" [error]Step {i+1} ({command_name}):[/error] Command failed.")
|
|
224
|
-
else:
|
|
225
|
-
console.print(f" [error]Step {i+1} ({command_name}):[/error] Command failed.")
|
|
226
|
-
# Check if the result is the expected tuple structure from @track_cost or preprocess success
|
|
227
|
-
elif isinstance(result_tuple, tuple) and len(result_tuple) == 3:
|
|
228
|
-
_result_data, cost, model_name = result_tuple
|
|
229
|
-
total_chain_cost += cost
|
|
230
|
-
if not ctx.obj.get("quiet"):
|
|
231
|
-
# Special handling for preprocess success message (check actual command name)
|
|
232
|
-
actual_command_name = invoked_subcommands[i] if i < num_commands else None # Get actual name if possible
|
|
233
|
-
if actual_command_name == "preprocess" and cost == 0.0 and model_name == "local":
|
|
234
|
-
console.print(f" [info]Step {i+1} ({command_name}):[/info] Command completed (local).")
|
|
235
|
-
else:
|
|
236
|
-
# Generic output using potentially "Unknown Command" name
|
|
237
|
-
console.print(f" [info]Step {i+1} ({command_name}):[/info] Cost: ${cost:.6f}, Model: {model_name}")
|
|
238
|
-
else:
|
|
239
|
-
# Handle unexpected return types if necessary
|
|
240
|
-
if not ctx.obj.get("quiet"):
|
|
241
|
-
# Provide more detail on the unexpected type
|
|
242
|
-
console.print(f" [warning]Step {i+1} ({command_name}):[/warning] Unexpected result format: {type(result_tuple).__name__} - {str(result_tuple)[:50]}...")
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if not ctx.obj.get("quiet"):
|
|
246
|
-
# Only print total cost if at least one command potentially contributed cost
|
|
247
|
-
if any(res is not None and isinstance(res, tuple) and len(res) == 3 for res in results):
|
|
248
|
-
console.print(f"[info]Total Estimated Cost for Chain:[/info] ${total_chain_cost:.6f}")
|
|
249
|
-
# Indicate if the chain might have been incomplete due to errors
|
|
250
|
-
if num_results < num_commands and not all(res is None for res in results): # Avoid printing if all failed
|
|
251
|
-
console.print("[warning]Note: Chain may have terminated early due to errors.[/warning]")
|
|
252
|
-
console.print("[info]-------------------------------------[/info]")
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
# --- Command Definitions ---
|
|
256
|
-
|
|
257
|
-
@cli.command("generate")
|
|
258
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
259
|
-
@click.option(
|
|
260
|
-
"--output",
|
|
261
|
-
type=click.Path(writable=True),
|
|
262
|
-
default=None,
|
|
263
|
-
help="Specify where to save the generated code (file or directory).",
|
|
264
|
-
)
|
|
265
|
-
@click.option(
|
|
266
|
-
"--original-prompt",
|
|
267
|
-
"original_prompt_file_path",
|
|
268
|
-
type=click.Path(exists=True, dir_okay=False),
|
|
269
|
-
default=None,
|
|
270
|
-
help="Path to the original prompt file for incremental generation.",
|
|
271
|
-
)
|
|
272
|
-
@click.option(
|
|
273
|
-
"--force-incremental",
|
|
274
|
-
"force_incremental_flag",
|
|
275
|
-
is_flag=True,
|
|
276
|
-
default=False,
|
|
277
|
-
help="Force incremental generation even if full regeneration is suggested.",
|
|
278
|
-
)
|
|
279
|
-
@click.pass_context
|
|
280
|
-
@track_cost
|
|
281
|
-
def generate(
|
|
282
|
-
ctx: click.Context,
|
|
283
|
-
prompt_file: str,
|
|
284
|
-
output: Optional[str],
|
|
285
|
-
original_prompt_file_path: Optional[str],
|
|
286
|
-
force_incremental_flag: bool,
|
|
287
|
-
) -> Optional[Tuple[str, float, str]]:
|
|
288
|
-
"""Generate code from a prompt file."""
|
|
289
|
-
try:
|
|
290
|
-
generated_code, incremental, total_cost, model_name = code_generator_main(
|
|
291
|
-
ctx=ctx,
|
|
292
|
-
prompt_file=prompt_file,
|
|
293
|
-
output=output,
|
|
294
|
-
original_prompt_file_path=original_prompt_file_path,
|
|
295
|
-
force_incremental_flag=force_incremental_flag,
|
|
296
|
-
)
|
|
297
|
-
return generated_code, total_cost, model_name
|
|
298
|
-
except Exception as exception:
|
|
299
|
-
handle_error(exception, "generate", ctx.obj.get("quiet", False))
|
|
300
|
-
return None
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
@cli.command("example")
|
|
304
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
305
|
-
@click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
|
|
306
|
-
@click.option(
|
|
307
|
-
"--output",
|
|
308
|
-
type=click.Path(writable=True),
|
|
309
|
-
default=None,
|
|
310
|
-
help="Specify where to save the generated example code (file or directory).",
|
|
311
|
-
)
|
|
312
|
-
@click.pass_context
|
|
313
|
-
@track_cost
|
|
314
|
-
def example(
|
|
315
|
-
ctx: click.Context,
|
|
316
|
-
prompt_file: str,
|
|
317
|
-
code_file: str,
|
|
318
|
-
output: Optional[str]
|
|
319
|
-
) -> Optional[Tuple[str, float, str]]:
|
|
320
|
-
"""Generate example code for a given prompt and implementation."""
|
|
321
|
-
try:
|
|
322
|
-
example_code, total_cost, model_name = context_generator_main(
|
|
323
|
-
ctx=ctx,
|
|
324
|
-
prompt_file=prompt_file,
|
|
325
|
-
code_file=code_file,
|
|
326
|
-
output=output,
|
|
327
|
-
)
|
|
328
|
-
return example_code, total_cost, model_name
|
|
329
|
-
except Exception as exception:
|
|
330
|
-
handle_error(exception, "example", ctx.obj.get("quiet", False))
|
|
331
|
-
return None
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
@cli.command("test")
|
|
335
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
336
|
-
@click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
|
|
337
|
-
@click.option(
|
|
338
|
-
"--output",
|
|
339
|
-
type=click.Path(writable=True),
|
|
340
|
-
default=None,
|
|
341
|
-
help="Specify where to save the generated test file (file or directory).",
|
|
342
|
-
)
|
|
343
|
-
@click.option(
|
|
344
|
-
"--language",
|
|
345
|
-
type=str,
|
|
346
|
-
default=None,
|
|
347
|
-
help="Specify the programming language."
|
|
348
|
-
)
|
|
349
|
-
@click.option(
|
|
350
|
-
"--coverage-report",
|
|
351
|
-
type=click.Path(exists=True, dir_okay=False),
|
|
352
|
-
default=None,
|
|
353
|
-
help="Path to the coverage report file for existing tests.",
|
|
354
|
-
)
|
|
355
|
-
@click.option(
|
|
356
|
-
"--existing-tests",
|
|
357
|
-
type=click.Path(exists=True, dir_okay=False),
|
|
358
|
-
default=None,
|
|
359
|
-
help="Path to the existing unit test file.",
|
|
360
|
-
)
|
|
361
|
-
@click.option(
|
|
362
|
-
"--target-coverage",
|
|
363
|
-
type=click.FloatRange(0.0, 100.0),
|
|
364
|
-
default=None, # Use None, default handled in cmd_test_main or env var
|
|
365
|
-
help="Desired code coverage percentage (default: 10.0 or PDD_TEST_COVERAGE_TARGET).",
|
|
366
|
-
)
|
|
367
|
-
@click.option(
|
|
368
|
-
"--merge",
|
|
369
|
-
is_flag=True,
|
|
370
|
-
default=False,
|
|
371
|
-
help="Merge new tests with existing test file instead of creating a separate file.",
|
|
372
|
-
)
|
|
373
|
-
@click.pass_context
|
|
374
|
-
@track_cost
|
|
375
|
-
def test(
|
|
376
|
-
ctx: click.Context,
|
|
377
|
-
prompt_file: str,
|
|
378
|
-
code_file: str,
|
|
379
|
-
output: Optional[str],
|
|
380
|
-
language: Optional[str],
|
|
381
|
-
coverage_report: Optional[str],
|
|
382
|
-
existing_tests: Optional[str],
|
|
383
|
-
target_coverage: Optional[float],
|
|
384
|
-
merge: bool,
|
|
385
|
-
) -> Optional[Tuple[str, float, str]]:
|
|
386
|
-
"""Generate unit tests for a given prompt and implementation."""
|
|
387
|
-
try:
|
|
388
|
-
test_code, total_cost, model_name = cmd_test_main(
|
|
389
|
-
ctx=ctx,
|
|
390
|
-
prompt_file=prompt_file,
|
|
391
|
-
code_file=code_file,
|
|
392
|
-
output=output,
|
|
393
|
-
language=language,
|
|
394
|
-
coverage_report=coverage_report,
|
|
395
|
-
existing_tests=existing_tests,
|
|
396
|
-
target_coverage=target_coverage,
|
|
397
|
-
merge=merge,
|
|
398
|
-
)
|
|
399
|
-
return test_code, total_cost, model_name
|
|
400
|
-
except Exception as exception:
|
|
401
|
-
handle_error(exception, "test", ctx.obj.get("quiet", False))
|
|
402
|
-
return None
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
@cli.command("preprocess")
|
|
406
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
407
|
-
@click.option(
|
|
408
|
-
"--output",
|
|
409
|
-
type=click.Path(writable=True),
|
|
410
|
-
default=None,
|
|
411
|
-
help="Specify where to save the preprocessed prompt file (file or directory).",
|
|
412
|
-
)
|
|
413
|
-
@click.option(
|
|
414
|
-
"--xml",
|
|
415
|
-
is_flag=True,
|
|
416
|
-
default=False,
|
|
417
|
-
help="Insert XML delimiters for structure (minimal preprocessing).",
|
|
418
|
-
)
|
|
419
|
-
@click.option(
|
|
420
|
-
"--recursive",
|
|
421
|
-
is_flag=True,
|
|
422
|
-
default=False,
|
|
423
|
-
help="Recursively preprocess includes.",
|
|
424
|
-
)
|
|
425
|
-
@click.option(
|
|
426
|
-
"--double",
|
|
427
|
-
is_flag=True,
|
|
428
|
-
default=False,
|
|
429
|
-
help="Double curly brackets.",
|
|
430
|
-
)
|
|
431
|
-
@click.option(
|
|
432
|
-
"--exclude",
|
|
433
|
-
multiple=True,
|
|
434
|
-
default=None,
|
|
435
|
-
help="List of keys to exclude from curly bracket doubling.",
|
|
436
|
-
)
|
|
437
|
-
@click.pass_context
|
|
438
|
-
# No @track_cost as preprocessing is local, but return dummy tuple for callback
|
|
439
|
-
def preprocess(
|
|
440
|
-
ctx: click.Context,
|
|
441
|
-
prompt_file: str,
|
|
442
|
-
output: Optional[str],
|
|
443
|
-
xml: bool,
|
|
444
|
-
recursive: bool,
|
|
445
|
-
double: bool,
|
|
446
|
-
exclude: Optional[Tuple[str, ...]],
|
|
447
|
-
) -> Optional[Tuple[str, float, str]]:
|
|
448
|
-
"""Preprocess a prompt file to prepare it for LLM use."""
|
|
449
|
-
try:
|
|
450
|
-
# Since preprocess is a local operation, we don't track cost
|
|
451
|
-
# But we need to return a tuple in the expected format for result callback
|
|
452
|
-
result = preprocess_main(
|
|
453
|
-
ctx=ctx,
|
|
454
|
-
prompt_file=prompt_file,
|
|
455
|
-
output=output,
|
|
456
|
-
xml=xml,
|
|
457
|
-
recursive=recursive,
|
|
458
|
-
double=double,
|
|
459
|
-
exclude=list(exclude) if exclude else [],
|
|
460
|
-
)
|
|
461
|
-
|
|
462
|
-
# Handle the result from preprocess_main
|
|
463
|
-
if result is None:
|
|
464
|
-
# If preprocess_main returns None, still return a dummy tuple for the callback
|
|
465
|
-
return "", 0.0, "local"
|
|
466
|
-
else:
|
|
467
|
-
# Unpack the return value from preprocess_main
|
|
468
|
-
processed_prompt, total_cost, model_name = result
|
|
469
|
-
return processed_prompt, total_cost, model_name
|
|
470
|
-
except Exception as exception:
|
|
471
|
-
handle_error(exception, "preprocess", ctx.obj.get("quiet", False))
|
|
472
|
-
return None
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
@cli.command("fix")
|
|
476
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
477
|
-
@click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
|
|
478
|
-
@click.argument("unit_test_file", type=click.Path(exists=True, dir_okay=False))
|
|
479
|
-
@click.argument("error_file", type=click.Path(dir_okay=False)) # Allow non-existent for loop mode
|
|
480
|
-
@click.option(
|
|
481
|
-
"--output-test",
|
|
482
|
-
type=click.Path(writable=True),
|
|
483
|
-
default=None,
|
|
484
|
-
help="Specify where to save the fixed unit test file (file or directory).",
|
|
485
|
-
)
|
|
486
|
-
@click.option(
|
|
487
|
-
"--output-code",
|
|
488
|
-
type=click.Path(writable=True),
|
|
489
|
-
default=None,
|
|
490
|
-
help="Specify where to save the fixed code file (file or directory).",
|
|
491
|
-
)
|
|
492
|
-
@click.option(
|
|
493
|
-
"--output-results",
|
|
494
|
-
type=click.Path(writable=True),
|
|
495
|
-
default=None,
|
|
496
|
-
help="Specify where to save the results log (file or directory).",
|
|
497
|
-
)
|
|
498
|
-
@click.option(
|
|
499
|
-
"--loop",
|
|
500
|
-
is_flag=True,
|
|
501
|
-
default=False,
|
|
502
|
-
help="Enable iterative fixing process."
|
|
503
|
-
)
|
|
504
|
-
@click.option(
|
|
505
|
-
"--verification-program",
|
|
506
|
-
type=click.Path(exists=True, dir_okay=False),
|
|
507
|
-
default=None,
|
|
508
|
-
help="Path to a Python program that verifies the fix.",
|
|
509
|
-
)
|
|
510
|
-
@click.option(
|
|
511
|
-
"--max-attempts",
|
|
512
|
-
type=int,
|
|
513
|
-
default=3,
|
|
514
|
-
show_default=True,
|
|
515
|
-
help="Maximum number of fix attempts.",
|
|
516
|
-
)
|
|
517
|
-
@click.option(
|
|
518
|
-
"--budget",
|
|
519
|
-
type=float,
|
|
520
|
-
default=5.0,
|
|
521
|
-
show_default=True,
|
|
522
|
-
help="Maximum cost allowed for the fixing process.",
|
|
523
|
-
)
|
|
524
|
-
@click.option(
|
|
525
|
-
"--auto-submit",
|
|
526
|
-
is_flag=True,
|
|
527
|
-
default=False,
|
|
528
|
-
help="Automatically submit the example if all unit tests pass.",
|
|
529
|
-
)
|
|
530
|
-
@click.pass_context
|
|
531
|
-
@track_cost
|
|
532
|
-
def fix(
|
|
533
|
-
ctx: click.Context,
|
|
534
|
-
prompt_file: str,
|
|
535
|
-
code_file: str,
|
|
536
|
-
unit_test_file: str,
|
|
537
|
-
error_file: str,
|
|
538
|
-
output_test: Optional[str],
|
|
539
|
-
output_code: Optional[str],
|
|
540
|
-
output_results: Optional[str],
|
|
541
|
-
loop: bool,
|
|
542
|
-
verification_program: Optional[str],
|
|
543
|
-
max_attempts: int,
|
|
544
|
-
budget: float,
|
|
545
|
-
auto_submit: bool,
|
|
546
|
-
) -> Optional[Tuple[Dict[str, Any], float, str]]:
|
|
547
|
-
"""Fix code based on a prompt and unit test errors."""
|
|
548
|
-
try:
|
|
549
|
-
# The actual logic is in fix_main
|
|
550
|
-
success, fixed_unit_test, fixed_code, attempts, total_cost, model_name = fix_main(
|
|
551
|
-
ctx=ctx,
|
|
552
|
-
prompt_file=prompt_file,
|
|
553
|
-
code_file=code_file,
|
|
554
|
-
unit_test_file=unit_test_file,
|
|
555
|
-
error_file=error_file,
|
|
556
|
-
output_test=output_test,
|
|
557
|
-
output_code=output_code,
|
|
558
|
-
output_results=output_results,
|
|
559
|
-
loop=loop,
|
|
560
|
-
verification_program=verification_program,
|
|
561
|
-
max_attempts=max_attempts,
|
|
562
|
-
budget=budget,
|
|
563
|
-
auto_submit=auto_submit,
|
|
564
|
-
)
|
|
565
|
-
result = {
|
|
566
|
-
"success": success,
|
|
567
|
-
"fixed_unit_test": fixed_unit_test,
|
|
568
|
-
"fixed_code": fixed_code,
|
|
569
|
-
"attempts": attempts,
|
|
570
|
-
}
|
|
571
|
-
return result, total_cost, model_name
|
|
572
|
-
except Exception as exception:
|
|
573
|
-
handle_error(exception, "fix", ctx.obj.get("quiet", False))
|
|
574
|
-
return None
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
@cli.command("split")
|
|
578
|
-
@click.argument("input_prompt", type=click.Path(exists=True, dir_okay=False))
|
|
579
|
-
@click.argument("input_code", type=click.Path(exists=True, dir_okay=False))
|
|
580
|
-
@click.argument("example_code", type=click.Path(exists=True, dir_okay=False))
|
|
581
|
-
@click.option(
|
|
582
|
-
"--output-sub",
|
|
583
|
-
type=click.Path(writable=True),
|
|
584
|
-
default=None,
|
|
585
|
-
help="Specify where to save the generated sub-prompt file (file or directory).",
|
|
586
|
-
)
|
|
587
|
-
@click.option(
|
|
588
|
-
"--output-modified",
|
|
589
|
-
type=click.Path(writable=True),
|
|
590
|
-
default=None,
|
|
591
|
-
help="Specify where to save the modified prompt file (file or directory).",
|
|
592
|
-
)
|
|
593
|
-
@click.pass_context
|
|
594
|
-
@track_cost
|
|
595
|
-
def split(
|
|
596
|
-
ctx: click.Context,
|
|
597
|
-
input_prompt: str,
|
|
598
|
-
input_code: str,
|
|
599
|
-
example_code: str,
|
|
600
|
-
output_sub: Optional[str],
|
|
601
|
-
output_modified: Optional[str],
|
|
602
|
-
) -> Optional[Tuple[Dict[str, str], float, str]]: # Modified return type
|
|
603
|
-
"""Split large complex prompt files into smaller ones."""
|
|
604
|
-
quiet = ctx.obj.get("quiet", False)
|
|
605
|
-
command_name = "split"
|
|
606
|
-
try:
|
|
607
|
-
result_data, total_cost, model_name = split_main(
|
|
608
|
-
ctx=ctx,
|
|
609
|
-
input_prompt_file=input_prompt,
|
|
610
|
-
input_code_file=input_code,
|
|
611
|
-
example_code_file=example_code,
|
|
612
|
-
output_sub=output_sub,
|
|
613
|
-
output_modified=output_modified,
|
|
614
|
-
)
|
|
615
|
-
return result_data, total_cost, model_name
|
|
616
|
-
except Exception as e:
|
|
617
|
-
handle_error(e, command_name, quiet)
|
|
618
|
-
return None # Return None on failure
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
@cli.command("change")
|
|
622
|
-
@click.argument("change_prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
623
|
-
@click.argument("input_code", type=click.Path(exists=True)) # Can be file or dir
|
|
624
|
-
@click.argument("input_prompt_file", type=click.Path(exists=True, dir_okay=False), required=False)
|
|
625
|
-
@click.option(
|
|
626
|
-
"--budget",
|
|
627
|
-
type=float,
|
|
628
|
-
default=5.0,
|
|
629
|
-
show_default=True,
|
|
630
|
-
help="Maximum cost allowed for the change process.",
|
|
631
|
-
)
|
|
632
|
-
@click.option(
|
|
633
|
-
"--output",
|
|
634
|
-
type=click.Path(writable=True),
|
|
635
|
-
default=None,
|
|
636
|
-
help="Specify where to save the modified prompt file (file or directory).",
|
|
637
|
-
)
|
|
638
|
-
@click.option(
|
|
639
|
-
"--csv",
|
|
640
|
-
"use_csv",
|
|
641
|
-
is_flag=True,
|
|
642
|
-
default=False,
|
|
643
|
-
help="Use a CSV file for batch change prompts.",
|
|
644
|
-
)
|
|
645
|
-
@click.pass_context
|
|
646
|
-
@track_cost
|
|
647
|
-
def change(
|
|
648
|
-
ctx: click.Context,
|
|
649
|
-
change_prompt_file: str,
|
|
650
|
-
input_code: str,
|
|
651
|
-
input_prompt_file: Optional[str],
|
|
652
|
-
output: Optional[str],
|
|
653
|
-
use_csv: bool,
|
|
654
|
-
budget: float,
|
|
655
|
-
) -> Optional[Tuple[str | Dict, float, str]]: # Modified return type
|
|
656
|
-
"""Modify prompt(s) based on change instructions."""
|
|
657
|
-
quiet = ctx.obj.get("quiet", False)
|
|
658
|
-
command_name = "change"
|
|
659
|
-
try:
|
|
660
|
-
# --- ADD VALIDATION LOGIC HERE ---
|
|
661
|
-
input_code_path = Path(input_code) # Convert to Path object
|
|
662
|
-
if use_csv:
|
|
663
|
-
if not input_code_path.is_dir():
|
|
664
|
-
raise click.UsageError("INPUT_CODE must be a directory when using --csv.")
|
|
665
|
-
if input_prompt_file:
|
|
666
|
-
raise click.UsageError("Cannot use --csv and specify an INPUT_PROMPT_FILE simultaneously.")
|
|
667
|
-
else: # Not using CSV
|
|
668
|
-
if not input_prompt_file:
|
|
669
|
-
# This check might be better inside change_main, but can be here too
|
|
670
|
-
raise click.UsageError("INPUT_PROMPT_FILE is required when not using --csv.")
|
|
671
|
-
if not input_code_path.is_file():
|
|
672
|
-
# This check might be better inside change_main, but can be here too
|
|
673
|
-
raise click.UsageError("INPUT_CODE must be a file when not using --csv.")
|
|
674
|
-
# --- END VALIDATION LOGIC ---
|
|
675
|
-
|
|
676
|
-
result_data, total_cost, model_name = change_main(
|
|
677
|
-
ctx=ctx,
|
|
678
|
-
change_prompt_file=change_prompt_file,
|
|
679
|
-
input_code=input_code,
|
|
680
|
-
input_prompt_file=input_prompt_file,
|
|
681
|
-
output=output,
|
|
682
|
-
use_csv=use_csv,
|
|
683
|
-
budget=budget,
|
|
684
|
-
)
|
|
685
|
-
return result_data, total_cost, model_name
|
|
686
|
-
except (click.UsageError, Exception) as e: # Catch specific and general exceptions
|
|
687
|
-
handle_error(e, command_name, quiet)
|
|
688
|
-
return None # Return None on failure
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
@cli.command("update")
|
|
692
|
-
@click.argument("input_prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
693
|
-
@click.argument("modified_code_file", type=click.Path(exists=True, dir_okay=False))
|
|
694
|
-
@click.argument("input_code_file", type=click.Path(exists=True, dir_okay=False), required=False)
|
|
695
|
-
@click.option(
|
|
696
|
-
"--output",
|
|
697
|
-
type=click.Path(writable=True),
|
|
698
|
-
default=None,
|
|
699
|
-
help="Specify where to save the updated prompt file. If not specified, overwrites the original prompt file to maintain it as the source of truth.",
|
|
700
|
-
)
|
|
701
|
-
@click.option(
|
|
702
|
-
"--git",
|
|
703
|
-
is_flag=True,
|
|
704
|
-
default=False,
|
|
705
|
-
help="Use git history to find the original code file.",
|
|
706
|
-
)
|
|
707
|
-
@click.pass_context
|
|
708
|
-
@track_cost
|
|
709
|
-
def update(
|
|
710
|
-
ctx: click.Context,
|
|
711
|
-
input_prompt_file: str,
|
|
712
|
-
modified_code_file: str,
|
|
713
|
-
input_code_file: Optional[str],
|
|
714
|
-
output: Optional[str],
|
|
715
|
-
git: bool,
|
|
716
|
-
) -> Optional[Tuple[str, float, str]]: # Modified return type
|
|
717
|
-
"""Update the original prompt file based on modified code."""
|
|
718
|
-
quiet = ctx.obj.get("quiet", False)
|
|
719
|
-
command_name = "update"
|
|
720
|
-
try:
|
|
721
|
-
if git and input_code_file:
|
|
722
|
-
raise click.UsageError("Cannot use --git and specify an INPUT_CODE_FILE simultaneously.")
|
|
723
|
-
if not git and not input_code_file:
|
|
724
|
-
raise click.UsageError("INPUT_CODE_FILE is required when not using --git.")
|
|
725
|
-
|
|
726
|
-
updated_prompt, total_cost, model_name = update_main(
|
|
727
|
-
ctx=ctx,
|
|
728
|
-
input_prompt_file=input_prompt_file,
|
|
729
|
-
modified_code_file=modified_code_file,
|
|
730
|
-
input_code_file=input_code_file,
|
|
731
|
-
output=output,
|
|
732
|
-
git=git,
|
|
733
|
-
)
|
|
734
|
-
return updated_prompt, total_cost, model_name
|
|
735
|
-
except (click.UsageError, Exception) as e: # Catch specific and general exceptions
|
|
736
|
-
handle_error(e, command_name, quiet)
|
|
737
|
-
return None # Return None on failure
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
@cli.command("detect")
|
|
741
|
-
@click.argument("prompt_files", nargs=-1, type=click.Path(exists=True, dir_okay=False))
|
|
742
|
-
@click.argument("change_file", type=click.Path(exists=True, dir_okay=False))
|
|
743
|
-
@click.option(
|
|
744
|
-
"--output",
|
|
745
|
-
type=click.Path(writable=True),
|
|
746
|
-
default=None,
|
|
747
|
-
help="Specify where to save the CSV analysis results (file or directory).",
|
|
748
|
-
)
|
|
749
|
-
@click.pass_context
|
|
750
|
-
@track_cost
|
|
751
|
-
def detect(
|
|
752
|
-
ctx: click.Context,
|
|
753
|
-
prompt_files: Tuple[str, ...],
|
|
754
|
-
change_file: str,
|
|
755
|
-
output: Optional[str],
|
|
756
|
-
) -> Optional[Tuple[List[Dict[str, str]], float, str]]: # Modified return type
|
|
757
|
-
"""Analyze prompts and a change description to find needed changes."""
|
|
758
|
-
quiet = ctx.obj.get("quiet", False)
|
|
759
|
-
command_name = "detect"
|
|
760
|
-
try:
|
|
761
|
-
if not prompt_files:
|
|
762
|
-
raise click.UsageError("At least one PROMPT_FILE must be provided.")
|
|
763
|
-
|
|
764
|
-
changes_list, total_cost, model_name = detect_change_main(
|
|
765
|
-
ctx=ctx,
|
|
766
|
-
prompt_files=list(prompt_files),
|
|
767
|
-
change_file=change_file,
|
|
768
|
-
output=output,
|
|
769
|
-
)
|
|
770
|
-
return changes_list, total_cost, model_name
|
|
771
|
-
except (click.UsageError, Exception) as e: # Catch specific and general exceptions
|
|
772
|
-
handle_error(e, command_name, quiet)
|
|
773
|
-
return None # Return None on failure
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
@cli.command("conflicts")
|
|
777
|
-
@click.argument("prompt1", type=click.Path(exists=True, dir_okay=False))
|
|
778
|
-
@click.argument("prompt2", type=click.Path(exists=True, dir_okay=False))
|
|
779
|
-
@click.option(
|
|
780
|
-
"--output",
|
|
781
|
-
type=click.Path(writable=True),
|
|
782
|
-
default=None,
|
|
783
|
-
help="Specify where to save the CSV conflict analysis results (file or directory).",
|
|
784
|
-
)
|
|
785
|
-
@click.pass_context
|
|
786
|
-
@track_cost
|
|
787
|
-
def conflicts(
|
|
788
|
-
ctx: click.Context,
|
|
789
|
-
prompt1: str,
|
|
790
|
-
prompt2: str,
|
|
791
|
-
output: Optional[str],
|
|
792
|
-
) -> Optional[Tuple[List[Dict[str, str]], float, str]]: # Modified return type
|
|
793
|
-
"""Analyze two prompt files to find conflicts."""
|
|
794
|
-
quiet = ctx.obj.get("quiet", False)
|
|
795
|
-
command_name = "conflicts"
|
|
796
|
-
try:
|
|
797
|
-
conflicts_list, total_cost, model_name = conflicts_main(
|
|
798
|
-
ctx=ctx,
|
|
799
|
-
prompt1=prompt1,
|
|
800
|
-
prompt2=prompt2,
|
|
801
|
-
output=output,
|
|
802
|
-
)
|
|
803
|
-
return conflicts_list, total_cost, model_name
|
|
804
|
-
except Exception as e:
|
|
805
|
-
handle_error(e, command_name, quiet)
|
|
806
|
-
return None # Return None on failure
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
@cli.command("crash")
|
|
810
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
811
|
-
@click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
|
|
812
|
-
@click.argument("program_file", type=click.Path(exists=True, dir_okay=False))
|
|
813
|
-
@click.argument("error_file", type=click.Path(dir_okay=False)) # Allow non-existent
|
|
814
|
-
@click.option(
|
|
815
|
-
"--output", # Corresponds to output_code in crash_main
|
|
816
|
-
type=click.Path(writable=True),
|
|
817
|
-
default=None,
|
|
818
|
-
help="Specify where to save the fixed code file (file or directory).",
|
|
819
|
-
)
|
|
820
|
-
@click.option(
|
|
821
|
-
"--output-program",
|
|
822
|
-
type=click.Path(writable=True),
|
|
823
|
-
default=None,
|
|
824
|
-
help="Specify where to save the fixed program file (file or directory).",
|
|
825
|
-
)
|
|
826
|
-
@click.option("--loop", is_flag=True, default=False, help="Enable iterative fixing process.")
|
|
827
|
-
@click.option(
|
|
828
|
-
"--max-attempts",
|
|
829
|
-
type=int,
|
|
830
|
-
default=3,
|
|
831
|
-
show_default=True,
|
|
832
|
-
help="Maximum number of fix attempts.",
|
|
833
|
-
)
|
|
834
|
-
@click.option(
|
|
835
|
-
"--budget",
|
|
836
|
-
type=float,
|
|
837
|
-
default=5.0,
|
|
838
|
-
show_default=True,
|
|
839
|
-
help="Maximum cost allowed for the fixing process.",
|
|
840
|
-
)
|
|
841
|
-
@click.pass_context
|
|
842
|
-
@track_cost
|
|
843
|
-
def crash(
|
|
844
|
-
ctx: click.Context,
|
|
845
|
-
prompt_file: str,
|
|
846
|
-
code_file: str,
|
|
847
|
-
program_file: str,
|
|
848
|
-
error_file: str,
|
|
849
|
-
output: Optional[str], # Maps to output_code
|
|
850
|
-
output_program: Optional[str],
|
|
851
|
-
loop: bool,
|
|
852
|
-
max_attempts: int,
|
|
853
|
-
budget: float,
|
|
854
|
-
) -> Optional[Tuple[Dict[str, Any], float, str]]: # Modified return type
|
|
855
|
-
"""Fix errors in a code module and calling program that caused a crash."""
|
|
856
|
-
quiet = ctx.obj.get("quiet", False)
|
|
857
|
-
command_name = "crash"
|
|
858
|
-
try:
|
|
859
|
-
success, fixed_code, fixed_program, attempts, cost, model = crash_main(
|
|
860
|
-
ctx=ctx,
|
|
861
|
-
prompt_file=prompt_file,
|
|
862
|
-
code_file=code_file,
|
|
863
|
-
program_file=program_file,
|
|
864
|
-
error_file=error_file,
|
|
865
|
-
output=output,
|
|
866
|
-
output_program=output_program,
|
|
867
|
-
loop=loop,
|
|
868
|
-
max_attempts=max_attempts,
|
|
869
|
-
budget=budget,
|
|
870
|
-
)
|
|
871
|
-
result_data = {
|
|
872
|
-
"success": success,
|
|
873
|
-
"attempts": attempts,
|
|
874
|
-
"fixed_code": fixed_code,
|
|
875
|
-
"fixed_program": fixed_program,
|
|
876
|
-
}
|
|
877
|
-
return result_data, cost, model
|
|
878
|
-
except Exception as e:
|
|
879
|
-
handle_error(e, command_name, quiet)
|
|
880
|
-
return None # Return None on failure
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
@cli.command("trace")
|
|
884
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
885
|
-
@click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
|
|
886
|
-
@click.argument("code_line", type=int)
|
|
887
|
-
@click.option(
|
|
888
|
-
"--output",
|
|
889
|
-
type=click.Path(writable=True),
|
|
890
|
-
default=None,
|
|
891
|
-
help="Specify where to save the trace analysis results log (file or directory).",
|
|
892
|
-
)
|
|
893
|
-
@click.pass_context
|
|
894
|
-
@track_cost
|
|
895
|
-
def trace(
|
|
896
|
-
ctx: click.Context,
|
|
897
|
-
prompt_file: str,
|
|
898
|
-
code_file: str,
|
|
899
|
-
code_line: int,
|
|
900
|
-
output: Optional[str],
|
|
901
|
-
) -> Optional[Tuple[int | str, float, str]]: # Modified return type
|
|
902
|
-
"""Find the associated line number between a prompt file and generated code."""
|
|
903
|
-
quiet = ctx.obj.get("quiet", False)
|
|
904
|
-
command_name = "trace"
|
|
905
|
-
try:
|
|
906
|
-
prompt_line_result, total_cost, model_name = trace_main(
|
|
907
|
-
ctx=ctx,
|
|
908
|
-
prompt_file=prompt_file,
|
|
909
|
-
code_file=code_file,
|
|
910
|
-
code_line=code_line,
|
|
911
|
-
output=output,
|
|
912
|
-
)
|
|
913
|
-
# Check if trace_main indicated failure (e.g., by returning None or specific error)
|
|
914
|
-
# This depends on trace_main's implementation; assuming it raises exceptions for now.
|
|
915
|
-
if prompt_line_result is None and total_cost == 0.0 and model_name == 'local_error': # Example check if trace_main returns specific tuple on failure
|
|
916
|
-
# Optionally handle specific non-exception failures differently if needed
|
|
917
|
-
# For now, rely on exceptions being raised for errors like out-of-range.
|
|
918
|
-
pass
|
|
919
|
-
return prompt_line_result, total_cost, model_name
|
|
920
|
-
except Exception as e:
|
|
921
|
-
handle_error(e, command_name, quiet)
|
|
922
|
-
# Exit with non-zero status code on any exception
|
|
923
|
-
ctx.exit(1)
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
@cli.command("bug")
|
|
927
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
928
|
-
@click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
|
|
929
|
-
@click.argument("program_file", type=click.Path(exists=True, dir_okay=False))
|
|
930
|
-
@click.argument("current_output_file", type=click.Path(exists=True, dir_okay=False))
|
|
931
|
-
@click.argument("desired_output_file", type=click.Path(exists=True, dir_okay=False))
|
|
932
|
-
@click.option(
|
|
933
|
-
"--output",
|
|
934
|
-
type=click.Path(writable=True),
|
|
935
|
-
default=None,
|
|
936
|
-
help="Specify where to save the generated unit test (file or directory).",
|
|
937
|
-
)
|
|
938
|
-
@click.option("--language", type=str, default=None, help="Specify the programming language (default: Python).")
|
|
939
|
-
@click.pass_context
|
|
940
|
-
@track_cost
|
|
941
|
-
def bug(
|
|
942
|
-
ctx: click.Context,
|
|
943
|
-
prompt_file: str,
|
|
944
|
-
code_file: str,
|
|
945
|
-
program_file: str,
|
|
946
|
-
current_output_file: str,
|
|
947
|
-
desired_output_file: str,
|
|
948
|
-
output: Optional[str],
|
|
949
|
-
language: Optional[str],
|
|
950
|
-
) -> Optional[Tuple[str, float, str]]: # Modified return type
|
|
951
|
-
"""Generate a unit test based on observed and desired outputs."""
|
|
952
|
-
quiet = ctx.obj.get("quiet", False)
|
|
953
|
-
command_name = "bug"
|
|
954
|
-
try:
|
|
955
|
-
unit_test_content, total_cost, model_name = bug_main(
|
|
956
|
-
ctx=ctx,
|
|
957
|
-
prompt_file=prompt_file,
|
|
958
|
-
code_file=code_file,
|
|
959
|
-
program_file=program_file,
|
|
960
|
-
current_output=current_output_file,
|
|
961
|
-
desired_output=desired_output_file,
|
|
962
|
-
output=output,
|
|
963
|
-
language=language,
|
|
964
|
-
)
|
|
965
|
-
return unit_test_content, total_cost, model_name
|
|
966
|
-
except Exception as e:
|
|
967
|
-
handle_error(e, command_name, quiet)
|
|
968
|
-
return None # Return None on failure
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
@cli.command("auto-deps")
|
|
972
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
973
|
-
@click.argument("directory_path", type=str) # Path with potential glob pattern
|
|
974
|
-
@click.option(
|
|
975
|
-
"--output",
|
|
976
|
-
type=click.Path(writable=True),
|
|
977
|
-
default=None,
|
|
978
|
-
help="Specify where to save the modified prompt file (file or directory).",
|
|
979
|
-
)
|
|
980
|
-
@click.option(
|
|
981
|
-
"--csv",
|
|
982
|
-
"auto_deps_csv_path",
|
|
983
|
-
type=click.Path(dir_okay=False), # CSV path is a file
|
|
984
|
-
default=None, # Default handled by auto_deps_main or env var
|
|
985
|
-
help="Specify the CSV file for dependency info (default: project_dependencies.csv or PDD_AUTO_DEPS_CSV_PATH).",
|
|
986
|
-
)
|
|
987
|
-
@click.option(
|
|
988
|
-
"--force-scan",
|
|
989
|
-
is_flag=True,
|
|
990
|
-
default=False,
|
|
991
|
-
help="Force rescanning of all potential dependency files.",
|
|
992
|
-
)
|
|
993
|
-
@click.pass_context
|
|
994
|
-
@track_cost
|
|
995
|
-
def auto_deps(
|
|
996
|
-
ctx: click.Context,
|
|
997
|
-
prompt_file: str,
|
|
998
|
-
directory_path: str,
|
|
999
|
-
output: Optional[str],
|
|
1000
|
-
auto_deps_csv_path: Optional[str],
|
|
1001
|
-
force_scan: bool,
|
|
1002
|
-
) -> Optional[Tuple[str, float, str]]: # Modified return type
|
|
1003
|
-
"""Analyze prompt and insert dependencies from a directory."""
|
|
1004
|
-
quiet = ctx.obj.get("quiet", False)
|
|
1005
|
-
command_name = "auto-deps"
|
|
1006
|
-
try:
|
|
1007
|
-
clean_directory_path = directory_path.strip('\"')
|
|
1008
|
-
|
|
1009
|
-
modified_prompt, total_cost, model_name = auto_deps_main(
|
|
1010
|
-
ctx=ctx,
|
|
1011
|
-
prompt_file=prompt_file,
|
|
1012
|
-
directory_path=clean_directory_path,
|
|
1013
|
-
auto_deps_csv_path=auto_deps_csv_path,
|
|
1014
|
-
output=output,
|
|
1015
|
-
force_scan=force_scan,
|
|
1016
|
-
)
|
|
1017
|
-
return modified_prompt, total_cost, model_name
|
|
1018
|
-
except Exception as e:
|
|
1019
|
-
handle_error(e, command_name, quiet)
|
|
1020
|
-
return None # Return None on failure
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
@cli.command("verify")
|
|
1024
|
-
@click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
|
|
1025
|
-
@click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
|
|
1026
|
-
@click.argument("program_file", type=click.Path(exists=True, dir_okay=False))
|
|
1027
|
-
@click.option(
|
|
1028
|
-
"--output-results",
|
|
1029
|
-
type=click.Path(writable=True),
|
|
1030
|
-
default=None,
|
|
1031
|
-
help="Specify where to save the verification results log (file or directory).",
|
|
1032
|
-
)
|
|
1033
|
-
@click.option(
|
|
1034
|
-
"--output-code",
|
|
1035
|
-
type=click.Path(writable=True),
|
|
1036
|
-
default=None,
|
|
1037
|
-
help="Specify where to save the verified code file (file or directory).",
|
|
1038
|
-
)
|
|
1039
|
-
@click.option(
|
|
1040
|
-
"--output-program",
|
|
1041
|
-
type=click.Path(writable=True),
|
|
1042
|
-
default=None,
|
|
1043
|
-
help="Specify where to save the verified program file (file or directory).",
|
|
1044
|
-
)
|
|
1045
|
-
@click.option(
|
|
1046
|
-
"--max-attempts",
|
|
1047
|
-
type=int,
|
|
1048
|
-
default=3,
|
|
1049
|
-
show_default=True,
|
|
1050
|
-
help="Maximum number of fix attempts within the verification loop.",
|
|
1051
|
-
)
|
|
1052
|
-
@click.option(
|
|
1053
|
-
"--budget",
|
|
1054
|
-
type=float,
|
|
1055
|
-
default=5.0,
|
|
1056
|
-
show_default=True,
|
|
1057
|
-
help="Maximum cost allowed for the verification and fixing process.",
|
|
1058
|
-
)
|
|
1059
|
-
@click.pass_context
|
|
1060
|
-
@track_cost
|
|
1061
|
-
def verify(
|
|
1062
|
-
ctx: click.Context,
|
|
1063
|
-
prompt_file: str,
|
|
1064
|
-
code_file: str,
|
|
1065
|
-
program_file: str,
|
|
1066
|
-
output_results: Optional[str],
|
|
1067
|
-
output_code: Optional[str],
|
|
1068
|
-
output_program: Optional[str],
|
|
1069
|
-
max_attempts: int,
|
|
1070
|
-
budget: float,
|
|
1071
|
-
) -> Optional[Tuple[Dict[str, Any], float, str]]: # Modified return type
|
|
1072
|
-
"""Verify code correctness against prompt using LLM judgment."""
|
|
1073
|
-
quiet = ctx.obj.get("quiet", False)
|
|
1074
|
-
command_name = "verify"
|
|
1075
|
-
try:
|
|
1076
|
-
success, final_program, final_code, attempts, total_cost_value, model_name_value = fix_verification_main(
|
|
1077
|
-
ctx=ctx,
|
|
1078
|
-
prompt_file=prompt_file,
|
|
1079
|
-
code_file=code_file,
|
|
1080
|
-
program_file=program_file,
|
|
1081
|
-
output_results=output_results,
|
|
1082
|
-
output_code=output_code,
|
|
1083
|
-
output_program=output_program,
|
|
1084
|
-
loop=True,
|
|
1085
|
-
verification_program=program_file,
|
|
1086
|
-
max_attempts=max_attempts,
|
|
1087
|
-
budget=budget,
|
|
1088
|
-
)
|
|
1089
|
-
result_data = {
|
|
1090
|
-
"success": success,
|
|
1091
|
-
"attempts": attempts,
|
|
1092
|
-
"verified_code_path": output_code,
|
|
1093
|
-
"verified_program_path": output_program,
|
|
1094
|
-
"results_log_path": output_results,
|
|
1095
|
-
}
|
|
1096
|
-
return result_data, total_cost_value, model_name_value
|
|
1097
|
-
except Exception as e:
|
|
1098
|
-
handle_error(e, command_name, quiet)
|
|
1099
|
-
return None # Return None on failure
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
@cli.command("sync")
|
|
1103
|
-
@click.argument("basename", type=str)
|
|
1104
|
-
@click.option(
|
|
1105
|
-
"--max-attempts",
|
|
1106
|
-
type=int,
|
|
1107
|
-
default=3,
|
|
1108
|
-
show_default=True,
|
|
1109
|
-
help="Maximum number of sync attempts.",
|
|
1110
|
-
)
|
|
1111
|
-
@click.option(
|
|
1112
|
-
"--budget",
|
|
1113
|
-
type=float,
|
|
1114
|
-
default=10.0,
|
|
1115
|
-
show_default=True,
|
|
1116
|
-
help="Maximum total cost allowed for the entire sync process.",
|
|
1117
|
-
)
|
|
1118
|
-
@click.option(
|
|
1119
|
-
"--skip-verify",
|
|
1120
|
-
is_flag=True,
|
|
1121
|
-
default=False,
|
|
1122
|
-
help="Skip verification step during sync.",
|
|
1123
|
-
)
|
|
1124
|
-
@click.option(
|
|
1125
|
-
"--skip-tests",
|
|
1126
|
-
is_flag=True,
|
|
1127
|
-
default=False,
|
|
1128
|
-
help="Skip test generation during sync.",
|
|
1129
|
-
)
|
|
1130
|
-
@click.option(
|
|
1131
|
-
"--target-coverage",
|
|
1132
|
-
type=click.FloatRange(0.0, 100.0),
|
|
1133
|
-
default=10.0,
|
|
1134
|
-
show_default=True,
|
|
1135
|
-
help="Target code coverage percentage for generated tests.",
|
|
1136
|
-
)
|
|
1137
|
-
@click.option(
|
|
1138
|
-
"--log",
|
|
1139
|
-
is_flag=True,
|
|
1140
|
-
default=False,
|
|
1141
|
-
help="Enable detailed logging during sync.",
|
|
1142
|
-
)
|
|
1143
|
-
@click.pass_context
|
|
1144
|
-
@track_cost
|
|
1145
|
-
def sync(
|
|
1146
|
-
ctx: click.Context,
|
|
1147
|
-
basename: str,
|
|
1148
|
-
max_attempts: int,
|
|
1149
|
-
budget: float,
|
|
1150
|
-
skip_verify: bool,
|
|
1151
|
-
skip_tests: bool,
|
|
1152
|
-
target_coverage: float,
|
|
1153
|
-
log: bool,
|
|
1154
|
-
) -> Optional[Tuple[Dict[str, Any], float, str]]:
|
|
1155
|
-
"""Automatically execute the complete PDD workflow loop for a given basename.
|
|
1156
|
-
|
|
1157
|
-
This command implements the entire synchronized cycle, intelligently determining
|
|
1158
|
-
what steps are needed and executing them in the correct order. It detects
|
|
1159
|
-
programming languages by scanning for prompt files matching the pattern
|
|
1160
|
-
{basename}_{language}.prompt in the prompts directory.
|
|
1161
|
-
"""
|
|
1162
|
-
try:
|
|
1163
|
-
results, total_cost, model = sync_main(
|
|
1164
|
-
ctx=ctx,
|
|
1165
|
-
basename=basename,
|
|
1166
|
-
max_attempts=max_attempts,
|
|
1167
|
-
budget=budget,
|
|
1168
|
-
skip_verify=skip_verify,
|
|
1169
|
-
skip_tests=skip_tests,
|
|
1170
|
-
target_coverage=target_coverage,
|
|
1171
|
-
log=log,
|
|
1172
|
-
)
|
|
1173
|
-
return results, total_cost, model
|
|
1174
|
-
except Exception as exception:
|
|
1175
|
-
handle_error(exception, "sync", ctx.obj.get("quiet", False))
|
|
1176
|
-
return None
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
@cli.command("install_completion")
|
|
1180
|
-
@click.pass_context
|
|
1181
|
-
# No @track_cost
|
|
1182
|
-
def install_completion_cmd(ctx: click.Context) -> None: # Return type remains None
|
|
1183
|
-
"""Install shell completion for the PDD CLI."""
|
|
1184
|
-
command_name = "install_completion" # For error handling
|
|
1185
|
-
quiet_mode = ctx.obj.get("quiet", False) # Get quiet from context
|
|
1186
|
-
|
|
1187
|
-
try:
|
|
1188
|
-
# The actual install_completion function is imported from .install_completion
|
|
1189
|
-
install_completion(quiet=quiet_mode) # Pass quiet_mode
|
|
1190
|
-
# Success messages are handled within install_completion based on quiet_mode
|
|
1191
|
-
# No need to print additional messages here unless specifically required
|
|
1192
|
-
# if not quiet_mode:
|
|
1193
|
-
# console.print(f"[success]'{command_name}' command completed successfully.[/success]")
|
|
1194
|
-
except Exception as e:
|
|
1195
|
-
# Use the centralized error handler
|
|
1196
|
-
handle_error(e, command_name, quiet_mode)
|
|
1197
|
-
# Do not return anything, as the callback expects None or a tuple
|
|
1198
|
-
|
|
33
|
+
from .preprocess_main import preprocess_main
|
|
34
|
+
from .construct_paths import construct_paths
|
|
35
|
+
from .fix_verification_main import fix_verification_main
|
|
36
|
+
from .core.errors import console
|
|
37
|
+
from .install_completion import install_completion
|
|
38
|
+
from .core.utils import _should_show_onboarding_reminder
|
|
39
|
+
from .core.cli import process_commands
|
|
40
|
+
import subprocess
|
|
1199
41
|
|
|
1200
|
-
# --- Entry Point ---
|
|
1201
42
|
if __name__ == "__main__":
|
|
1202
43
|
cli()
|