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/agentic_change.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import List, Tuple, Optional, Any
|
|
10
|
+
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
|
|
13
|
+
# Internal imports
|
|
14
|
+
from .agentic_change_orchestrator import run_agentic_change_orchestrator
|
|
15
|
+
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _check_gh_cli() -> bool:
|
|
20
|
+
"""
|
|
21
|
+
Check if the GitHub CLI (gh) is installed and available in the system PATH.
|
|
22
|
+
"""
|
|
23
|
+
return shutil.which("gh") is not None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _parse_issue_url(url: str) -> Optional[Tuple[str, str, int]]:
|
|
27
|
+
"""
|
|
28
|
+
Parse a GitHub issue URL to extract the owner, repository name, and issue number.
|
|
29
|
+
|
|
30
|
+
Supported formats:
|
|
31
|
+
- https://github.com/{owner}/{repo}/issues/{number}
|
|
32
|
+
- https://www.github.com/{owner}/{repo}/issues/{number}
|
|
33
|
+
- github.com/{owner}/{repo}/issues/{number}
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Tuple of (owner, repo, issue_number) if successful, else None.
|
|
37
|
+
"""
|
|
38
|
+
pattern = r"(?:https?://)?(?:www\.)?github\.com/([^/]+)/([^/]+)/issues/(\d+)"
|
|
39
|
+
match = re.search(pattern, url)
|
|
40
|
+
if match:
|
|
41
|
+
return match.group(1), match.group(2), int(match.group(3))
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _run_gh_command(args: List[str]) -> Tuple[bool, str]:
|
|
46
|
+
"""
|
|
47
|
+
Execute a gh CLI command.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
args: List of arguments to pass to `gh`.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Tuple of (success, output). Output is stdout on success, stderr on failure.
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
result = subprocess.run(
|
|
57
|
+
["gh"] + args,
|
|
58
|
+
capture_output=True,
|
|
59
|
+
text=True,
|
|
60
|
+
check=False
|
|
61
|
+
)
|
|
62
|
+
if result.returncode != 0:
|
|
63
|
+
return False, result.stderr.strip()
|
|
64
|
+
return True, result.stdout.strip()
|
|
65
|
+
except Exception as e:
|
|
66
|
+
return False, str(e)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _setup_repository(owner: str, repo: str, quiet: bool) -> Path:
|
|
70
|
+
"""
|
|
71
|
+
Prepare the working directory for the agent.
|
|
72
|
+
|
|
73
|
+
Logic:
|
|
74
|
+
1. If the current directory is the target repository, use it.
|
|
75
|
+
2. Otherwise, clone the repository into a temporary directory.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Path to the working directory.
|
|
79
|
+
"""
|
|
80
|
+
# Check if current directory is the repo
|
|
81
|
+
try:
|
|
82
|
+
if (Path.cwd() / ".git").exists():
|
|
83
|
+
# Get remote origin URL
|
|
84
|
+
res = subprocess.run(
|
|
85
|
+
["git", "remote", "get-url", "origin"],
|
|
86
|
+
capture_output=True,
|
|
87
|
+
text=True
|
|
88
|
+
)
|
|
89
|
+
if res.returncode == 0:
|
|
90
|
+
remote_url = res.stdout.strip()
|
|
91
|
+
# Check if owner/repo is in the remote URL
|
|
92
|
+
# Matches formats like:
|
|
93
|
+
# - https://github.com/owner/repo.git
|
|
94
|
+
# - git@github.com:owner/repo.git
|
|
95
|
+
if f"{owner}/{repo}" in remote_url:
|
|
96
|
+
if not quiet:
|
|
97
|
+
console.print(f"[blue]Using current directory as repository: {Path.cwd()}[/blue]")
|
|
98
|
+
return Path.cwd()
|
|
99
|
+
except Exception:
|
|
100
|
+
# If git check fails, proceed to clone
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
# Clone to a temporary directory
|
|
104
|
+
temp_dir = Path(tempfile.mkdtemp(prefix=f"pdd_{repo}_"))
|
|
105
|
+
if not quiet:
|
|
106
|
+
console.print(f"[blue]Cloning {owner}/{repo} to temporary directory: {temp_dir}[/blue]")
|
|
107
|
+
|
|
108
|
+
# Use gh repo clone to handle authentication automatically
|
|
109
|
+
clone_cmd = ["repo", "clone", f"{owner}/{repo}", "."]
|
|
110
|
+
|
|
111
|
+
# We run this in the temp_dir
|
|
112
|
+
try:
|
|
113
|
+
result = subprocess.run(
|
|
114
|
+
["gh"] + clone_cmd,
|
|
115
|
+
cwd=temp_dir,
|
|
116
|
+
capture_output=True,
|
|
117
|
+
text=True,
|
|
118
|
+
check=False
|
|
119
|
+
)
|
|
120
|
+
if result.returncode != 0:
|
|
121
|
+
raise RuntimeError(f"Failed to clone repository: {result.stderr.strip()}")
|
|
122
|
+
except Exception as e:
|
|
123
|
+
raise RuntimeError(f"Failed to execute clone command: {e}")
|
|
124
|
+
|
|
125
|
+
return temp_dir
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def run_agentic_change(
|
|
129
|
+
issue_url: str,
|
|
130
|
+
*,
|
|
131
|
+
verbose: bool = False,
|
|
132
|
+
quiet: bool = False,
|
|
133
|
+
timeout_adder: float = 0.0,
|
|
134
|
+
use_github_state: bool = True
|
|
135
|
+
) -> Tuple[bool, str, float, str, List[str]]:
|
|
136
|
+
"""
|
|
137
|
+
CLI entry point for the agentic change workflow.
|
|
138
|
+
|
|
139
|
+
Fetches issue details and comments from GitHub, sets up the repository,
|
|
140
|
+
and invokes the orchestrator to perform the 12-step change process.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
issue_url: The full URL of the GitHub issue.
|
|
144
|
+
verbose: If True, enables detailed logging.
|
|
145
|
+
quiet: If True, suppresses standard output.
|
|
146
|
+
timeout_adder: Additional time to add to step timeouts.
|
|
147
|
+
use_github_state: If True, persists state to GitHub comments.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Tuple containing:
|
|
151
|
+
- success (bool)
|
|
152
|
+
- message (str)
|
|
153
|
+
- total_cost (float)
|
|
154
|
+
- model_used (str)
|
|
155
|
+
- changed_files (List[str])
|
|
156
|
+
"""
|
|
157
|
+
# 1. Check dependencies
|
|
158
|
+
if not _check_gh_cli():
|
|
159
|
+
return False, "gh CLI not found", 0.0, "", []
|
|
160
|
+
|
|
161
|
+
# 2. Parse URL
|
|
162
|
+
parsed = _parse_issue_url(issue_url)
|
|
163
|
+
if not parsed:
|
|
164
|
+
return False, "Invalid GitHub URL", 0.0, "", []
|
|
165
|
+
|
|
166
|
+
owner, repo, issue_number = parsed
|
|
167
|
+
|
|
168
|
+
if not quiet:
|
|
169
|
+
console.print(f"[bold]Fetching issue #{issue_number} from {owner}/{repo}...[/bold]")
|
|
170
|
+
|
|
171
|
+
# 3. Fetch Issue Content
|
|
172
|
+
success, issue_json = _run_gh_command(["api", f"repos/{owner}/{repo}/issues/{issue_number}"])
|
|
173
|
+
if not success:
|
|
174
|
+
return False, f"Issue not found: {issue_json}", 0.0, "", []
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
issue_data = json.loads(issue_json)
|
|
178
|
+
except json.JSONDecodeError:
|
|
179
|
+
return False, "Failed to parse issue JSON", 0.0, "", []
|
|
180
|
+
|
|
181
|
+
# Extract metadata
|
|
182
|
+
title = issue_data.get("title", "")
|
|
183
|
+
body = issue_data.get("body", "") or ""
|
|
184
|
+
author = issue_data.get("user", {}).get("login", "unknown")
|
|
185
|
+
comments_url = issue_data.get("comments_url", "")
|
|
186
|
+
|
|
187
|
+
# 4. Fetch Comments
|
|
188
|
+
comments_data = []
|
|
189
|
+
if comments_url:
|
|
190
|
+
success, comments_json = _run_gh_command(["api", comments_url])
|
|
191
|
+
if success:
|
|
192
|
+
try:
|
|
193
|
+
comments_data = json.loads(comments_json)
|
|
194
|
+
except json.JSONDecodeError:
|
|
195
|
+
if verbose:
|
|
196
|
+
console.print("[yellow]Warning: Failed to parse comments JSON[/yellow]")
|
|
197
|
+
|
|
198
|
+
# 5. Construct Full Context
|
|
199
|
+
issue_content = f"Title: {title}\n\nDescription:\n{body}\n"
|
|
200
|
+
if comments_data and isinstance(comments_data, list):
|
|
201
|
+
issue_content += "\nComments:\n"
|
|
202
|
+
for comment in comments_data:
|
|
203
|
+
if isinstance(comment, dict):
|
|
204
|
+
c_user = comment.get("user", {}).get("login", "unknown")
|
|
205
|
+
c_body = comment.get("body", "")
|
|
206
|
+
issue_content += f"\n--- Comment by {c_user} ---\n{c_body}\n"
|
|
207
|
+
|
|
208
|
+
# 6. Setup Repository (Clone or Use Current)
|
|
209
|
+
try:
|
|
210
|
+
work_dir = _setup_repository(owner, repo, quiet)
|
|
211
|
+
except RuntimeError as e:
|
|
212
|
+
return False, str(e), 0.0, "", []
|
|
213
|
+
|
|
214
|
+
# 7. Run Orchestrator
|
|
215
|
+
if not quiet:
|
|
216
|
+
console.print(f"[bold green]Starting Agentic Change Orchestrator...[/bold green]")
|
|
217
|
+
|
|
218
|
+
return run_agentic_change_orchestrator(
|
|
219
|
+
issue_url=issue_url,
|
|
220
|
+
issue_content=issue_content,
|
|
221
|
+
repo_owner=owner,
|
|
222
|
+
repo_name=repo,
|
|
223
|
+
issue_number=issue_number,
|
|
224
|
+
issue_author=author,
|
|
225
|
+
issue_title=title,
|
|
226
|
+
cwd=work_dir,
|
|
227
|
+
verbose=verbose,
|
|
228
|
+
quiet=quiet,
|
|
229
|
+
timeout_adder=timeout_adder,
|
|
230
|
+
use_github_state=use_github_state
|
|
231
|
+
)
|