pdd-cli 0.0.42__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.
Files changed (119) hide show
  1. pdd/__init__.py +4 -4
  2. pdd/agentic_common.py +863 -0
  3. pdd/agentic_crash.py +534 -0
  4. pdd/agentic_fix.py +1179 -0
  5. pdd/agentic_langtest.py +162 -0
  6. pdd/agentic_update.py +370 -0
  7. pdd/agentic_verify.py +183 -0
  8. pdd/auto_deps_main.py +15 -5
  9. pdd/auto_include.py +63 -5
  10. pdd/bug_main.py +3 -2
  11. pdd/bug_to_unit_test.py +2 -0
  12. pdd/change_main.py +11 -4
  13. pdd/cli.py +22 -1181
  14. pdd/cmd_test_main.py +80 -19
  15. pdd/code_generator.py +58 -18
  16. pdd/code_generator_main.py +672 -25
  17. pdd/commands/__init__.py +42 -0
  18. pdd/commands/analysis.py +248 -0
  19. pdd/commands/fix.py +140 -0
  20. pdd/commands/generate.py +257 -0
  21. pdd/commands/maintenance.py +174 -0
  22. pdd/commands/misc.py +79 -0
  23. pdd/commands/modify.py +230 -0
  24. pdd/commands/report.py +144 -0
  25. pdd/commands/templates.py +215 -0
  26. pdd/commands/utility.py +110 -0
  27. pdd/config_resolution.py +58 -0
  28. pdd/conflicts_main.py +8 -3
  29. pdd/construct_paths.py +281 -81
  30. pdd/context_generator.py +10 -2
  31. pdd/context_generator_main.py +113 -11
  32. pdd/continue_generation.py +47 -7
  33. pdd/core/__init__.py +0 -0
  34. pdd/core/cli.py +503 -0
  35. pdd/core/dump.py +554 -0
  36. pdd/core/errors.py +63 -0
  37. pdd/core/utils.py +90 -0
  38. pdd/crash_main.py +44 -11
  39. pdd/data/language_format.csv +71 -62
  40. pdd/data/llm_model.csv +20 -18
  41. pdd/detect_change_main.py +5 -4
  42. pdd/fix_code_loop.py +331 -77
  43. pdd/fix_error_loop.py +209 -60
  44. pdd/fix_errors_from_unit_tests.py +4 -3
  45. pdd/fix_main.py +75 -18
  46. pdd/fix_verification_errors.py +12 -100
  47. pdd/fix_verification_errors_loop.py +319 -272
  48. pdd/fix_verification_main.py +57 -17
  49. pdd/generate_output_paths.py +93 -10
  50. pdd/generate_test.py +16 -5
  51. pdd/get_jwt_token.py +48 -9
  52. pdd/get_run_command.py +73 -0
  53. pdd/get_test_command.py +68 -0
  54. pdd/git_update.py +70 -19
  55. pdd/increase_tests.py +7 -0
  56. pdd/incremental_code_generator.py +2 -2
  57. pdd/insert_includes.py +11 -3
  58. pdd/llm_invoke.py +1278 -110
  59. pdd/load_prompt_template.py +36 -10
  60. pdd/pdd_completion.fish +25 -2
  61. pdd/pdd_completion.sh +30 -4
  62. pdd/pdd_completion.zsh +79 -4
  63. pdd/postprocess.py +10 -3
  64. pdd/preprocess.py +228 -15
  65. pdd/preprocess_main.py +8 -5
  66. pdd/prompts/agentic_crash_explore_LLM.prompt +49 -0
  67. pdd/prompts/agentic_fix_explore_LLM.prompt +45 -0
  68. pdd/prompts/agentic_fix_harvest_only_LLM.prompt +48 -0
  69. pdd/prompts/agentic_fix_primary_LLM.prompt +85 -0
  70. pdd/prompts/agentic_update_LLM.prompt +1071 -0
  71. pdd/prompts/agentic_verify_explore_LLM.prompt +45 -0
  72. pdd/prompts/auto_include_LLM.prompt +98 -101
  73. pdd/prompts/change_LLM.prompt +1 -3
  74. pdd/prompts/detect_change_LLM.prompt +562 -3
  75. pdd/prompts/example_generator_LLM.prompt +22 -1
  76. pdd/prompts/extract_code_LLM.prompt +5 -1
  77. pdd/prompts/extract_program_code_fix_LLM.prompt +14 -2
  78. pdd/prompts/extract_prompt_update_LLM.prompt +7 -8
  79. pdd/prompts/extract_promptline_LLM.prompt +17 -11
  80. pdd/prompts/find_verification_errors_LLM.prompt +6 -0
  81. pdd/prompts/fix_code_module_errors_LLM.prompt +16 -4
  82. pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +6 -41
  83. pdd/prompts/fix_verification_errors_LLM.prompt +22 -0
  84. pdd/prompts/generate_test_LLM.prompt +21 -6
  85. pdd/prompts/increase_tests_LLM.prompt +1 -2
  86. pdd/prompts/insert_includes_LLM.prompt +1181 -6
  87. pdd/prompts/split_LLM.prompt +1 -62
  88. pdd/prompts/trace_LLM.prompt +25 -22
  89. pdd/prompts/unfinished_prompt_LLM.prompt +85 -1
  90. pdd/prompts/update_prompt_LLM.prompt +22 -1
  91. pdd/prompts/xml_convertor_LLM.prompt +3246 -7
  92. pdd/pytest_output.py +188 -21
  93. pdd/python_env_detector.py +151 -0
  94. pdd/render_mermaid.py +236 -0
  95. pdd/setup_tool.py +648 -0
  96. pdd/simple_math.py +2 -0
  97. pdd/split_main.py +3 -2
  98. pdd/summarize_directory.py +56 -7
  99. pdd/sync_determine_operation.py +918 -186
  100. pdd/sync_main.py +82 -32
  101. pdd/sync_orchestration.py +1456 -453
  102. pdd/sync_tui.py +848 -0
  103. pdd/template_registry.py +264 -0
  104. pdd/templates/architecture/architecture_json.prompt +242 -0
  105. pdd/templates/generic/generate_prompt.prompt +174 -0
  106. pdd/trace.py +168 -12
  107. pdd/trace_main.py +4 -3
  108. pdd/track_cost.py +151 -61
  109. pdd/unfinished_prompt.py +49 -3
  110. pdd/update_main.py +549 -67
  111. pdd/update_model_costs.py +2 -2
  112. pdd/update_prompt.py +19 -4
  113. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/METADATA +20 -7
  114. pdd_cli-0.0.90.dist-info/RECORD +153 -0
  115. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/licenses/LICENSE +1 -1
  116. pdd_cli-0.0.42.dist-info/RECORD +0 -115
  117. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/WHEEL +0 -0
  118. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/entry_points.txt +0 -0
  119. {pdd_cli-0.0.42.dist-info → pdd_cli-0.0.90.dist-info}/top_level.txt +0 -0
