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/load_prompt_template.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
import os
|
|
3
2
|
from typing import Optional
|
|
4
|
-
import sys
|
|
5
3
|
from rich import print
|
|
4
|
+
from pdd.path_resolution import get_default_resolver
|
|
6
5
|
|
|
7
6
|
def print_formatted(message: str) -> None:
|
|
8
7
|
"""Print message with raw formatting tags for testing compatibility."""
|
|
@@ -23,18 +22,26 @@ def load_prompt_template(prompt_name: str) -> Optional[str]:
|
|
|
23
22
|
print_formatted("[red]Unexpected error loading prompt template[/red]")
|
|
24
23
|
return None
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
resolver = get_default_resolver()
|
|
26
|
+
prompt_path = resolver.resolve_prompt_template(prompt_name)
|
|
27
|
+
|
|
28
|
+
if prompt_path is None:
|
|
29
|
+
candidate_roots = []
|
|
30
|
+
if resolver.pdd_path_env is not None:
|
|
31
|
+
candidate_roots.append(resolver.pdd_path_env)
|
|
32
|
+
if resolver.repo_root is not None:
|
|
33
|
+
candidate_roots.append(resolver.repo_root)
|
|
34
|
+
candidate_roots.append(resolver.cwd)
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
prompt_candidates = []
|
|
37
|
+
for root in candidate_roots:
|
|
38
|
+
prompt_candidates.append(root / 'prompts' / f"{prompt_name}.prompt")
|
|
39
|
+
prompt_candidates.append(root / 'pdd' / 'prompts' / f"{prompt_name}.prompt")
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
tried = "\n".join(str(c) for c in prompt_candidates)
|
|
42
|
+
print_formatted(
|
|
43
|
+
f"[red]Prompt file not found in any candidate locations for '{prompt_name}'. Tried:\n{tried}[/red]"
|
|
44
|
+
)
|
|
38
45
|
return None
|
|
39
46
|
|
|
40
47
|
try:
|
pdd/path_resolution.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Literal, Optional
|
|
7
|
+
|
|
8
|
+
IncludeProfile = Literal["cwd_then_package_then_repo"]
|
|
9
|
+
PromptProfile = Literal["pdd_path_then_repo_then_cwd"]
|
|
10
|
+
DataProfile = Literal["pdd_path_only"]
|
|
11
|
+
ProjectRootProfile = Literal["pdd_path_then_marker_then_cwd"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class PathResolver:
|
|
16
|
+
cwd: Path
|
|
17
|
+
pdd_path_env: Optional[Path]
|
|
18
|
+
package_root: Path
|
|
19
|
+
repo_root: Optional[Path]
|
|
20
|
+
|
|
21
|
+
def resolve_include(self, rel: str, profile: IncludeProfile = "cwd_then_package_then_repo") -> Path:
|
|
22
|
+
if profile != "cwd_then_package_then_repo":
|
|
23
|
+
raise ValueError(f"Unsupported include profile: {profile}")
|
|
24
|
+
|
|
25
|
+
cwd_path = self.cwd / rel
|
|
26
|
+
if cwd_path.exists():
|
|
27
|
+
return cwd_path
|
|
28
|
+
|
|
29
|
+
pkg_path = self.package_root / rel
|
|
30
|
+
if pkg_path.exists():
|
|
31
|
+
return pkg_path
|
|
32
|
+
|
|
33
|
+
if self.repo_root is not None:
|
|
34
|
+
repo_path = self.repo_root / rel
|
|
35
|
+
if repo_path.exists():
|
|
36
|
+
return repo_path
|
|
37
|
+
|
|
38
|
+
return cwd_path
|
|
39
|
+
|
|
40
|
+
def resolve_prompt_template(
|
|
41
|
+
self,
|
|
42
|
+
name: str,
|
|
43
|
+
profile: PromptProfile = "pdd_path_then_repo_then_cwd",
|
|
44
|
+
) -> Optional[Path]:
|
|
45
|
+
if profile != "pdd_path_then_repo_then_cwd":
|
|
46
|
+
raise ValueError(f"Unsupported prompt profile: {profile}")
|
|
47
|
+
|
|
48
|
+
roots = []
|
|
49
|
+
if self.pdd_path_env is not None:
|
|
50
|
+
roots.append(self.pdd_path_env)
|
|
51
|
+
if self.repo_root is not None:
|
|
52
|
+
roots.append(self.repo_root)
|
|
53
|
+
roots.append(self.cwd)
|
|
54
|
+
|
|
55
|
+
prompt_file = f"{name}.prompt"
|
|
56
|
+
for root in roots:
|
|
57
|
+
candidate = root / "prompts" / prompt_file
|
|
58
|
+
if candidate.exists():
|
|
59
|
+
return candidate
|
|
60
|
+
candidate = root / "pdd" / "prompts" / prompt_file
|
|
61
|
+
if candidate.exists():
|
|
62
|
+
return candidate
|
|
63
|
+
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
def resolve_data_file(self, rel: str, profile: DataProfile = "pdd_path_only") -> Path:
|
|
67
|
+
if profile != "pdd_path_only":
|
|
68
|
+
raise ValueError(f"Unsupported data profile: {profile}")
|
|
69
|
+
if self.pdd_path_env is None:
|
|
70
|
+
raise ValueError("PDD_PATH environment variable is not set.")
|
|
71
|
+
return self.pdd_path_env / rel
|
|
72
|
+
|
|
73
|
+
def resolve_project_root(
|
|
74
|
+
self,
|
|
75
|
+
profile: ProjectRootProfile = "pdd_path_then_marker_then_cwd",
|
|
76
|
+
max_levels: int = 5,
|
|
77
|
+
) -> Path:
|
|
78
|
+
if profile != "pdd_path_then_marker_then_cwd":
|
|
79
|
+
raise ValueError(f"Unsupported project root profile: {profile}")
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
self.pdd_path_env is not None
|
|
83
|
+
and self.pdd_path_env.is_dir()
|
|
84
|
+
and not _is_within(self.pdd_path_env, self.package_root)
|
|
85
|
+
):
|
|
86
|
+
return self.pdd_path_env
|
|
87
|
+
|
|
88
|
+
current = self.cwd
|
|
89
|
+
for _ in range(max_levels):
|
|
90
|
+
if _has_project_marker(current):
|
|
91
|
+
return current
|
|
92
|
+
parent = current.parent
|
|
93
|
+
if parent == current:
|
|
94
|
+
break
|
|
95
|
+
current = parent
|
|
96
|
+
|
|
97
|
+
return self.cwd
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_default_resolver() -> PathResolver:
|
|
101
|
+
cwd = Path.cwd().resolve()
|
|
102
|
+
|
|
103
|
+
pdd_path_env = None
|
|
104
|
+
env_value = os.getenv("PDD_PATH")
|
|
105
|
+
if env_value:
|
|
106
|
+
pdd_path_env = Path(env_value).expanduser().resolve()
|
|
107
|
+
|
|
108
|
+
package_root = Path(__file__).resolve().parent
|
|
109
|
+
repo_root = package_root.parent
|
|
110
|
+
|
|
111
|
+
return PathResolver(
|
|
112
|
+
cwd=cwd,
|
|
113
|
+
pdd_path_env=pdd_path_env,
|
|
114
|
+
package_root=package_root,
|
|
115
|
+
repo_root=repo_root,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _has_project_marker(path: Path) -> bool:
|
|
120
|
+
return (
|
|
121
|
+
(path / ".git").exists()
|
|
122
|
+
or (path / "pyproject.toml").exists()
|
|
123
|
+
or (path / "data").is_dir()
|
|
124
|
+
or (path / ".env").exists()
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _is_within(path: Path, parent: Path) -> bool:
|
|
129
|
+
try:
|
|
130
|
+
resolved_path = path.resolve()
|
|
131
|
+
resolved_parent = parent.resolve()
|
|
132
|
+
except Exception:
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
if resolved_path == resolved_parent:
|
|
136
|
+
return True
|
|
137
|
+
parent_str = str(resolved_parent)
|
|
138
|
+
if not parent_str.endswith(os.sep):
|
|
139
|
+
parent_str = parent_str + os.sep
|
|
140
|
+
return str(resolved_path).startswith(parent_str)
|
pdd/pdd_completion.fish
CHANGED
|
@@ -10,6 +10,8 @@ complete -c pdd -n "__fish_use_subcommand" -l quiet -d "Decrease output verbosit
|
|
|
10
10
|
complete -c pdd -n "__fish_use_subcommand" -l output-cost -r -d "Enable cost tracking and output CSV file"
|
|
11
11
|
complete -c pdd -n "__fish_use_subcommand" -l review-examples -d "Review few-shot examples before execution"
|
|
12
12
|
complete -c pdd -n "__fish_use_subcommand" -l local -d "Run commands locally"
|
|
13
|
+
complete -c pdd -n "__fish_use_subcommand" -l context -r -d "Override .pddrc context"
|
|
14
|
+
complete -c pdd -n "__fish_use_subcommand" -l list-contexts -d ".pddrc contexts and exit"
|
|
13
15
|
complete -c pdd -n "__fish_use_subcommand" -l help -d "Show help message"
|
|
14
16
|
complete -c pdd -n "__fish_use_subcommand" -l version -d "Show version information"
|
|
15
17
|
|
|
@@ -27,13 +29,18 @@ complete -c pdd -n "__fish_use_subcommand" -a conflicts -d "Analyze conflicts be
|
|
|
27
29
|
complete -c pdd -n "__fish_use_subcommand" -a crash -d "Fix code causing program crash"
|
|
28
30
|
complete -c pdd -n "__fish_use_subcommand" -a trace -d "Trace code line to prompt"
|
|
29
31
|
complete -c pdd -n "__fish_use_subcommand" -a bug -d "Generate unit test from bug report"
|
|
30
|
-
complete -c pdd -n "__fish_use_subcommand" -a auto-deps -d "Analyze and insert dependencies"
|
|
32
|
+
complete -c pdd -n "__fish_use_subcommand" -a auto-deps -d "Analyze and insert dependencies from directory or glob"
|
|
31
33
|
complete -c pdd -n "__fish_use_subcommand" -a verify -d "Verify functional correctness using LLM judgment"
|
|
34
|
+
complete -c pdd -n "__fish_use_subcommand" -a sync -d "Synchronize prompt, code, examples, tests"
|
|
35
|
+
complete -c pdd -n "__fish_use_subcommand" -a setup -d "Interactive setup and completion install"
|
|
36
|
+
complete -c pdd -n "__fish_use_subcommand" -a install_completion -d "Install shell completion"
|
|
37
|
+
complete -c pdd -n "__fish_use_subcommand" -a pytest-output -d "Run pytest and capture structured output"
|
|
32
38
|
|
|
33
39
|
# Command-specific completions
|
|
34
40
|
complete -c pdd -n "__fish_seen_subcommand_from generate" -l output -r -d "Output location for generated code"
|
|
35
41
|
complete -c pdd -n "__fish_seen_subcommand_from generate" -l original-prompt -r -d "Original prompt file for incremental generation"
|
|
36
42
|
complete -c pdd -n "__fish_seen_subcommand_from generate" -l incremental -d "Force incremental patching"
|
|
43
|
+
complete -c pdd -n "__fish_seen_subcommand_from generate" -s e -l env -xa "(env | cut -d= -f1 | sed 's/.*/&=/' | sort -u)" -d "Set template variable (KEY=VALUE) or read KEY from env"
|
|
37
44
|
complete -c pdd -n "__fish_seen_subcommand_from generate" -a "(__fish_complete_suffix .prompt)"
|
|
38
45
|
|
|
39
46
|
complete -c pdd -n "__fish_seen_subcommand_from example" -l output -r -d "Output location for example code"
|
|
@@ -125,10 +132,26 @@ complete -c pdd -n "__fish_seen_subcommand_from verify" -l budget -x -d "Max bud
|
|
|
125
132
|
complete -c pdd -n "__fish_seen_subcommand_from verify" -a "(__fish_complete_suffix .prompt)"
|
|
126
133
|
complete -c pdd -n "__fish_seen_subcommand_from verify" -a "(__fish_complete_suffix .py .js .java .cpp .rb .go)" # For CODE_FILE and PROGRAM_FILE
|
|
127
134
|
|
|
135
|
+
# sync command
|
|
136
|
+
complete -c pdd -n "__fish_seen_subcommand_from sync" -l max-attempts -x -d "Max attempts for loops"
|
|
137
|
+
complete -c pdd -n "__fish_seen_subcommand_from sync" -l budget -x -d "Total budget for sync"
|
|
138
|
+
complete -c pdd -n "__fish_seen_subcommand_from sync" -l skip-verify -d "Skip functional verification"
|
|
139
|
+
complete -c pdd -n "__fish_seen_subcommand_from sync" -l skip-tests -d "Skip unit test generation"
|
|
140
|
+
complete -c pdd -n "__fish_seen_subcommand_from sync" -l target-coverage -x -d "Desired coverage percentage"
|
|
141
|
+
complete -c pdd -n "__fish_seen_subcommand_from sync" -l log -d "Show analysis instead of running"
|
|
142
|
+
|
|
143
|
+
# setup and install_completion have no options
|
|
144
|
+
complete -c pdd -n "__fish_seen_subcommand_from setup" -d "Run interactive setup"
|
|
145
|
+
complete -c pdd -n "__fish_seen_subcommand_from install_completion" -d "Install shell completion"
|
|
146
|
+
|
|
147
|
+
# pytest-output command
|
|
148
|
+
complete -c pdd -n "__fish_seen_subcommand_from pytest-output" -l json-only -d "Print only JSON"
|
|
149
|
+
complete -c pdd -n "__fish_seen_subcommand_from pytest-output" -a "(__fish_complete_suffix .py)"
|
|
150
|
+
|
|
128
151
|
# File completion for all commands
|
|
129
152
|
complete -c pdd -n "__fish_seen_subcommand_from generate example test preprocess fix split change update detect conflicts crash trace bug auto-deps verify" -a "(__fish_complete_suffix .prompt)"
|
|
130
153
|
complete -c pdd -n "__fish_seen_subcommand_from generate example test preprocess fix split change update detect conflicts crash trace bug auto-deps verify" -a "(__fish_complete_suffix .py .js .java .cpp .rb .go)"
|
|
131
154
|
complete -c pdd -n "__fish_seen_subcommand_from generate example test preprocess fix split change update detect conflicts crash trace bug auto-deps verify" -a "(__fish_complete_suffix .log .txt .csv)"
|
|
132
155
|
|
|
133
156
|
# Help completion
|
|
134
|
-
complete -c pdd -n "__fish_seen_subcommand_from help" -a "generate example test preprocess fix split change update detect conflicts crash trace bug auto-deps verify" -d "Show help for specific command"
|
|
157
|
+
complete -c pdd -n "__fish_seen_subcommand_from help" -a "generate example test preprocess fix split change update detect conflicts crash trace bug auto-deps verify sync setup install_completion pytest-output" -d "Show help for specific command"
|
pdd/pdd_completion.sh
CHANGED
|
@@ -15,13 +15,13 @@ _pdd() {
|
|
|
15
15
|
cword=$COMP_CWORD
|
|
16
16
|
|
|
17
17
|
# Global options
|
|
18
|
-
local global_opts="--force --strength --time --temperature --verbose --quiet --output-cost --review-examples --local --help --version"
|
|
18
|
+
local global_opts="--force --strength --time --temperature --verbose --quiet --output-cost --review-examples --local --context --list-contexts --help --version"
|
|
19
19
|
|
|
20
20
|
# Commands
|
|
21
|
-
local commands="generate example test preprocess fix split change update detect conflicts crash trace bug auto-deps verify"
|
|
21
|
+
local commands="generate example test preprocess fix split change update detect conflicts crash trace bug auto-deps verify sync setup install_completion pytest-output"
|
|
22
22
|
|
|
23
23
|
# Command-specific options
|
|
24
|
-
local generate_opts="--output --original-prompt --incremental"
|
|
24
|
+
local generate_opts="--output --original-prompt --incremental --env -e"
|
|
25
25
|
local example_opts="--output"
|
|
26
26
|
local test_opts="--output --language --coverage-report --existing-tests --target-coverage --merge"
|
|
27
27
|
local preprocess_opts="--output --xml --recursive --double --exclude"
|
|
@@ -36,6 +36,8 @@ _pdd() {
|
|
|
36
36
|
local bug_opts="--output --language"
|
|
37
37
|
local auto_deps_opts="--output --csv --force-scan"
|
|
38
38
|
local verify_opts="--output-results --output-code --output-program --max-attempts --budget"
|
|
39
|
+
local sync_opts="--max-attempts --budget --skip-verify --skip-tests --target-coverage --log"
|
|
40
|
+
local pytest_output_opts="--json-only"
|
|
39
41
|
|
|
40
42
|
# Complete global options before command
|
|
41
43
|
if [[ $cword -eq 1 ]]; then
|
|
@@ -46,6 +48,16 @@ _pdd() {
|
|
|
46
48
|
# Complete command-specific options
|
|
47
49
|
case ${words[1]} in
|
|
48
50
|
generate)
|
|
51
|
+
# If completing the value for -e/--env, suggest environment variable names (with and without '=')
|
|
52
|
+
if [[ $prev == "-e" || $prev == "--env" ]]; then
|
|
53
|
+
local vars
|
|
54
|
+
vars=$(env | cut -d= -f1 | sort -u)
|
|
55
|
+
# Offer both KEY and KEY=
|
|
56
|
+
local vars_with_eq
|
|
57
|
+
vars_with_eq=$(printf '%s=\n' $vars)
|
|
58
|
+
COMPREPLY=($(compgen -W "$vars $vars_with_eq" -- "$cur"))
|
|
59
|
+
return
|
|
60
|
+
fi
|
|
49
61
|
_complete_files ".prompt"
|
|
50
62
|
COMPREPLY+=($(compgen -W "$generate_opts" -- "$cur"))
|
|
51
63
|
;;
|
|
@@ -131,6 +143,20 @@ _pdd() {
|
|
|
131
143
|
_complete_files
|
|
132
144
|
COMPREPLY+=($(compgen -W "$verify_opts" -- "$cur"))
|
|
133
145
|
;;
|
|
146
|
+
sync)
|
|
147
|
+
# BASENAME (not a file), offer options
|
|
148
|
+
COMPREPLY+=($(compgen -W "$sync_opts" -- "$cur"))
|
|
149
|
+
;;
|
|
150
|
+
setup)
|
|
151
|
+
# no command-specific options
|
|
152
|
+
;;
|
|
153
|
+
install_completion)
|
|
154
|
+
# no command-specific options
|
|
155
|
+
;;
|
|
156
|
+
pytest-output)
|
|
157
|
+
_complete_files
|
|
158
|
+
COMPREPLY+=($(compgen -W "$pytest_output_opts" -- "$cur"))
|
|
159
|
+
;;
|
|
134
160
|
*)
|
|
135
161
|
COMPREPLY=($(compgen -W "$global_opts" -- "$cur"))
|
|
136
162
|
;;
|
|
@@ -157,4 +183,4 @@ _complete_files() {
|
|
|
157
183
|
fi
|
|
158
184
|
}
|
|
159
185
|
|
|
160
|
-
complete -F _pdd pdd
|
|
186
|
+
complete -F _pdd pdd
|
pdd/pdd_completion.zsh
CHANGED
|
@@ -57,6 +57,8 @@ _pdd_global_opts=(
|
|
|
57
57
|
'--output-cost[Enable cost tracking and output a CSV file with usage details.]:filename:_files'
|
|
58
58
|
'--review-examples[Review and optionally exclude few-shot examples before command execution.]'
|
|
59
59
|
'--local[Run commands locally instead of in the cloud.]'
|
|
60
|
+
'--context[Override automatic .pddrc context]:context-name:_guard'
|
|
61
|
+
'--list-contexts[List available .pddrc contexts and exit]'
|
|
60
62
|
'--help[Show help message and exit.]'
|
|
61
63
|
'--version[Show version and exit.]'
|
|
62
64
|
)
|
|
@@ -65,6 +67,14 @@ _pdd_global_opts=(
|
|
|
65
67
|
# Per-subcommand completion functions
|
|
66
68
|
##
|
|
67
69
|
|
|
70
|
+
# Helper: suggest environment variables (KEY and KEY=)
|
|
71
|
+
_pdd_env_vars() {
|
|
72
|
+
local -a envs envs_eq
|
|
73
|
+
envs=(${(f)"$(env | cut -d= -f1 | sort -u)"})
|
|
74
|
+
envs_eq=(${envs/%/=})
|
|
75
|
+
_describe -t envvars 'environment variables' envs_eq envs
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
# generate
|
|
69
79
|
# Usage: pdd [GLOBAL OPTIONS] generate [OPTIONS] PROMPT_FILE
|
|
70
80
|
# Options:
|
|
@@ -77,6 +87,7 @@ _pdd_generate() {
|
|
|
77
87
|
'--output=[Specify where to save the generated code.]:filename:_files' \
|
|
78
88
|
'--original-prompt=[The original prompt file used to generate existing code.]:filename:_files' \
|
|
79
89
|
'--incremental[Force incremental patching even if changes are significant.]' \
|
|
90
|
+
'(-e --env)'{-e,--env}'[Set template variable (KEY=VALUE) or read KEY from env]:template variable:_pdd_env_vars' \
|
|
80
91
|
'1:prompt-file:_files' \
|
|
81
92
|
'*:filename:_files'
|
|
82
93
|
}
|
|
@@ -349,7 +360,7 @@ _pdd_bug() {
|
|
|
349
360
|
# --force-scan
|
|
350
361
|
# Args:
|
|
351
362
|
# 1: PROMPT_FILE
|
|
352
|
-
# 2: DIRECTORY_PATH
|
|
363
|
+
# 2: DIRECTORY_PATH (directory or glob pattern)
|
|
353
364
|
_pdd_auto_deps() {
|
|
354
365
|
_arguments -s \
|
|
355
366
|
$_pdd_global_opts \
|
|
@@ -357,7 +368,7 @@ _pdd_auto_deps() {
|
|
|
357
368
|
'--csv=[CSV file for dependency info (default: project_dependencies.csv).]:filename:_files' \
|
|
358
369
|
'--force-scan[Force rescanning of all potential dependency files.]' \
|
|
359
370
|
'1:prompt-file:_files' \
|
|
360
|
-
'2:directory:_files -/' \
|
|
371
|
+
'2:directory-or-glob:_files -/' \
|
|
361
372
|
'*:filename:_files'
|
|
362
373
|
}
|
|
363
374
|
|
|
@@ -387,6 +398,54 @@ _pdd_verify() {
|
|
|
387
398
|
'*:filename:_files'
|
|
388
399
|
}
|
|
389
400
|
|
|
401
|
+
# sync
|
|
402
|
+
# Usage: pdd [GLOBAL OPTIONS] sync [OPTIONS] BASENAME
|
|
403
|
+
# Options:
|
|
404
|
+
# --max-attempts [INT]
|
|
405
|
+
# --budget [FLOAT]
|
|
406
|
+
# --skip-verify
|
|
407
|
+
# --skip-tests
|
|
408
|
+
# --target-coverage [FLOAT]
|
|
409
|
+
# --log
|
|
410
|
+
# Arg:
|
|
411
|
+
# 1: BASENAME
|
|
412
|
+
_pdd_sync() {
|
|
413
|
+
_arguments -s \
|
|
414
|
+
$_pdd_global_opts \
|
|
415
|
+
'--max-attempts=[Maximum attempts for iterative loops (default 3)]:int' \
|
|
416
|
+
'--budget=[Maximum total cost for sync (default 10.0)]:float' \
|
|
417
|
+
'--skip-verify[Skip the functional verification step]' \
|
|
418
|
+
'--skip-tests[Skip unit test generation and fixing]' \
|
|
419
|
+
'--target-coverage=[Desired code coverage percentage]:float' \
|
|
420
|
+
'--log[Show analysis instead of executing operations]' \
|
|
421
|
+
'1:basename: ' \
|
|
422
|
+
'*: :'
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
# setup (no options)
|
|
426
|
+
_pdd_setup() {
|
|
427
|
+
_arguments -s $_pdd_global_opts
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
# install_completion (no options)
|
|
431
|
+
_pdd_install_completion() {
|
|
432
|
+
_arguments -s $_pdd_global_opts
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
# pytest-output
|
|
436
|
+
# Usage: pdd [GLOBAL OPTIONS] pytest-output [OPTIONS] TEST_FILE
|
|
437
|
+
# Options:
|
|
438
|
+
# --json-only
|
|
439
|
+
# Arg:
|
|
440
|
+
# 1: TEST_FILE
|
|
441
|
+
_pdd_pytest_output() {
|
|
442
|
+
_arguments -s \
|
|
443
|
+
$_pdd_global_opts \
|
|
444
|
+
'--json-only[Print only JSON to stdout]' \
|
|
445
|
+
'1:test-file:_files' \
|
|
446
|
+
'*:filename:_files'
|
|
447
|
+
}
|
|
448
|
+
|
|
390
449
|
##
|
|
391
450
|
# Main PDD completion dispatcher
|
|
392
451
|
##
|
|
@@ -410,8 +469,12 @@ _pdd() {
|
|
|
410
469
|
'crash:Fix errors in a code module and its calling program'
|
|
411
470
|
'trace:Find the prompt file line number associated with a code line'
|
|
412
471
|
'bug:Generate a unit test based on incorrect vs desired outputs'
|
|
413
|
-
'auto-deps:Analyze a prompt
|
|
472
|
+
'auto-deps:Analyze a prompt and include deps from a directory or glob'
|
|
414
473
|
'verify:Verify functional correctness using LLM judgment and iteratively fix'
|
|
474
|
+
'sync:Synchronize prompt, code, examples, tests with analysis'
|
|
475
|
+
'setup:Interactive setup and completion install'
|
|
476
|
+
'install_completion:Install shell completion for current shell'
|
|
477
|
+
'pytest-output:Run pytest and capture structured output'
|
|
415
478
|
)
|
|
416
479
|
|
|
417
480
|
# If there's no subcommand yet (i.e., user typed only "pdd " or "pdd -<Tab>"), offer global opts or subcommands.
|
|
@@ -471,6 +534,18 @@ _pdd() {
|
|
|
471
534
|
verify)
|
|
472
535
|
_pdd_verify
|
|
473
536
|
;;
|
|
537
|
+
sync)
|
|
538
|
+
_pdd_sync
|
|
539
|
+
;;
|
|
540
|
+
setup)
|
|
541
|
+
_pdd_setup
|
|
542
|
+
;;
|
|
543
|
+
install_completion)
|
|
544
|
+
_pdd_install_completion
|
|
545
|
+
;;
|
|
546
|
+
pytest-output)
|
|
547
|
+
_pdd_pytest_output
|
|
548
|
+
;;
|
|
474
549
|
# If the subcommand is unknown or not typed yet, fall back to showing the list of subcommands.
|
|
475
550
|
*)
|
|
476
551
|
_describe -t subcommands 'pdd subcommand' _pdd_subcommands
|
|
@@ -487,4 +562,4 @@ else
|
|
|
487
562
|
echo >&2 "Warning: Could not register pdd completion. Make sure ZSH completion system is working."
|
|
488
563
|
fi
|
|
489
564
|
|
|
490
|
-
# End of pdd_completion.zsh
|
|
565
|
+
# End of pdd_completion.zsh
|
pdd/postprocess.py
CHANGED
|
@@ -3,10 +3,12 @@ from rich import print
|
|
|
3
3
|
from pydantic import BaseModel, Field
|
|
4
4
|
from .load_prompt_template import load_prompt_template
|
|
5
5
|
from .llm_invoke import llm_invoke
|
|
6
|
-
from . import DEFAULT_TIME
|
|
6
|
+
from . import DEFAULT_TIME, DEFAULT_STRENGTH
|
|
7
7
|
|
|
8
8
|
class ExtractedCode(BaseModel):
|
|
9
9
|
"""Pydantic model for the extracted code."""
|
|
10
|
+
focus: str = Field(default="", description="The focus of the generation")
|
|
11
|
+
explanation: str = Field(default="", description="Explanation of the extraction")
|
|
10
12
|
extracted_code: str = Field(description="The extracted code from the LLM output")
|
|
11
13
|
|
|
12
14
|
def postprocess_0(text: str) -> str:
|
|
@@ -36,7 +38,7 @@ def postprocess_0(text: str) -> str:
|
|
|
36
38
|
def postprocess(
|
|
37
39
|
llm_output: str,
|
|
38
40
|
language: str,
|
|
39
|
-
strength: float =
|
|
41
|
+
strength: float = DEFAULT_STRENGTH,
|
|
40
42
|
temperature: float = 0,
|
|
41
43
|
time: float = DEFAULT_TIME,
|
|
42
44
|
verbose: bool = False
|
|
@@ -93,13 +95,21 @@ def postprocess(
|
|
|
93
95
|
temperature=temperature,
|
|
94
96
|
time=time,
|
|
95
97
|
verbose=verbose,
|
|
96
|
-
output_pydantic=ExtractedCode
|
|
98
|
+
output_pydantic=ExtractedCode,
|
|
99
|
+
language=language,
|
|
97
100
|
)
|
|
98
101
|
|
|
99
102
|
if not response or 'result' not in response:
|
|
100
103
|
raise ValueError("Failed to get valid response from LLM")
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
result_obj = response['result']
|
|
106
|
+
if not isinstance(result_obj, ExtractedCode):
|
|
107
|
+
# If we got a string (likely an error message from llm_invoke), fallback to simple extraction
|
|
108
|
+
if verbose:
|
|
109
|
+
print(f"[yellow]Structured extraction failed ({result_obj}). Falling back to simple extraction.[/yellow]")
|
|
110
|
+
return (postprocess_0(llm_output), response.get('cost', 0.0), response.get('model_name', 'fallback'))
|
|
111
|
+
|
|
112
|
+
extracted_code_obj: ExtractedCode = result_obj
|
|
103
113
|
code_text = extracted_code_obj.extracted_code
|
|
104
114
|
|
|
105
115
|
# Step 3c: Remove triple backticks and language identifier if present
|