pdd-cli 0.0.45__py3-none-any.whl → 0.0.90__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 +4 -4
- pdd/agentic_common.py +863 -0
- pdd/agentic_crash.py +534 -0
- pdd/agentic_fix.py +1179 -0
- pdd/agentic_langtest.py +162 -0
- pdd/agentic_update.py +370 -0
- pdd/agentic_verify.py +183 -0
- pdd/auto_deps_main.py +15 -5
- pdd/auto_include.py +63 -5
- pdd/bug_main.py +3 -2
- pdd/bug_to_unit_test.py +2 -0
- pdd/change_main.py +11 -4
- pdd/cli.py +22 -1181
- pdd/cmd_test_main.py +73 -21
- pdd/code_generator.py +58 -18
- pdd/code_generator_main.py +672 -25
- pdd/commands/__init__.py +42 -0
- pdd/commands/analysis.py +248 -0
- pdd/commands/fix.py +140 -0
- pdd/commands/generate.py +257 -0
- pdd/commands/maintenance.py +174 -0
- pdd/commands/misc.py +79 -0
- pdd/commands/modify.py +230 -0
- pdd/commands/report.py +144 -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 +258 -82
- pdd/context_generator.py +10 -2
- pdd/context_generator_main.py +113 -11
- pdd/continue_generation.py +47 -7
- pdd/core/__init__.py +0 -0
- pdd/core/cli.py +503 -0
- pdd/core/dump.py +554 -0
- pdd/core/errors.py +63 -0
- pdd/core/utils.py +90 -0
- pdd/crash_main.py +44 -11
- pdd/data/language_format.csv +71 -63
- pdd/data/llm_model.csv +20 -18
- pdd/detect_change_main.py +5 -4
- pdd/fix_code_loop.py +330 -76
- pdd/fix_error_loop.py +207 -61
- pdd/fix_errors_from_unit_tests.py +4 -3
- pdd/fix_main.py +75 -18
- pdd/fix_verification_errors.py +12 -100
- pdd/fix_verification_errors_loop.py +306 -272
- pdd/fix_verification_main.py +28 -9
- pdd/generate_output_paths.py +93 -10
- pdd/generate_test.py +16 -5
- pdd/get_jwt_token.py +9 -2
- pdd/get_run_command.py +73 -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 +11 -3
- pdd/llm_invoke.py +1269 -103
- pdd/load_prompt_template.py +36 -10
- pdd/pdd_completion.fish +25 -2
- pdd/pdd_completion.sh +30 -4
- pdd/pdd_completion.zsh +79 -4
- pdd/postprocess.py +10 -3
- pdd/preprocess.py +228 -15
- pdd/preprocess_main.py +8 -5
- pdd/prompts/agentic_crash_explore_LLM.prompt +49 -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 +1071 -0
- pdd/prompts/agentic_verify_explore_LLM.prompt +45 -0
- pdd/prompts/auto_include_LLM.prompt +100 -905
- pdd/prompts/detect_change_LLM.prompt +122 -20
- 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 +4 -2
- pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +8 -0
- pdd/prompts/fix_verification_errors_LLM.prompt +22 -0
- pdd/prompts/generate_test_LLM.prompt +21 -6
- pdd/prompts/increase_tests_LLM.prompt +1 -5
- pdd/prompts/insert_includes_LLM.prompt +228 -108
- 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/render_mermaid.py +236 -0
- pdd/setup_tool.py +648 -0
- pdd/simple_math.py +2 -0
- pdd/split_main.py +3 -2
- pdd/summarize_directory.py +49 -6
- pdd/sync_determine_operation.py +543 -98
- pdd/sync_main.py +81 -31
- pdd/sync_orchestration.py +1334 -751
- pdd/sync_tui.py +848 -0
- pdd/template_registry.py +264 -0
- pdd/templates/architecture/architecture_json.prompt +242 -0
- pdd/templates/generic/generate_prompt.prompt +174 -0
- pdd/trace.py +168 -12
- pdd/trace_main.py +4 -3
- pdd/track_cost.py +151 -61
- pdd/unfinished_prompt.py +49 -3
- pdd/update_main.py +549 -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.90.dist-info}/METADATA +19 -6
- pdd_cli-0.0.90.dist-info/RECORD +153 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.90.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.90.dist-info}/WHEEL +0 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.90.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.90.dist-info}/top_level.txt +0 -0
pdd/sync_main.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import time
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Any, Dict, List, Tuple
|
|
4
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
from rich.console import Console
|
|
@@ -79,12 +79,12 @@ def _detect_languages(basename: str, prompts_dir: Path) -> List[str]:
|
|
|
79
79
|
def sync_main(
|
|
80
80
|
ctx: click.Context,
|
|
81
81
|
basename: str,
|
|
82
|
-
max_attempts: int,
|
|
83
|
-
budget: float,
|
|
82
|
+
max_attempts: Optional[int],
|
|
83
|
+
budget: Optional[float],
|
|
84
84
|
skip_verify: bool,
|
|
85
85
|
skip_tests: bool,
|
|
86
86
|
target_coverage: float,
|
|
87
|
-
|
|
87
|
+
dry_run: bool,
|
|
88
88
|
) -> Tuple[Dict[str, Any], float, str]:
|
|
89
89
|
"""
|
|
90
90
|
CLI wrapper for the sync command. Handles parameter validation, path construction,
|
|
@@ -93,12 +93,12 @@ def sync_main(
|
|
|
93
93
|
Args:
|
|
94
94
|
ctx: The Click context object.
|
|
95
95
|
basename: The base name for the prompt file.
|
|
96
|
-
max_attempts: Maximum number of fix attempts.
|
|
97
|
-
budget: Maximum total cost for the sync process.
|
|
96
|
+
max_attempts: Maximum number of fix attempts. If None, uses .pddrc value or default (3).
|
|
97
|
+
budget: Maximum total cost for the sync process. If None, uses .pddrc value or default (20.0).
|
|
98
98
|
skip_verify: Skip the functional verification step.
|
|
99
99
|
skip_tests: Skip unit test generation and fixing.
|
|
100
100
|
target_coverage: Desired code coverage percentage.
|
|
101
|
-
|
|
101
|
+
dry_run: If True, analyze sync state without executing operations.
|
|
102
102
|
|
|
103
103
|
Returns:
|
|
104
104
|
A tuple containing the results dictionary, total cost, and primary model name.
|
|
@@ -118,15 +118,19 @@ def sync_main(
|
|
|
118
118
|
local = ctx.obj.get("local", False)
|
|
119
119
|
context_override = ctx.obj.get("context", None)
|
|
120
120
|
|
|
121
|
-
#
|
|
121
|
+
# Default values for max_attempts and budget when not specified via CLI or .pddrc
|
|
122
|
+
DEFAULT_MAX_ATTEMPTS = 3
|
|
123
|
+
DEFAULT_BUDGET = 20.0
|
|
124
|
+
|
|
125
|
+
# 2. Validate inputs (basename only - budget/max_attempts validated after config resolution)
|
|
122
126
|
_validate_basename(basename)
|
|
123
|
-
if budget <= 0:
|
|
124
|
-
raise click.BadParameter("Budget must be a positive number.", param_hint="--budget")
|
|
125
|
-
if max_attempts <= 0:
|
|
126
|
-
raise click.BadParameter("Max attempts must be a positive integer.", param_hint="--max-attempts")
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
# Validate CLI-specified values if provided (not None)
|
|
129
|
+
# Note: max_attempts=0 is valid (skips LLM loop, goes straight to agentic mode)
|
|
130
|
+
if budget is not None and budget <= 0:
|
|
131
|
+
raise click.BadParameter("Budget must be a positive number.", param_hint="--budget")
|
|
132
|
+
if max_attempts is not None and max_attempts < 0:
|
|
133
|
+
raise click.BadParameter("Max attempts must be a non-negative integer.", param_hint="--max-attempts")
|
|
130
134
|
|
|
131
135
|
# 3. Use construct_paths in 'discovery' mode to find the prompts directory.
|
|
132
136
|
try:
|
|
@@ -151,10 +155,10 @@ def sync_main(
|
|
|
151
155
|
f"Expected files with format: '{basename}_<language>.prompt'"
|
|
152
156
|
)
|
|
153
157
|
|
|
154
|
-
# 5. Handle --
|
|
155
|
-
if
|
|
158
|
+
# 5. Handle --dry-run mode separately
|
|
159
|
+
if dry_run:
|
|
156
160
|
if not quiet:
|
|
157
|
-
rprint(Panel(f"Displaying sync
|
|
161
|
+
rprint(Panel(f"Displaying sync analysis for [bold cyan]{basename}[/bold cyan]", title="PDD Sync Dry Run", expand=False))
|
|
158
162
|
|
|
159
163
|
for lang in languages:
|
|
160
164
|
if not quiet:
|
|
@@ -189,19 +193,27 @@ def sync_main(
|
|
|
189
193
|
code_dir=str(code_dir),
|
|
190
194
|
examples_dir=str(examples_dir),
|
|
191
195
|
tests_dir=str(tests_dir),
|
|
192
|
-
|
|
196
|
+
dry_run=True,
|
|
193
197
|
verbose=verbose,
|
|
194
198
|
quiet=quiet,
|
|
199
|
+
context_override=context_override,
|
|
195
200
|
)
|
|
196
201
|
return {}, 0.0, ""
|
|
197
202
|
|
|
198
203
|
# 6. Main Sync Workflow
|
|
204
|
+
# Determine display values for summary panel (use CLI values or defaults for display)
|
|
205
|
+
display_budget = budget if budget is not None else DEFAULT_BUDGET
|
|
206
|
+
display_max_attempts = max_attempts if max_attempts is not None else DEFAULT_MAX_ATTEMPTS
|
|
207
|
+
|
|
208
|
+
if not quiet and display_budget < 1.0:
|
|
209
|
+
console.log(f"[yellow]Warning:[/] Budget of ${display_budget:.2f} is low. Complex operations may exceed this limit.")
|
|
210
|
+
|
|
199
211
|
if not quiet:
|
|
200
212
|
summary_panel = Panel(
|
|
201
213
|
f"Basename: [bold cyan]{basename}[/bold cyan]\n"
|
|
202
214
|
f"Languages: [bold green]{', '.join(languages)}[/bold green]\n"
|
|
203
|
-
f"Budget: [bold yellow]${
|
|
204
|
-
f"Max Attempts: [bold blue]{
|
|
215
|
+
f"Budget: [bold yellow]${display_budget:.2f}[/bold yellow]\n"
|
|
216
|
+
f"Max Attempts: [bold blue]{display_max_attempts}[/bold blue]",
|
|
205
217
|
title="PDD Sync Starting",
|
|
206
218
|
expand=False,
|
|
207
219
|
)
|
|
@@ -211,13 +223,15 @@ def sync_main(
|
|
|
211
223
|
total_cost = 0.0
|
|
212
224
|
primary_model = ""
|
|
213
225
|
overall_success = True
|
|
214
|
-
remaining_budget
|
|
226
|
+
# remaining_budget will be set from resolved config on first language iteration
|
|
227
|
+
remaining_budget: Optional[float] = None
|
|
215
228
|
|
|
216
229
|
for lang in languages:
|
|
217
230
|
if not quiet:
|
|
218
231
|
rprint(f"\n[bold]🚀 Syncing for language: [green]{lang}[/green]...[/bold]")
|
|
219
232
|
|
|
220
|
-
|
|
233
|
+
# Check budget exhaustion (after first iteration when remaining_budget is set)
|
|
234
|
+
if remaining_budget is not None and remaining_budget <= 0:
|
|
221
235
|
if not quiet:
|
|
222
236
|
rprint(f"[yellow]Budget exhausted. Skipping sync for '{lang}'.[/yellow]")
|
|
223
237
|
overall_success = False
|
|
@@ -231,17 +245,25 @@ def sync_main(
|
|
|
231
245
|
command_options = {
|
|
232
246
|
"basename": basename,
|
|
233
247
|
"language": lang,
|
|
234
|
-
"max_attempts": max_attempts,
|
|
235
|
-
"budget": budget,
|
|
236
248
|
"target_coverage": target_coverage,
|
|
237
|
-
"strength": strength,
|
|
238
|
-
"temperature": temperature,
|
|
239
249
|
"time": time_param,
|
|
240
250
|
}
|
|
241
|
-
|
|
251
|
+
# Only pass values if explicitly set by user (not CLI defaults)
|
|
252
|
+
# This allows .pddrc values to take precedence when user doesn't pass CLI flags
|
|
253
|
+
if max_attempts is not None:
|
|
254
|
+
command_options["max_attempts"] = max_attempts
|
|
255
|
+
if budget is not None:
|
|
256
|
+
command_options["budget"] = budget
|
|
257
|
+
if strength != DEFAULT_STRENGTH:
|
|
258
|
+
command_options["strength"] = strength
|
|
259
|
+
if temperature != 0.0: # 0.0 is the CLI default for temperature
|
|
260
|
+
command_options["temperature"] = temperature
|
|
261
|
+
|
|
262
|
+
# Use force=True for path discovery - actual file writes happen in sync_orchestration
|
|
263
|
+
# which will handle confirmations via the TUI's confirm_callback
|
|
242
264
|
resolved_config, _, _, resolved_language = construct_paths(
|
|
243
265
|
input_file_paths={"prompt_file": str(prompt_file_path)},
|
|
244
|
-
force=force
|
|
266
|
+
force=True, # Always force during path discovery
|
|
245
267
|
quiet=True,
|
|
246
268
|
command="sync",
|
|
247
269
|
command_options=command_options,
|
|
@@ -249,11 +271,38 @@ def sync_main(
|
|
|
249
271
|
)
|
|
250
272
|
|
|
251
273
|
# Extract all parameters directly from the resolved configuration
|
|
274
|
+
# Priority: CLI value > .pddrc value > hardcoded default
|
|
252
275
|
final_strength = resolved_config.get("strength", strength)
|
|
253
276
|
final_temp = resolved_config.get("temperature", temperature)
|
|
254
|
-
final_max_attempts = resolved_config.get("max_attempts", max_attempts)
|
|
255
277
|
final_target_coverage = resolved_config.get("target_coverage", target_coverage)
|
|
256
|
-
|
|
278
|
+
|
|
279
|
+
# For max_attempts and budget: CLI > .pddrc > hardcoded default
|
|
280
|
+
# If CLI value is provided (not None), use it. Otherwise, use .pddrc or default.
|
|
281
|
+
if max_attempts is not None:
|
|
282
|
+
final_max_attempts = max_attempts
|
|
283
|
+
else:
|
|
284
|
+
final_max_attempts = resolved_config.get("max_attempts") or DEFAULT_MAX_ATTEMPTS
|
|
285
|
+
|
|
286
|
+
if budget is not None:
|
|
287
|
+
final_budget = budget
|
|
288
|
+
else:
|
|
289
|
+
final_budget = resolved_config.get("budget") or DEFAULT_BUDGET
|
|
290
|
+
|
|
291
|
+
# Validate the resolved values
|
|
292
|
+
# Note: max_attempts=0 is valid (skips LLM loop, goes straight to agentic mode)
|
|
293
|
+
if final_budget <= 0:
|
|
294
|
+
raise click.BadParameter("Budget must be a positive number.", param_hint="--budget")
|
|
295
|
+
if final_max_attempts < 0:
|
|
296
|
+
raise click.BadParameter("Max attempts must be a non-negative integer.", param_hint="--max-attempts")
|
|
297
|
+
|
|
298
|
+
# Initialize remaining_budget from first resolved config if not set yet
|
|
299
|
+
if remaining_budget is None:
|
|
300
|
+
remaining_budget = final_budget
|
|
301
|
+
|
|
302
|
+
# Update ctx.obj with resolved values so sub-commands inherit them
|
|
303
|
+
ctx.obj["strength"] = final_strength
|
|
304
|
+
ctx.obj["temperature"] = final_temp
|
|
305
|
+
|
|
257
306
|
code_dir = resolved_config.get("code_dir", "src")
|
|
258
307
|
tests_dir = resolved_config.get("tests_dir", "tests")
|
|
259
308
|
examples_dir = resolved_config.get("examples_dir", "examples")
|
|
@@ -280,6 +329,7 @@ def sync_main(
|
|
|
280
329
|
review_examples=review_examples,
|
|
281
330
|
local=local,
|
|
282
331
|
context_config=resolved_config,
|
|
332
|
+
context_override=context_override,
|
|
283
333
|
)
|
|
284
334
|
|
|
285
335
|
lang_cost = sync_result.get("total_cost", 0.0)
|
|
@@ -330,4 +380,4 @@ def sync_main(
|
|
|
330
380
|
aggregated_results["total_cost"] = total_cost
|
|
331
381
|
aggregated_results["primary_model"] = primary_model
|
|
332
382
|
|
|
333
|
-
return aggregated_results, total_cost, primary_model
|
|
383
|
+
return aggregated_results, total_cost, primary_model
|