pdd/agentic_verify.py ADDED
@@ -0,0 +1,183 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import re
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from rich.console import Console
10
+
11
+ from .agentic_common import run_agentic_task
12
+ from .load_prompt_template import load_prompt_template
13
+
14
+ console = Console()
15
+
16
+
17
+ def _get_file_mtimes(root: Path) -> dict[Path, float]:
18
+ """
19
+ Recursively scan the directory to record file modification times.
20
+ Excludes common ignored directories like .git, __pycache__, .venv, etc.
21
+ """
22
+ mtimes = {}
23
+ ignore_dirs = {".git", "__pycache__", ".venv", "venv", "node_modules", ".idea", ".vscode"}
24
+
25
+ for path in root.rglob("*"):
26
+ # Skip ignored directories
27
+ if any(part in ignore_dirs for part in path.parts):
28
+ continue
29
+
30
+ if path.is_file():
31
+ try:
32
+ mtimes[path] = path.stat().st_mtime
33
+ except OSError:
34
+ # Handle cases where file might disappear or be inaccessible during scan
35
+ continue
36
+ return mtimes
37
+
38
+
39
+ def _extract_json_from_text(text: str) -> dict[str, Any] | None:
40
+ """
41
+ Attempts to extract a JSON object from a string.
42
+ Handles Markdown code blocks and raw JSON.
43
+ """
44
+ # Try to find JSON within markdown code blocks first
45
+ json_block_pattern = r"```(?:json)?\s*(\{.*?\})\s*```"
46
+ match = re.search(json_block_pattern, text, re.DOTALL)
47
+
48
+ if match:
49
+ json_str = match.group(1)
50
+ else:
51
+ # Try to find the first opening brace and last closing brace
52
+ start = text.find("{")
53
+ end = text.rfind("}")
54
+ if start != -1 and end != -1 and end > start:
55
+ json_str = text[start : end + 1]
56
+ else:
57
+ return None
58
+
59
+ try:
60
+ return json.loads(json_str)
61
+ except json.JSONDecodeError:
62
+ return None
63
+
64
+
65
+ def run_agentic_verify(
66
+ prompt_file: Path,
67
+ code_file: Path,
68
+ program_file: Path,
69
+ verification_log_file: Path,
70
+ *,
71
+ verbose: bool = False,
72
+ quiet: bool = False,
73
+ ) -> tuple[bool, str, float, str, list[str]]:
74
+ """
75
+ Runs an agentic verification fallback.
76
+
77
+ This function delegates the verification fix to a CLI agent (explore mode).
78
+ It records file changes, parses the agent's JSON output, and returns the results.
79
+
80
+ Args:
81
+ prompt_file: Path to the prompt specification file.
82
+ code_file: Path to the generated code file.
83
+ program_file: Path to the program/driver file.
84
+ verification_log_file: Path to the log containing previous failures.
85
+ verbose: Enable verbose logging.
86
+ quiet: Suppress standard output.
87
+
88
+ Returns:
89
+ Tuple containing:
90
+ - success (bool): Whether the agent claims success.
91
+ - message (str): The explanation or output message.
92
+ - cost (float): Estimated cost of the operation.
93
+ - model (str): The model/provider used.
94
+ - changed_files (list[str]): List of files modified during execution.
95
+ """
96
+ project_root = Path.cwd()
97
+
98
+ if not quiet:
99
+ console.print(f"[bold blue]Starting Agentic Verify (Explore Mode)[/bold blue]")
100
+ console.print(f"Context: {project_root}")
101
+
102
+ # 1. Load Prompt Template
103
+ template_name = "agentic_verify_explore_LLM"
104
+ template = load_prompt_template(template_name)
105
+
106
+ if not template:
107
+ error_msg = f"Failed to load prompt template: {template_name}"
108
+ console.print(f"[bold red]{error_msg}[/bold red]")
109
+ return False, error_msg, 0.0, "unknown", []
110
+
111
+ # 2. Prepare Context
112
+ if verification_log_file.exists():
113
+ previous_attempts = verification_log_file.read_text(encoding="utf-8")
114
+ else:
115
+ previous_attempts = "No previous verification logs found."
116
+
117
+ # 3. Format Instruction
118
+ instruction = template.format(
119
+ prompt_path=prompt_file.resolve(),
120
+ code_path=code_file.resolve(),
121
+ program_path=program_file.resolve(),
122
+ project_root=project_root.resolve(),
123
+ previous_attempts=previous_attempts
124
+ )
125
+
126
+ # 4. Record State Before Execution
127
+ mtimes_before = _get_file_mtimes(project_root)
128
+
129
+ # 5. Run Agentic Task
130
+ # We use the project root as the CWD so the agent can explore freely
131
+ agent_success, agent_output, cost, provider = run_agentic_task(
132
+ instruction=instruction,
133
+ cwd=project_root,
134
+ verbose=verbose,
135
+ quiet=quiet,
136
+ label="verify-explore"
137
+ )
138
+
139
+ # 6. Record State After Execution & Detect Changes
140
+ mtimes_after = _get_file_mtimes(project_root)
141
+ changed_files = []
142
+
143
+ for path, mtime in mtimes_after.items():
144
+ # Check if file is new or modified
145
+ if path not in mtimes_before or mtimes_before[path] != mtime:
146
+ # Store relative path for cleaner output
147
+ try:
148
+ rel_path = path.relative_to(project_root)
149
+ changed_files.append(str(rel_path))
150
+ except ValueError:
151
+ changed_files.append(str(path))
152
+
153
+ # 7. Parse Agent Output
154
+ # The agent is instructed to return JSON.
155
+ parsed_data = _extract_json_from_text(agent_output)
156
+
157
+ final_success = False
158
+ final_message = agent_output
159
+
160
+ if parsed_data:
161
+ # Trust the agent's self-reported success if JSON is valid
162
+ final_success = parsed_data.get("success", False)
163
+ final_message = parsed_data.get("message", agent_output)
164
+
165
+ # We prefer our calculated changed_files, but if we found none and the agent
166
+ # claims to have changed some (and they exist), we could log that discrepancy.
167
+ # For now, we stick to the physical reality of mtimes.
168
+ else:
169
+ # Fallback if agent didn't output valid JSON but the CLI tool reported success
170
+ if verbose:
171
+ console.print("[yellow]Warning: Could not parse JSON from agent output. Using raw output.[/yellow]")
172
+
173
+ # If the CLI tool failed (agent_success is False), we definitely failed.
174
+ # If the CLI tool succeeded, we still default to False because we couldn't verify the JSON contract.
175
+ final_success = False
176
+
177
+ if not quiet:
178
+ status_color = "green" if final_success else "red"
179
+ console.print(f"[{status_color}]Agentic Verify Finished. Success: {final_success}[/{status_color}]")
180
+ if changed_files:
181
+ console.print(f"Changed files: {', '.join(changed_files)}")
182
+
183
+ return final_success, final_message, cost, provider, changed_files
pdd/auto_deps_main.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Main function for the auto-deps command."""
2
2
  import sys
3
3
  from pathlib import Path
4
- from typing import Tuple, Optional
4
+ from typing import Callable, Tuple, Optional
5
5
  import click
6
6
  from rich import print as rprint
7
7
 
@@ -15,7 +15,8 @@ def auto_deps_main( # pylint: disable=too-many-arguments, too-many-locals
15
15
  directory_path: str,
16
16
  auto_deps_csv_path: Optional[str],
17
17
  output: Optional[str],
18
- force_scan: Optional[bool]
18
+ force_scan: Optional[bool],
19
+ progress_callback: Optional[Callable[[int, int], None]] = None
19
20
  ) -> Tuple[str, float, str]:
20
21
  """
