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.
Files changed (195) hide show
  1. pdd/__init__.py +40 -8
  2. pdd/agentic_bug.py +323 -0
  3. pdd/agentic_bug_orchestrator.py +497 -0
  4. pdd/agentic_change.py +231 -0
  5. pdd/agentic_change_orchestrator.py +526 -0
  6. pdd/agentic_common.py +598 -0
  7. pdd/agentic_crash.py +534 -0
  8. pdd/agentic_e2e_fix.py +319 -0
  9. pdd/agentic_e2e_fix_orchestrator.py +426 -0
  10. pdd/agentic_fix.py +1294 -0
  11. pdd/agentic_langtest.py +162 -0
  12. pdd/agentic_update.py +387 -0
  13. pdd/agentic_verify.py +183 -0
  14. pdd/architecture_sync.py +565 -0
  15. pdd/auth_service.py +210 -0
  16. pdd/auto_deps_main.py +71 -51
  17. pdd/auto_include.py +245 -5
  18. pdd/auto_update.py +125 -47
  19. pdd/bug_main.py +196 -23
  20. pdd/bug_to_unit_test.py +2 -0
  21. pdd/change_main.py +11 -4
  22. pdd/cli.py +22 -1181
  23. pdd/cmd_test_main.py +350 -150
  24. pdd/code_generator.py +60 -18
  25. pdd/code_generator_main.py +790 -57
  26. pdd/commands/__init__.py +48 -0
  27. pdd/commands/analysis.py +306 -0
  28. pdd/commands/auth.py +309 -0
  29. pdd/commands/connect.py +290 -0
  30. pdd/commands/fix.py +163 -0
  31. pdd/commands/generate.py +257 -0
  32. pdd/commands/maintenance.py +175 -0
  33. pdd/commands/misc.py +87 -0
  34. pdd/commands/modify.py +256 -0
  35. pdd/commands/report.py +144 -0
  36. pdd/commands/sessions.py +284 -0
  37. pdd/commands/templates.py +215 -0
  38. pdd/commands/utility.py +110 -0
  39. pdd/config_resolution.py +58 -0
  40. pdd/conflicts_main.py +8 -3
  41. pdd/construct_paths.py +589 -111
  42. pdd/context_generator.py +10 -2
  43. pdd/context_generator_main.py +175 -76
  44. pdd/continue_generation.py +53 -10
  45. pdd/core/__init__.py +33 -0
  46. pdd/core/cli.py +527 -0
  47. pdd/core/cloud.py +237 -0
  48. pdd/core/dump.py +554 -0
  49. pdd/core/errors.py +67 -0
  50. pdd/core/remote_session.py +61 -0
  51. pdd/core/utils.py +90 -0
  52. pdd/crash_main.py +262 -33
  53. pdd/data/language_format.csv +71 -63
  54. pdd/data/llm_model.csv +20 -18
  55. pdd/detect_change_main.py +5 -4
  56. pdd/docs/prompting_guide.md +864 -0
  57. pdd/docs/whitepaper_with_benchmarks/data_and_functions/benchmark_analysis.py +495 -0
  58. pdd/docs/whitepaper_with_benchmarks/data_and_functions/creation_compare.py +528 -0
  59. pdd/fix_code_loop.py +523 -95
  60. pdd/fix_code_module_errors.py +6 -2
  61. pdd/fix_error_loop.py +491 -92
  62. pdd/fix_errors_from_unit_tests.py +4 -3
  63. pdd/fix_main.py +278 -21
  64. pdd/fix_verification_errors.py +12 -100
  65. pdd/fix_verification_errors_loop.py +529 -286
  66. pdd/fix_verification_main.py +294 -89
  67. pdd/frontend/dist/assets/index-B5DZHykP.css +1 -0
  68. pdd/frontend/dist/assets/index-DQ3wkeQ2.js +449 -0
  69. pdd/frontend/dist/index.html +376 -0
  70. pdd/frontend/dist/logo.svg +33 -0
  71. pdd/generate_output_paths.py +139 -15
  72. pdd/generate_test.py +218 -146
  73. pdd/get_comment.py +19 -44
  74. pdd/get_extension.py +8 -9
  75. pdd/get_jwt_token.py +318 -22
  76. pdd/get_language.py +8 -7
  77. pdd/get_run_command.py +75 -0
  78. pdd/get_test_command.py +68 -0
  79. pdd/git_update.py +70 -19
  80. pdd/incremental_code_generator.py +2 -2
  81. pdd/insert_includes.py +13 -4
  82. pdd/llm_invoke.py +1711 -181
  83. pdd/load_prompt_template.py +19 -12
  84. pdd/path_resolution.py +140 -0
  85. pdd/pdd_completion.fish +25 -2
  86. pdd/pdd_completion.sh +30 -4
  87. pdd/pdd_completion.zsh +79 -4
  88. pdd/postprocess.py +14 -4
  89. pdd/preprocess.py +293 -24
  90. pdd/preprocess_main.py +41 -6
  91. pdd/prompts/agentic_bug_step10_pr_LLM.prompt +182 -0
  92. pdd/prompts/agentic_bug_step1_duplicate_LLM.prompt +73 -0
  93. pdd/prompts/agentic_bug_step2_docs_LLM.prompt +129 -0
  94. pdd/prompts/agentic_bug_step3_triage_LLM.prompt +95 -0
  95. pdd/prompts/agentic_bug_step4_reproduce_LLM.prompt +97 -0
  96. pdd/prompts/agentic_bug_step5_root_cause_LLM.prompt +123 -0
  97. pdd/prompts/agentic_bug_step6_test_plan_LLM.prompt +107 -0
  98. pdd/prompts/agentic_bug_step7_generate_LLM.prompt +172 -0
  99. pdd/prompts/agentic_bug_step8_verify_LLM.prompt +119 -0
  100. pdd/prompts/agentic_bug_step9_e2e_test_LLM.prompt +289 -0
  101. pdd/prompts/agentic_change_step10_identify_issues_LLM.prompt +1006 -0
  102. pdd/prompts/agentic_change_step11_fix_issues_LLM.prompt +984 -0
  103. pdd/prompts/agentic_change_step12_create_pr_LLM.prompt +131 -0
  104. pdd/prompts/agentic_change_step1_duplicate_LLM.prompt +73 -0
  105. pdd/prompts/agentic_change_step2_docs_LLM.prompt +101 -0
  106. pdd/prompts/agentic_change_step3_research_LLM.prompt +126 -0
  107. pdd/prompts/agentic_change_step4_clarify_LLM.prompt +164 -0
  108. pdd/prompts/agentic_change_step5_docs_change_LLM.prompt +981 -0
  109. pdd/prompts/agentic_change_step6_devunits_LLM.prompt +1005 -0
  110. pdd/prompts/agentic_change_step7_architecture_LLM.prompt +1044 -0
  111. pdd/prompts/agentic_change_step8_analyze_LLM.prompt +1027 -0
  112. pdd/prompts/agentic_change_step9_implement_LLM.prompt +1077 -0
  113. pdd/prompts/agentic_crash_explore_LLM.prompt +49 -0
  114. pdd/prompts/agentic_e2e_fix_step1_unit_tests_LLM.prompt +90 -0
  115. pdd/prompts/agentic_e2e_fix_step2_e2e_tests_LLM.prompt +91 -0
  116. pdd/prompts/agentic_e2e_fix_step3_root_cause_LLM.prompt +89 -0
  117. pdd/prompts/agentic_e2e_fix_step4_fix_e2e_tests_LLM.prompt +96 -0
  118. pdd/prompts/agentic_e2e_fix_step5_identify_devunits_LLM.prompt +91 -0
  119. pdd/prompts/agentic_e2e_fix_step6_create_unit_tests_LLM.prompt +106 -0
  120. pdd/prompts/agentic_e2e_fix_step7_verify_tests_LLM.prompt +116 -0
  121. pdd/prompts/agentic_e2e_fix_step8_run_pdd_fix_LLM.prompt +120 -0
  122. pdd/prompts/agentic_e2e_fix_step9_verify_all_LLM.prompt +146 -0
  123. pdd/prompts/agentic_fix_explore_LLM.prompt +45 -0
  124. pdd/prompts/agentic_fix_harvest_only_LLM.prompt +48 -0
  125. pdd/prompts/agentic_fix_primary_LLM.prompt +85 -0
  126. pdd/prompts/agentic_update_LLM.prompt +925 -0
  127. pdd/prompts/agentic_verify_explore_LLM.prompt +45 -0
  128. pdd/prompts/auto_include_LLM.prompt +122 -905
  129. pdd/prompts/change_LLM.prompt +3093 -1
  130. pdd/prompts/detect_change_LLM.prompt +686 -27
  131. pdd/prompts/example_generator_LLM.prompt +22 -1
  132. pdd/prompts/extract_code_LLM.prompt +5 -1
  133. pdd/prompts/extract_program_code_fix_LLM.prompt +7 -1
  134. pdd/prompts/extract_prompt_update_LLM.prompt +7 -8
  135. pdd/prompts/extract_promptline_LLM.prompt +17 -11
  136. pdd/prompts/find_verification_errors_LLM.prompt +6 -0
  137. pdd/prompts/fix_code_module_errors_LLM.prompt +12 -2
  138. pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +9 -0
  139. pdd/prompts/fix_verification_errors_LLM.prompt +22 -0
  140. pdd/prompts/generate_test_LLM.prompt +41 -7
  141. pdd/prompts/generate_test_from_example_LLM.prompt +115 -0
  142. pdd/prompts/increase_tests_LLM.prompt +1 -5
  143. pdd/prompts/insert_includes_LLM.prompt +316 -186
  144. pdd/prompts/prompt_code_diff_LLM.prompt +119 -0
  145. pdd/prompts/prompt_diff_LLM.prompt +82 -0
  146. pdd/prompts/trace_LLM.prompt +25 -22
  147. pdd/prompts/unfinished_prompt_LLM.prompt +85 -1
  148. pdd/prompts/update_prompt_LLM.prompt +22 -1
  149. pdd/pytest_output.py +127 -12
  150. pdd/remote_session.py +876 -0
  151. pdd/render_mermaid.py +236 -0
  152. pdd/server/__init__.py +52 -0
  153. pdd/server/app.py +335 -0
  154. pdd/server/click_executor.py +587 -0
  155. pdd/server/executor.py +338 -0
  156. pdd/server/jobs.py +661 -0
  157. pdd/server/models.py +241 -0
  158. pdd/server/routes/__init__.py +31 -0
  159. pdd/server/routes/architecture.py +451 -0
  160. pdd/server/routes/auth.py +364 -0
  161. pdd/server/routes/commands.py +929 -0
  162. pdd/server/routes/config.py +42 -0
  163. pdd/server/routes/files.py +603 -0
  164. pdd/server/routes/prompts.py +1322 -0
  165. pdd/server/routes/websocket.py +473 -0
  166. pdd/server/security.py +243 -0
  167. pdd/server/terminal_spawner.py +209 -0
  168. pdd/server/token_counter.py +222 -0
  169. pdd/setup_tool.py +648 -0
  170. pdd/simple_math.py +2 -0
  171. pdd/split_main.py +3 -2
  172. pdd/summarize_directory.py +237 -195
  173. pdd/sync_animation.py +8 -4
  174. pdd/sync_determine_operation.py +839 -112
  175. pdd/sync_main.py +351 -57
  176. pdd/sync_orchestration.py +1400 -756
  177. pdd/sync_tui.py +848 -0
  178. pdd/template_expander.py +161 -0
  179. pdd/template_registry.py +264 -0
  180. pdd/templates/architecture/architecture_json.prompt +237 -0
  181. pdd/templates/generic/generate_prompt.prompt +174 -0
  182. pdd/trace.py +168 -12
  183. pdd/trace_main.py +4 -3
  184. pdd/track_cost.py +140 -63
  185. pdd/unfinished_prompt.py +51 -4
  186. pdd/update_main.py +567 -67
  187. pdd/update_model_costs.py +2 -2
  188. pdd/update_prompt.py +19 -4
  189. {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/METADATA +29 -11
  190. pdd_cli-0.0.118.dist-info/RECORD +227 -0
  191. {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/licenses/LICENSE +1 -1
  192. pdd_cli-0.0.45.dist-info/RECORD +0 -116
  193. {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/WHEEL +0 -0
  194. {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/entry_points.txt +0 -0
  195. {pdd_cli-0.0.45.dist-info → pdd_cli-0.0.118.dist-info}/top_level.txt +0 -0
pdd/core/utils.py ADDED
@@ -0,0 +1,90 @@
1
+ """
2
+ Helper functions for the PDD CLI.
3
+ """
4
+ import os
5
+ import sys
6
+ import subprocess
7
+ from pathlib import Path
8
+ from typing import Optional
9
+ import click
10
+
11
+ from ..install_completion import (
12
+ get_current_shell,
13
+ get_shell_rc_path,
14
+ )
15
+
16
+ def _first_pending_command(ctx: click.Context) -> Optional[str]:
17
+ """Return the first subcommand scheduled for this invocation."""
18
+ for arg in ctx.protected_args:
19
+ if not arg.startswith("-"):
20
+ return arg
21
+ return None
22
+
23
+
24
+ def _api_env_exists() -> bool:
25
+ """Check whether the ~/.pdd/api-env file exists."""
26
+ return (Path.home() / ".pdd" / "api-env").exists()
27
+
28
+
29
+ def _completion_installed() -> bool:
30
+ """Check if the shell RC file already sources the PDD completion script."""
31
+ shell = get_current_shell()
32
+ rc_path = get_shell_rc_path(shell) if shell else None
33
+ if not rc_path:
34
+ return False
35
+
36
+ try:
37
+ content = Path(rc_path).read_text(encoding="utf-8")
38
+ except (OSError, UnicodeDecodeError):
39
+ return False
40
+
41
+ return "PDD CLI completion" in content or "pdd_completion" in content
42
+
43
+
44
+ def _project_has_local_configuration() -> bool:
45
+ """Detect project-level env configuration that should suppress reminders."""
46
+ cwd = Path.cwd()
47
+
48
+ env_file = cwd / ".env"
49
+ if env_file.exists():
50
+ try:
51
+ env_content = env_file.read_text(encoding="utf-8")
52
+ except (OSError, UnicodeDecodeError):
53
+ env_content = ""
54
+ if any(token in env_content for token in ("OPENAI_API_KEY=", "GOOGLE_API_KEY=", "ANTHROPIC_API_KEY=")):
55
+ return True
56
+
57
+ project_pdd_dir = cwd / ".pdd"
58
+ if project_pdd_dir.exists():
59
+ return True
60
+
61
+ return False
62
+
63
+
64
+ def _should_show_onboarding_reminder(ctx: click.Context) -> bool:
65
+ """Determine whether to display the onboarding reminder banner."""
66
+ suppress = os.getenv("PDD_SUPPRESS_SETUP_REMINDER", "").lower()
67
+ if suppress in {"1", "true", "yes"}:
68
+ return False
69
+
70
+ first_command = _first_pending_command(ctx)
71
+ if first_command == "setup":
72
+ return False
73
+
74
+ if _api_env_exists():
75
+ return False
76
+
77
+ if _project_has_local_configuration():
78
+ return False
79
+
80
+ if _completion_installed():
81
+ return False
82
+
83
+ return True
84
+
85
+
86
+ def _run_setup_utility() -> None:
87
+ """Execute the interactive setup utility script."""
88
+ result = subprocess.run([sys.executable, "-m", "pdd.setup_tool"])
89
+ if result.returncode not in (0, None):
90
+ raise RuntimeError(f"Setup utility exited with status {result.returncode}")
pdd/crash_main.py CHANGED
@@ -1,12 +1,21 @@
1
1
  import sys
2
2
  from typing import Tuple, Optional, Dict, Any
3
+ import json
3
4
  import click
4
5
  from rich import print as rprint
5
- from . import DEFAULT_STRENGTH, DEFAULT_TIME
6
+ from rich.console import Console
7
+ from rich.panel import Panel
6
8
  from pathlib import Path
7
9
 
10
+ import requests
11
+ import os
12
+
13
+ from .config_resolution import resolve_effective_config
8
14
  from .construct_paths import construct_paths
9
15
  from .fix_code_loop import fix_code_loop
16
+ from .core.cloud import CloudConfig
17
+ from .get_language import get_language
18
+
10
19
  # Import fix_code_module_errors conditionally or ensure it's always available
11
20
  try:
12
21
  from .fix_code_module_errors import fix_code_module_errors
@@ -14,6 +23,19 @@ except ImportError:
14
23
  # Handle case where fix_code_module_errors might not be available if not needed
15
24
  fix_code_module_errors = None
16
25
 
26
+ # Cloud request timeout
27
+ CLOUD_REQUEST_TIMEOUT = 400 # seconds
28
+
29
+ console = Console()
30
+
31
+
32
+ def _env_flag_enabled(name: str) -> bool:
33
+ """Return True when an env var is set to a truthy value."""
34
+ value = os.environ.get(name)
35
+ if value is None:
36
+ return False
37
+ return str(value).strip().lower() in {"1", "true", "yes", "on"}
38
+
17
39
  def crash_main(
18
40
  ctx: click.Context,
19
41
  prompt_file: str,
@@ -24,7 +46,10 @@ def crash_main(
24
46
  output_program: Optional[str] = None,
25
47
  loop: bool = False,
26
48
  max_attempts: Optional[int] = None,
27
- budget: Optional[float] = None
49
+ budget: Optional[float] = None,
50
+ agentic_fallback: bool = True,
51
+ strength: Optional[float] = None,
52
+ temperature: Optional[float] = None,
28
53
  ) -> Tuple[bool, str, str, int, float, str]:
29
54
  """
30
55
  Main function to fix errors in a code module and its calling program that caused a crash.
@@ -39,6 +64,7 @@ def crash_main(
39
64
  :param loop: Enable iterative fixing process.
40
65
  :param max_attempts: Maximum number of fix attempts before giving up.
41
66
  :param budget: Maximum cost allowed for the fixing process.
67
+ :param agentic_fallback: Enable agentic fallback if the primary fix mechanism fails.
42
68
  :return: A tuple containing:
43
69
  - bool: Success status
44
70
  - str: The final fixed code module
@@ -54,9 +80,9 @@ def crash_main(
54
80
  quiet = ctx.params.get("quiet", ctx.obj.get("quiet", False))
55
81
  verbose = ctx.params.get("verbose", ctx.obj.get("verbose", False))
56
82
 
57
- strength = ctx.obj.get("strength", DEFAULT_STRENGTH)
58
- temperature = ctx.obj.get("temperature", 0)
59
- time_param = ctx.obj.get("time", DEFAULT_TIME)
83
+ # Store parameter values for later resolution
84
+ param_strength = strength
85
+ param_temperature = temperature
60
86
 
61
87
  try:
62
88
  input_file_paths = {
@@ -77,8 +103,20 @@ def crash_main(
77
103
  force=force,
78
104
  quiet=quiet,
79
105
  command="crash",
80
- command_options=command_options
106
+ command_options=command_options,
107
+ context_override=ctx.obj.get('context'),
108
+ confirm_callback=ctx.obj.get('confirm_callback')
109
+ )
110
+ # Use centralized config resolution with proper priority:
111
+ # CLI > pddrc > defaults
112
+ effective_config = resolve_effective_config(
113
+ ctx,
114
+ resolved_config,
115
+ param_overrides={"strength": param_strength, "temperature": param_temperature}
81
116
  )
117
+ strength = effective_config["strength"]
118
+ temperature = effective_config["temperature"]
119
+ time_param = effective_config["time"]
82
120
 
83
121
  prompt_content = input_strings["prompt_file"]
84
122
  code_content = input_strings["code_file"]
@@ -91,10 +129,33 @@ def crash_main(
91
129
  code_updated: bool = False
92
130
  program_updated: bool = False
93
131
 
132
+ # Determine cloud vs local execution preference
133
+ is_local_execution_preferred = ctx.obj.get('local', False)
134
+ cloud_only = _env_flag_enabled("PDD_CLOUD_ONLY") or _env_flag_enabled("PDD_NO_LOCAL_FALLBACK")
135
+ current_execution_is_local = is_local_execution_preferred and not cloud_only
136
+
137
+ # Cloud execution tracking
138
+ cloud_execution_attempted = False
139
+ cloud_execution_succeeded = False
140
+
94
141
  if loop:
142
+ # Determine if loop should use cloud for LLM calls (hybrid mode)
143
+ # Local program execution stays local, but LLM fix calls can go to cloud
144
+ use_cloud_for_loop = not is_local_execution_preferred and not cloud_only
145
+
146
+ # If cloud_only is set but we're in loop mode, we still use hybrid approach
147
+ if cloud_only and not is_local_execution_preferred:
148
+ use_cloud_for_loop = True
149
+
150
+ if verbose:
151
+ mode_desc = "hybrid (local execution + cloud LLM)" if use_cloud_for_loop else "local"
152
+ console.print(Panel(f"Performing {mode_desc} crash fix loop...", title="[blue]Mode[/blue]", expand=False))
153
+
95
154
  success, final_program, final_code, attempts, cost, model = fix_code_loop(
96
155
  code_file, prompt_content, program_file, strength, temperature,
97
- max_attempts or 3, budget or 5.0, error_file, verbose, time_param
156
+ max_attempts if max_attempts is not None else 3, budget or 5.0, error_file, verbose, time_param,
157
+ prompt_file=prompt_file, agentic_fallback=agentic_fallback,
158
+ use_cloud=use_cloud_for_loop
98
159
  )
99
160
  # Always set final_code/final_program to something non-empty
100
161
  if not final_code:
@@ -104,33 +165,182 @@ def crash_main(
104
165
  code_updated = final_code != original_code_content
105
166
  program_updated = final_program != original_program_content
106
167
  else:
107
- if fix_code_module_errors is None:
108
- raise ImportError("fix_code_module_errors is required but not available.")
168
+ # Single-pass mode: attempt cloud first, fallback to local
169
+ if not current_execution_is_local:
170
+ if verbose:
171
+ console.print(Panel("Attempting cloud crash fix execution...", title="[blue]Mode[/blue]", expand=False))
109
172
 
110
- update_program, update_code, fixed_program, fixed_code, _, cost, model = fix_code_module_errors(
111
- program_content, prompt_content, code_content, error_content,
112
- strength, temperature, verbose, time_param
113
- )
114
- success = True
115
- attempts = 1
173
+ jwt_token = CloudConfig.get_jwt_token(verbose=verbose)
116
174
 
117
- # Fallback if fixed_program is empty but update_program is True
118
- if update_program and not fixed_program.strip():
119
- fixed_program = program_content
120
- if update_code and not fixed_code.strip():
121
- fixed_code = code_content
175
+ if not jwt_token:
176
+ if cloud_only:
177
+ console.print("[red]Cloud authentication failed.[/red]")
178
+ raise click.UsageError("Cloud authentication failed")
179
+ console.print("[yellow]Cloud authentication failed. Falling back to local execution.[/yellow]")
180
+ current_execution_is_local = True
122
181
 
123
- final_code = fixed_code if update_code else code_content
124
- final_program = fixed_program if update_program else program_content
182
+ if jwt_token and not current_execution_is_local:
183
+ cloud_execution_attempted = True
184
+ # Build cloud payload
185
+ payload = {
186
+ "programContent": program_content,
187
+ "promptContent": prompt_content,
188
+ "codeContent": code_content,
189
+ "errorContent": error_content,
190
+ "language": language,
191
+ "strength": strength,
192
+ "temperature": temperature,
193
+ "time": time_param if time_param is not None else 0.25,
194
+ "verbose": verbose,
195
+ "programPath": program_file,
196
+ "codePath": code_file,
197
+ }
125
198
 
126
- # Always set final_code/final_program to something non-empty
127
- if not final_code:
128
- final_code = original_code_content
129
- if not final_program:
130
- final_program = original_program_content
199
+ headers = {
200
+ "Authorization": f"Bearer {jwt_token}",
201
+ "Content-Type": "application/json"
202
+ }
203
+ cloud_url = CloudConfig.get_endpoint_url("crashCode")
131
204
 
132
- code_updated = final_code != original_code_content
133
- program_updated = final_program != original_program_content
205
+ try:
206
+ response = requests.post(
207
+ cloud_url,
208
+ json=payload,
209
+ headers=headers,
210
+ timeout=CLOUD_REQUEST_TIMEOUT
211
+ )
212
+ response.raise_for_status()
213
+
214
+ response_data = response.json()
215
+ fixed_code = response_data.get("fixedCode", "")
216
+ fixed_program = response_data.get("fixedProgram", "")
217
+ update_code = response_data.get("updateCode", False)
218
+ update_program = response_data.get("updateProgram", False)
219
+ cost = float(response_data.get("totalCost", 0.0))
220
+ model = response_data.get("modelName", "cloud_model")
221
+
222
+ if not (fixed_code or fixed_program):
223
+ if cloud_only:
224
+ console.print("[red]Cloud execution returned no fixed code.[/red]")
225
+ raise click.UsageError("Cloud execution returned no fixed code")
226
+ console.print("[yellow]Cloud execution returned no fixed code. Falling back to local.[/yellow]")
227
+ current_execution_is_local = True
228
+ else:
229
+ cloud_execution_succeeded = True
230
+ success = True
231
+ attempts = 1
232
+
233
+ # Fallback if fixed_program is empty but update_program is True
234
+ if update_program and not fixed_program.strip():
235
+ fixed_program = program_content
236
+ if update_code and not fixed_code.strip():
237
+ fixed_code = code_content
238
+
239
+ final_code = fixed_code if update_code else code_content
240
+ final_program = fixed_program if update_program else program_content
241
+
242
+ # Always set final_code/final_program to something non-empty
243
+ if not final_code:
244
+ final_code = original_code_content
245
+ if not final_program:
246
+ final_program = original_program_content
247
+
248
+ code_updated = final_code != original_code_content
249
+ program_updated = final_program != original_program_content
250
+
251
+ if verbose:
252
+ console.print(Panel(
253
+ f"Cloud crash fix completed. Model: {model}, Cost: ${cost:.6f}",
254
+ title="[green]Cloud Success[/green]",
255
+ expand=False
256
+ ))
257
+
258
+ except requests.exceptions.Timeout:
259
+ if cloud_only:
260
+ console.print(f"[red]Cloud execution timed out ({CLOUD_REQUEST_TIMEOUT}s).[/red]")
261
+ raise click.UsageError("Cloud execution timed out")
262
+ console.print(f"[yellow]Cloud execution timed out ({CLOUD_REQUEST_TIMEOUT}s). Falling back to local.[/yellow]")
263
+ current_execution_is_local = True
264
+
265
+ except requests.exceptions.HTTPError as e:
266
+ status_code = e.response.status_code if e.response else 0
267
+ err_content = e.response.text[:200] if e.response else "No response content"
268
+
269
+ # Non-recoverable errors: do NOT fall back to local
270
+ if status_code == 402: # Insufficient credits
271
+ try:
272
+ error_data = e.response.json()
273
+ current_balance = error_data.get("currentBalance", "unknown")
274
+ estimated_cost = error_data.get("estimatedCost", "unknown")
275
+ console.print(f"[red]Insufficient credits. Current balance: {current_balance}, estimated cost: {estimated_cost}[/red]")
276
+ except Exception:
277
+ console.print(f"[red]Insufficient credits: {err_content}[/red]")
278
+ raise click.UsageError("Insufficient credits for cloud crash fix")
279
+ elif status_code == 401: # Authentication error
280
+ console.print(f"[red]Authentication failed: {err_content}[/red]")
281
+ raise click.UsageError("Cloud authentication failed")
282
+ elif status_code == 403: # Authorization error (not approved)
283
+ console.print(f"[red]Access denied: {err_content}[/red]")
284
+ raise click.UsageError("Access denied - user not approved")
285
+ elif status_code == 400: # Validation error
286
+ console.print(f"[red]Invalid request: {err_content}[/red]")
287
+ raise click.UsageError(f"Invalid request: {err_content}")
288
+ else:
289
+ # Recoverable errors (5xx, unexpected errors): fall back to local
290
+ if cloud_only:
291
+ console.print(f"[red]Cloud HTTP error ({status_code}): {err_content}[/red]")
292
+ raise click.UsageError(f"Cloud HTTP error ({status_code}): {err_content}")
293
+ console.print(f"[yellow]Cloud HTTP error ({status_code}): {err_content}. Falling back to local.[/yellow]")
294
+ current_execution_is_local = True
295
+
296
+ except requests.exceptions.RequestException as e:
297
+ if cloud_only:
298
+ console.print(f"[red]Cloud network error: {e}[/red]")
299
+ raise click.UsageError(f"Cloud network error: {e}")
300
+ console.print(f"[yellow]Cloud network error: {e}. Falling back to local.[/yellow]")
301
+ current_execution_is_local = True
302
+
303
+ except json.JSONDecodeError:
304
+ if cloud_only:
305
+ console.print("[red]Cloud returned invalid JSON.[/red]")
306
+ raise click.UsageError("Cloud returned invalid JSON")
307
+ console.print("[yellow]Cloud returned invalid JSON. Falling back to local.[/yellow]")
308
+ current_execution_is_local = True
309
+
310
+ # Local execution path (when cloud failed/skipped or local preferred)
311
+ if not cloud_execution_succeeded:
312
+ if fix_code_module_errors is None:
313
+ raise ImportError("fix_code_module_errors is required but not available.")
314
+
315
+ if verbose:
316
+ console.print(Panel("Performing local crash fix...", title="[blue]Mode[/blue]", expand=False))
317
+
318
+ update_program, update_code, fixed_program, fixed_code, _, cost, model = fix_code_module_errors(
319
+ program_content, prompt_content, code_content, error_content,
320
+ strength, temperature, time_param, verbose,
321
+ program_path=program_file,
322
+ code_path=code_file,
323
+ )
324
+ success = True
325
+ attempts = 1
326
+
327
+ # Fallback if fixed_program is empty but update_program is True
328
+ if update_program and not fixed_program.strip():
329
+ fixed_program = program_content
330
+ if update_code and not fixed_code.strip():
331
+ fixed_code = code_content
332
+
333
+ final_code = fixed_code if update_code else code_content
334
+ final_program = fixed_program if update_program else program_content
335
+
336
+ # Always set final_code/final_program to something non-empty
337
+ if not final_code:
338
+ final_code = original_code_content
339
+ if not final_program:
340
+ final_program = original_program_content
341
+
342
+ code_updated = final_code != original_code_content
343
+ program_updated = final_program != original_program_content
134
344
 
135
345
  output_code_path_str = output_file_paths.get("output")
136
346
  output_program_path_str = output_file_paths.get("output_program")
@@ -161,20 +371,39 @@ def crash_main(
161
371
  if code_updated:
162
372
  rprint(f"[bold]Fixed code saved to:[/bold] {output_code_path_str}")
163
373
  else:
164
- rprint(f"[info]Code file '{Path(code_file).name}' was not modified (but output file was written).[/info]")
374
+ rprint(f"[bold]Code saved to:[/bold] {output_code_path_str} [dim](not modified)[/dim]")
165
375
  if output_program_path_str:
166
376
  if program_updated:
167
377
  rprint(f"[bold]Fixed program saved to:[/bold] {output_program_path_str}")
168
378
  else:
169
- rprint(f"[info]Program file '{Path(program_file).name}' was not modified (but output file was written).[/info]")
379
+ rprint(f"[bold]Program saved to:[/bold] {output_program_path_str} [dim](not modified)[/dim]")
380
+
381
+ if verbose:
382
+ rprint("\n[bold]Verbose diagnostics:[/bold]")
383
+ rprint(f" Code file: {code_file}")
384
+ rprint(f" Program file: {program_file}")
385
+ rprint(f" Code updated: {code_updated}")
386
+ rprint(f" Program updated: {program_updated}")
387
+ rprint(f" Original code length: {len(original_code_content)} chars")
388
+ rprint(f" Final code length: {len(final_code)} chars")
389
+ rprint(f" Original program length: {len(original_program_content)} chars")
390
+ rprint(f" Final program length: {len(final_program)} chars")
170
391
 
171
392
  return success, final_code, final_program, attempts, cost, model
172
393
 
173
394
  except FileNotFoundError as e:
174
395
  if not quiet:
175
396
  rprint(f"[bold red]Error:[/bold red] Input file not found: {e}")
176
- sys.exit(1)
397
+ # Return error result instead of sys.exit(1) to allow orchestrator to handle gracefully
398
+ return False, "", "", 0, 0.0, f"FileNotFoundError: {e}"
399
+ except click.Abort:
400
+ # User cancelled - re-raise to stop the sync loop
401
+ raise
402
+ except click.UsageError:
403
+ # Re-raise UsageError for proper CLI handling (e.g., cloud auth failures, insufficient credits)
404
+ raise
177
405
  except Exception as e:
178
406
  if not quiet:
179
407
  rprint(f"[bold red]An unexpected error occurred:[/bold red] {str(e)}")
180
- sys.exit(1)
408
+ # Return error result instead of sys.exit(1) to allow orchestrator to handle gracefully
409
+ return False, "", "", 0, 0.0, f"Error: {e}"
@@ -1,63 +1,71 @@
1
- language,comment,extension
2
- Python,#,.py
3
- Java,//,.java
4
- C++,//,.cpp
5
- JavaScript,//,.js
6
- HTML,"<!-- -->",.html
7
- CSS,"/**/",.css
8
- Ruby,#,.rb
9
- PHP,//,.php
10
- Swift,//,.swift
11
- Go,//,.go
12
- Rust,//,.rs
13
- Kotlin,//,.kt
14
- TypeScript,//,.ts
15
- TypeScriptReact,//,.tsx
16
- C#,//,.cs
17
- SQL,--,.sql
18
- Shell,#,.sh
19
- Bash,#,.sh
20
- Fish,#,.fish
21
- Zsh,#,.zsh
22
- PowerShell,#,.ps1
23
- Perl,#,.pl
24
- R,#,.R
25
- MATLAB,%,.m
26
- Lua,--,.lua
27
- Haskell,--,.hs
28
- Scala,//,.scala
29
- Groovy,//,.groovy
30
- Dart,//,.dart
31
- F#,//,.fs
32
- YAML,#,.yml
33
- JSON,del,.json
34
- JSONL,del,.jsonl
35
- XML,"<!-- -->",.xml
36
- Makefile,#,
37
- CSV,del,.csv
38
- Markdown,del,.md
39
- LaTeX,%,.tex
40
- Assembly,;,.asm
41
- Fortran,!,.f90
42
- COBOL,*>,.cob
43
- Lisp,;,.lisp
44
- Prolog,%,.pl
45
- Erlang,%,.erl
46
- Clojure,;,.clj
47
- Julia,#,.jl
48
- Elixir,#,.ex
49
- Pascal,//,.pas
50
- VBScript,"'",.vbs
51
- CoffeeScript,#,.coffee
52
- Objective-C,//,.m
53
- Scheme,;,.scm
54
- Tcl,#,.tcl
55
- D,//,.d
56
- Ada,--,.ada
57
- Nim,#,.nim
58
- OCaml,"(**)",.ml
59
- LLM,del,.prompt
60
- prompt,del,.prompt
61
- TOML,#,.toml
62
- Log,del,.log
63
- reStructuredText,del,.rst
1
+ language,comment,extension,run_command,run_test_command
2
+ Python,#,.py,python {file},python -m pytest {file} -v
3
+ Java,//,.java,java {file},
4
+ C++,//,.cpp,,
5
+ JavaScript,//,.js,node {file},
6
+ HTML,"<!-- -->",.html,,
7
+ CSS,"/**/",.css,,
8
+ Ruby,#,.rb,ruby {file},
9
+ PHP,//,.php,php {file},
10
+ Swift,//,.swift,swift {file},swift test
11
+ Go,//,.go,go run {file},go test -v {file}
12
+ Rust,//,.rs,,cargo test
13
+ Kotlin,//,.kt,kotlin {file},
14
+ TypeScript,//,.ts,npx tsx {file},
15
+ TypeScriptReact,//,.tsx,npx tsx {file},
16
+ C#,//,.cs,dotnet run {file},dotnet test
17
+ SQL,--,.sql,,
18
+ Shell,#,.sh,sh {file},
19
+ Bash,#,.sh,bash {file},
20
+ Fish,#,.fish,fish {file},
21
+ Zsh,#,.zsh,zsh {file},
22
+ PowerShell,#,.ps1,pwsh {file},
23
+ Perl,#,.pl,perl {file},
24
+ R,#,.R,Rscript {file},
25
+ MATLAB,%,.m,,
26
+ Lua,--,.lua,lua {file},
27
+ Haskell,--,.hs,runhaskell {file},
28
+ Scala,//,.scala,scala {file},
29
+ Groovy,//,.groovy,groovy {file},
30
+ Dart,//,.dart,dart run {file},
31
+ F#,//,.fs,dotnet fsi {file},
32
+ YAML,#,.yml,,
33
+ YAML,#,.yaml,,
34
+ JSON,del,.json,,
35
+ JSONL,del,.jsonl,,
36
+ XML,"<!-- -->",.xml,,
37
+ Makefile,#,,,
38
+ CSV,del,.csv,,
39
+ Markdown,del,.md,,
40
+ LaTeX,%,.tex,,
41
+ Assembly,;,.asm,,
42
+ Fortran,!,.f90,gfortran -o {file}.out {file} && ./{file}.out,
43
+ COBOL,*>,.cob,,
44
+ Lisp,;,.lisp,sbcl --script {file},
45
+ Prolog,%,.pl,swipl -s {file},
46
+ Erlang,%,.erl,escript {file},
47
+ Clojure,;,.clj,clojure {file},
48
+ Julia,#,.jl,julia {file},
49
+ Elixir,#,.ex,elixir {file},
50
+ Pascal,//,.pas,fpc {file} && ./{file},
51
+ VBScript,"'",.vbs,cscript {file},
52
+ CoffeeScript,#,.coffee,coffee {file},
53
+ Objective-C,//,.m,,
54
+ Scheme,;,.scm,scheme --script {file},
55
+ Tcl,#,.tcl,tclsh {file},
56
+ D,//,.d,rdmd {file},
57
+ Ada,--,.ada,,
58
+ Nim,#,.nim,nim r {file},
59
+ OCaml,"(**)",.ml,ocaml {file},
60
+ LLM,del,.prompt,,
61
+ prompt,del,.prompt,,
62
+ TOML,#,.toml,,
63
+ Log,del,.log,,
64
+ reStructuredText,del,.rst,,
65
+ Text,del,.txt,,
66
+ INI,;,.ini,,
67
+ Verilog,//,.v,,
68
+ Systemverilog,//,.sv,,
69
+ Prisma,///,.prisma,,
70
+ Lean,--,.lean,lean {file},
71
+ Agda,--,.agda,,
pdd/data/llm_model.csv CHANGED
@@ -1,18 +1,20 @@
1
- provider,model,input,output,coding_arena_elo,base_url,api_key,max_reasoning_tokens,structured_output,reasoning_type
2
- OpenAI,gpt-4.1-nano,0.1,0.4,1249,,OPENAI_API_KEY,0,True,none
3
- xai,xai/grok-3-beta,3.0,15.0,1332,https://api.x.ai/v1,XAI_API_KEY,0,False,none
4
- Anthropic,claude-3-5-haiku-20241022,.8,4,1261,,ANTHROPIC_API_KEY,0,True,none
5
- OpenAI,deepseek/deepseek-chat,.27,1.1,1353,https://api.deepseek.com/beta,DEEPSEEK_API_KEY,0,False,none
6
- Google,vertex_ai/gemini-2.5-flash,0.15,0.6,1330,,VERTEX_CREDENTIALS,0,True,effort
7
- Google,gemini-2.5-pro,1.25,10.0,1360,,GOOGLE_API_KEY,0,True,none
8
- Anthropic,claude-sonnet-4-20250514,3.0,15.0,1340,,ANTHROPIC_API_KEY,64000,True,budget
9
- Google,vertex_ai/gemini-2.5-pro,1.25,10.0,1361,,VERTEX_CREDENTIALS,0,True,none
10
- OpenAI,o4-mini,1.1,4.4,1333,,OPENAI_API_KEY,0,True,effort
11
- OpenAI,o3,10.0,40.0,1389,,OPENAI_API_KEY,0,True,effort
12
- OpenAI,gpt-4.1,2.0,8.0,1335,,OPENAI_API_KEY,0,True,none
13
- OpenAI,deepseek/deepseek-reasoner,0.55,2.19,1337,https://api.deepseek.com/beta,DEEPSEEK_API_KEY,0,False,none
14
- Fireworks,fireworks_ai/accounts/fireworks/models/deepseek-r1,3.0,8.0,1338,,FIREWORKS_API_KEY,0,False,none
15
- OpenAI,chatgpt-4o-latest,5,15,1369,,OPENAI_API_KEY,0,False,none
16
- Anthropic,bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0,3.0,15.0,1339,,,64000,True,budget
17
- OpenAI,azure/o4-mini,1.1,4.4,1334,,OPENAI_API_KEY,0,True,effort
18
- OpenAI,openai/mlx-community/Qwen3-30B-A3B-4bit,0,0,1293,http://localhost:8080,,0,False,none
1
+ provider,model,input,output,coding_arena_elo,base_url,api_key,max_reasoning_tokens,structured_output,reasoning_type,location
2
+ OpenAI,gpt-5-nano,0.05,0.4,1249,,OPENAI_API_KEY,0,True,none,
3
+ Google,vertex_ai/gemini-3-flash-preview,0.5,3.0,1430,,VERTEX_CREDENTIALS,0,True,effort,global
4
+ Google,gemini/gemini-3-pro-preview,1.25,10.0,1487,,GEMINI_API_KEY,0,True,effort,
5
+ Google,vertex_ai/claude-sonnet-4-5,3.0,15.0,1370,,VERTEX_CREDENTIALS,128000,True,budget,
6
+ Google,vertex_ai/gemini-3-pro-preview,1.25,10.0,1487,,VERTEX_CREDENTIALS,0,True,effort,
7
+ OpenAI,gpt-5.1-codex-mini,0.25,2.0,1325,,OPENAI_API_KEY,0,True,effort,
8
+ OpenAI,gpt-5.2,1.75,14.0,1486,,OPENAI_API_KEY,0,True,effort,
9
+ OpenAI,gpt-5.1-codex,1.25,10.0,1478,,OPENAI_API_KEY,0,True,effort,
10
+ OpenAI,gpt-5.1-codex-max,1.25,10.0,1480,,OPENAI_API_KEY,0,True,effort,
11
+ Google,vertex_ai/deepseek-ai/deepseek-v3.2-maas,0.28,0.42,1450,,VERTEX_CREDENTIALS,0,True,effort,global
12
+ Fireworks,fireworks_ai/accounts/fireworks/models/qwen3-coder-480b-a35b-instruct,0.45,1.80,1363,,FIREWORKS_API_KEY,0,False,none,
13
+ Google,vertex_ai/claude-opus-4-5,5.0,25.0,1465,,VERTEX_CREDENTIALS,128000,True,budget,global
14
+ OpenAI,openai/mlx-community/Qwen3-30B-A3B-4bit,0,0,1040,http://localhost:8080,,0,False,none,
15
+ lm_studio,lm_studio/openai-gpt-oss-120b-mlx-6,0.0001,0,1082,http://localhost:1234/v1,,0,True,effort,
16
+ Fireworks,fireworks_ai/accounts/fireworks/models/glm-4p7,0.60,2.20,1481,,FIREWORKS_API_KEY,0,False,none,
17
+ OpenAI,groq/moonshotai/kimi-k2-instruct-0905,1.0,3.0,1330,,GROQ_API_KEY,0,True,none,
18
+ Anthropic,anthropic/claude-sonnet-4-5-20250929,3.0,15.0,1370,,ANTHROPIC_API_KEY,128000,True,budget,
19
+ Anthropic,anthropic/claude-opus-4-5-20251101,5.0,25.0,1474,,ANTHROPIC_API_KEY,128000,True,budget,
20
+ Anthropic,anthropic/claude-haiku-4-5-20251001,1.0,5.0,1270,,ANTHROPIC_API_KEY,128000,True,budget,