21
22
  Main function to analyze and insert dependencies into a prompt file.
@@ -27,6 +28,7 @@ def auto_deps_main( # pylint: disable=too-many-arguments, too-many-locals
27
28
  auto_deps_csv_path: Path to CSV file containing auto-dependency information.
28
29
  output: Optional path to save the modified prompt file.
29
30
  force_scan: Flag to force rescan of directory by deleting CSV file.
31
+ progress_callback: Callback for progress updates (current, total) for each file.
30
32
 
31
33
  Returns:
32
34
  Tuple containing:
@@ -49,7 +51,9 @@ def auto_deps_main( # pylint: disable=too-many-arguments, too-many-locals
49
51
  force=ctx.obj.get('force', False),
50
52
  quiet=ctx.obj.get('quiet', False),
51
53
  command="auto-deps",
52
- command_options=command_options
54
+ command_options=command_options,
55
+ context_override=ctx.obj.get('context'),
56
+ confirm_callback=ctx.obj.get('confirm_callback')
53
57
  )
54
58
 
55
59
  # Get the CSV file path
@@ -74,10 +78,12 @@ def auto_deps_main( # pylint: disable=too-many-arguments, too-many-locals
74
78
  input_prompt=input_strings["prompt_file"],
75
79
  directory_path=directory_path,
76
80
  csv_filename=csv_path,
81
+ prompt_filename=prompt_file,
77
82
  strength=strength,
78
83
  temperature=temperature,
79
84
  time=time_budget,
80
- verbose=not ctx.obj.get('quiet', False)
85
+ verbose=not ctx.obj.get('quiet', False),
86
+ progress_callback=progress_callback
81
87
  )
82
88
 
83
89
  # Save the modified prompt to the output file
@@ -98,7 +104,11 @@ def auto_deps_main( # pylint: disable=too-many-arguments, too-many-locals
98
104
 
99
105
  return modified_prompt, total_cost, model_name
100
106
 
107
+ except click.Abort:
108
+ # User cancelled - re-raise to stop the sync loop
109
+ raise
101
110
  except Exception as exc:
102
111
  if not ctx.obj.get('quiet', False):
103
112
  rprint(f"[bold red]Error:[/bold red] {str(exc)}")
104
- sys.exit(1)
113
+ # Return error result instead of sys.exit(1) to allow orchestrator to handle gracefully
114
+ return "", 0.0, f"Error: {exc}"
pdd/auto_include.py CHANGED
@@ -2,8 +2,9 @@
2
2
  This module provides the `auto_include` function to automatically find and
3
3
  insert dependencies into a prompt.
4
4
  """
5
+ import re
5
6
  from io import StringIO
6
- from typing import Tuple, Optional
7
+ from typing import Callable, Tuple, Optional
7
8
 
8
9
  import pandas as pd
9
10
  from pydantic import BaseModel, Field
@@ -61,11 +62,17 @@ def _load_prompts() -> tuple[str, str]:
61
62
  return auto_include_prompt, extract_prompt
62
63
 
63
64
 
64
- def _summarize(directory_path: str, csv_file: Optional[str], llm_kwargs: dict) -> tuple[str, float, str]:
65
+ def _summarize(
66
+ directory_path: str,
67
+ csv_file: Optional[str],
68
+ llm_kwargs: dict,
69
+ progress_callback: Optional[Callable[[int, int], None]] = None
70
+ ) -> tuple[str, float, str]:
65
71
  """Summarize the directory."""
66
72
  return summarize_directory(
67
73
  directory_path=directory_path,
68
74
  csv_file=csv_file,
75
+ progress_callback=progress_callback,
69
76
  **llm_kwargs
70
77
  )
71
78
 
@@ -108,14 +115,57 @@ def _run_llm_and_extract(
108
115
  return dependencies, total_cost, model_name
109
116
 
110
117
 
118
+ def _extract_module_name(prompt_filename: Optional[str]) -> Optional[str]:
119
+ """Extract module name from prompt filename.
120
+
121
+ Handles various language suffixes:
122
+ - 'prompts/agentic_fix_python.prompt' -> 'agentic_fix'
123
+ - 'prompts/some_module_LLM.prompt' -> 'some_module'
124
+ - 'prompts/cli_bash.prompt' -> 'cli'
125
+
126
+ Args:
127
+ prompt_filename: The prompt filename to extract the module name from.
128
+
129
+ Returns:
130
+ The module name, or None if it cannot be extracted.
131
+ """
132
+ if not prompt_filename:
133
+ return None
134
+ # Pattern: captures module name before the last underscore + language + .prompt
135
+ # e.g., "agentic_fix_python.prompt" captures "agentic_fix"
136
+ match = re.search(r'([^/]+)_[^_]+\.prompt$', prompt_filename)
137
+ if match:
138
+ return match.group(1)
139
+ return None
140
+
141
+
142
+ def _filter_self_references(dependencies: str, module_name: Optional[str]) -> str:
143
+ """Remove includes that reference the module's own example file.
144
+
145
+ Args:
146
+ dependencies: The dependencies string containing include tags.
147
+ module_name: The module name to filter out self-references for.
148
+
149
+ Returns:
150
+ The dependencies string with self-referential includes removed.
151
+ """
152
+ if not module_name:
153
+ return dependencies
154
+ # Pattern matches: <...><include>context/{module_name}_example.py</include></...>
155
+ pattern = rf'<[^>]+><include>context/{re.escape(module_name)}_example\.py</include></[^>]+>\s*'
156
+ return re.sub(pattern, '', dependencies)
157
+
158
+
111
159
  def auto_include(
112
160
  input_prompt: str,
113
161
  directory_path: str,
114
162
  csv_file: Optional[str] = None,
163
+ prompt_filename: Optional[str] = None,
115
164
  strength: float = DEFAULT_STRENGTH,
116
165
  temperature: float = 0.0,
117
166
  time: float = DEFAULT_TIME,
118
- verbose: bool = False
167
+ verbose: bool = False,
168
+ progress_callback: Optional[Callable[[int, int], None]] = None
119
169
  ) -> Tuple[str, str, float, str]:
120
170
  """
121
171
  Automatically find and insert proper dependencies into the prompt.
@@ -124,10 +174,14 @@ def auto_include(
124
174
  input_prompt (str): The prompt requiring includes
125
175
  directory_path (str): Directory path of dependencies
126
176
  csv_file (Optional[str]): Contents of existing CSV file
177
+ prompt_filename (Optional[str]): The prompt filename being processed,
178
+ used to filter out self-referential example files
127
179
  strength (float): Strength of LLM model (0-1)
128
180
  temperature (float): Temperature of LLM model (0-1)
129
181
  time (float): Time budget for LLM calls
130
182
  verbose (bool): Whether to print detailed information
183
+ progress_callback (Optional[Callable[[int, int], None]]): Callback for progress updates.
184
+ Called with (current, total) for each file processed.
131
185
 
132
186
  Returns:
133
187
  Tuple[str, str, float, str]: (dependencies, csv_output, total_cost, model_name)
@@ -152,7 +206,7 @@ def auto_include(
152
206
  console.print(Panel("Step 2: Running summarize_directory", style="blue"))
153
207
 
154
208
  csv_output, summary_cost, summary_model = _summarize(
155
- directory_path, csv_file, llm_kwargs
209
+ directory_path, csv_file, llm_kwargs, progress_callback
156
210
  )
157
211
 
158
212
  available_includes = _get_available_includes_from_csv(csv_output)
@@ -167,7 +221,11 @@ def auto_include(
167
221
  available_includes=available_includes,
168
222
  llm_kwargs=llm_kwargs,
169
223
  )
170
-
224
+
225
+ # Filter out self-referential includes (module's own example file)
226
+ module_name = _extract_module_name(prompt_filename)
227
+ dependencies = _filter_self_references(dependencies, module_name)
228
+
171
229
  total_cost = summary_cost + llm_cost
172
230
  model_name = llm_model_name or summary_model
173
231
 
pdd/bug_main.py CHANGED
@@ -50,7 +50,8 @@ def bug_main(
50
50
  force=ctx.obj.get('force', False),
51
51
  quiet=ctx.obj.get('quiet', False),
52
52
  command="bug",
53
- command_options=command_options
53
+ command_options=command_options,
54
+ context_override=ctx.obj.get('context')
54
55
  )
55
56
 
56
57
  # Use the language detected by construct_paths if none was explicitly provided
@@ -117,4 +118,4 @@ def bug_main(
117
118
  except Exception as e:
118
119
  if not ctx.obj.get('quiet', False):
119
120
  rprint(f"[bold red]Error:[/bold red] {str(e)}")
120
- sys.exit(1)
121
+ sys.exit(1)
pdd/bug_to_unit_test.py CHANGED
@@ -108,6 +108,7 @@ def bug_to_unit_test( # pylint: disable=too-many-arguments, too-many-locals
108
108
  strength=0.89,
109
109
  temperature=temperature,
110
110
  time=time,
111
+ language=language,
111
112
  verbose=False,
112
113
  )
113
114
 
@@ -121,6 +122,7 @@ def bug_to_unit_test( # pylint: disable=too-many-arguments, too-many-locals
121
122
  strength=strength,
122
123
  temperature=temperature,
123
124
  time=time,
125
+ language=language,
124
126
  verbose=True,
125
127
  )
126
128
  total_cost += continued_cost
pdd/change_main.py CHANGED
@@ -17,11 +17,11 @@ from rich import print as rprint
17
17
  from rich.panel import Panel
18
18
 
19
19
  # Use relative imports for internal modules
20
+ from .config_resolution import resolve_effective_config
20
21
  from .construct_paths import construct_paths
21
22
  from .change import change as change_func
22
23
  from .process_csv_change import process_csv_change
23
24
  from .get_extension import get_extension
24
- from . import DEFAULT_STRENGTH, DEFAULT_TIME
25
25
 
26
26
  # Set up logging
27
27
  logger = logging.getLogger(__name__)
@@ -72,9 +72,8 @@ def change_main(
72
72
  # Retrieve global options from context
73
73
  force: bool = ctx.obj.get("force", False)
74
74
  quiet: bool = ctx.obj.get("quiet", False)
75
- strength: float = ctx.obj.get("strength", DEFAULT_STRENGTH)
76
- temperature: float = ctx.obj.get("temperature", 0.0)
77
- time_budget: float = ctx.obj.get("time", DEFAULT_TIME)
75
+ # Note: strength/temperature/time will be resolved after construct_paths
76
+ # using resolve_effective_config for proper priority handling
78
77
  # --- Get language and extension from context ---
79
78
  # These are crucial for knowing the target code file types, especially in CSV mode
80
79
  target_language: str = ctx.obj.get("language", "")
@@ -203,6 +202,7 @@ def change_main(
203
202
  quiet=quiet,
204
203
  command="change",
205
204
  command_options=command_options,
205
+ context_override=ctx.obj.get('context')
206
206
  )
207
207
  logger.debug("construct_paths returned:")
208
208
  logger.debug(" input_strings keys: %s", list(input_strings.keys()))
@@ -215,6 +215,13 @@ def change_main(
215
215
  logger.error(msg, exc_info=True)
216
216
  return msg, 0.0, ""
217
217
 
218
+ # Use centralized config resolution with proper priority:
219
+ # CLI > pddrc > defaults
220
+ effective_config = resolve_effective_config(ctx, resolved_config)
221
+ strength = effective_config["strength"]
222
+ temperature = effective_config["temperature"]
223
+ time_budget = effective_config["time"]
224
+
218
225
  # --- 3. Perform Prompt Modification ---
219
226
  if use_csv:
220
227
  logger.info("Running in CSV mode.")