pdd-cli 0.0.90__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 (144) hide show
  1. pdd/__init__.py +38 -6
  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 +521 -786
  7. pdd/agentic_e2e_fix.py +319 -0
  8. pdd/agentic_e2e_fix_orchestrator.py +426 -0
  9. pdd/agentic_fix.py +118 -3
  10. pdd/agentic_update.py +25 -8
  11. pdd/architecture_sync.py +565 -0
  12. pdd/auth_service.py +210 -0
  13. pdd/auto_deps_main.py +63 -53
  14. pdd/auto_include.py +185 -3
  15. pdd/auto_update.py +125 -47
  16. pdd/bug_main.py +195 -23
  17. pdd/cmd_test_main.py +345 -197
  18. pdd/code_generator.py +4 -2
  19. pdd/code_generator_main.py +118 -32
  20. pdd/commands/__init__.py +6 -0
  21. pdd/commands/analysis.py +87 -29
  22. pdd/commands/auth.py +309 -0
  23. pdd/commands/connect.py +290 -0
  24. pdd/commands/fix.py +136 -113
  25. pdd/commands/maintenance.py +3 -2
  26. pdd/commands/misc.py +8 -0
  27. pdd/commands/modify.py +190 -164
  28. pdd/commands/sessions.py +284 -0
  29. pdd/construct_paths.py +334 -32
  30. pdd/context_generator_main.py +167 -170
  31. pdd/continue_generation.py +6 -3
  32. pdd/core/__init__.py +33 -0
  33. pdd/core/cli.py +27 -3
  34. pdd/core/cloud.py +237 -0
  35. pdd/core/errors.py +4 -0
  36. pdd/core/remote_session.py +61 -0
  37. pdd/crash_main.py +219 -23
  38. pdd/data/llm_model.csv +4 -4
  39. pdd/docs/prompting_guide.md +864 -0
  40. pdd/docs/whitepaper_with_benchmarks/data_and_functions/benchmark_analysis.py +495 -0
  41. pdd/docs/whitepaper_with_benchmarks/data_and_functions/creation_compare.py +528 -0
  42. pdd/fix_code_loop.py +208 -34
  43. pdd/fix_code_module_errors.py +6 -2
  44. pdd/fix_error_loop.py +291 -38
  45. pdd/fix_main.py +204 -4
  46. pdd/fix_verification_errors_loop.py +235 -26
  47. pdd/fix_verification_main.py +269 -83
  48. pdd/frontend/dist/assets/index-B5DZHykP.css +1 -0
  49. pdd/frontend/dist/assets/index-DQ3wkeQ2.js +449 -0
  50. pdd/frontend/dist/index.html +376 -0
  51. pdd/frontend/dist/logo.svg +33 -0
  52. pdd/generate_output_paths.py +46 -5
  53. pdd/generate_test.py +212 -151
  54. pdd/get_comment.py +19 -44
  55. pdd/get_extension.py +8 -9
  56. pdd/get_jwt_token.py +309 -20
  57. pdd/get_language.py +8 -7
  58. pdd/get_run_command.py +7 -5
  59. pdd/insert_includes.py +2 -1
  60. pdd/llm_invoke.py +459 -95
  61. pdd/load_prompt_template.py +15 -34
  62. pdd/path_resolution.py +140 -0
  63. pdd/postprocess.py +4 -1
  64. pdd/preprocess.py +68 -12
  65. pdd/preprocess_main.py +33 -1
  66. pdd/prompts/agentic_bug_step10_pr_LLM.prompt +182 -0
  67. pdd/prompts/agentic_bug_step1_duplicate_LLM.prompt +73 -0
  68. pdd/prompts/agentic_bug_step2_docs_LLM.prompt +129 -0
  69. pdd/prompts/agentic_bug_step3_triage_LLM.prompt +95 -0
  70. pdd/prompts/agentic_bug_step4_reproduce_LLM.prompt +97 -0
  71. pdd/prompts/agentic_bug_step5_root_cause_LLM.prompt +123 -0
  72. pdd/prompts/agentic_bug_step6_test_plan_LLM.prompt +107 -0
  73. pdd/prompts/agentic_bug_step7_generate_LLM.prompt +172 -0
  74. pdd/prompts/agentic_bug_step8_verify_LLM.prompt +119 -0
  75. pdd/prompts/agentic_bug_step9_e2e_test_LLM.prompt +289 -0
  76. pdd/prompts/agentic_change_step10_identify_issues_LLM.prompt +1006 -0
  77. pdd/prompts/agentic_change_step11_fix_issues_LLM.prompt +984 -0
  78. pdd/prompts/agentic_change_step12_create_pr_LLM.prompt +131 -0
  79. pdd/prompts/agentic_change_step1_duplicate_LLM.prompt +73 -0
  80. pdd/prompts/agentic_change_step2_docs_LLM.prompt +101 -0
  81. pdd/prompts/agentic_change_step3_research_LLM.prompt +126 -0
  82. pdd/prompts/agentic_change_step4_clarify_LLM.prompt +164 -0
  83. pdd/prompts/agentic_change_step5_docs_change_LLM.prompt +981 -0
  84. pdd/prompts/agentic_change_step6_devunits_LLM.prompt +1005 -0
  85. pdd/prompts/agentic_change_step7_architecture_LLM.prompt +1044 -0
  86. pdd/prompts/agentic_change_step8_analyze_LLM.prompt +1027 -0
  87. pdd/prompts/agentic_change_step9_implement_LLM.prompt +1077 -0
  88. pdd/prompts/agentic_e2e_fix_step1_unit_tests_LLM.prompt +90 -0
  89. pdd/prompts/agentic_e2e_fix_step2_e2e_tests_LLM.prompt +91 -0
  90. pdd/prompts/agentic_e2e_fix_step3_root_cause_LLM.prompt +89 -0
  91. pdd/prompts/agentic_e2e_fix_step4_fix_e2e_tests_LLM.prompt +96 -0
  92. pdd/prompts/agentic_e2e_fix_step5_identify_devunits_LLM.prompt +91 -0
  93. pdd/prompts/agentic_e2e_fix_step6_create_unit_tests_LLM.prompt +106 -0
  94. pdd/prompts/agentic_e2e_fix_step7_verify_tests_LLM.prompt +116 -0
  95. pdd/prompts/agentic_e2e_fix_step8_run_pdd_fix_LLM.prompt +120 -0
  96. pdd/prompts/agentic_e2e_fix_step9_verify_all_LLM.prompt +146 -0
  97. pdd/prompts/agentic_fix_primary_LLM.prompt +2 -2
  98. pdd/prompts/agentic_update_LLM.prompt +192 -338
  99. pdd/prompts/auto_include_LLM.prompt +22 -0
  100. pdd/prompts/change_LLM.prompt +3093 -1
  101. pdd/prompts/detect_change_LLM.prompt +571 -14
  102. pdd/prompts/fix_code_module_errors_LLM.prompt +8 -0
  103. pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +1 -0
  104. pdd/prompts/generate_test_LLM.prompt +20 -1
  105. pdd/prompts/generate_test_from_example_LLM.prompt +115 -0
  106. pdd/prompts/insert_includes_LLM.prompt +262 -252
  107. pdd/prompts/prompt_code_diff_LLM.prompt +119 -0
  108. pdd/prompts/prompt_diff_LLM.prompt +82 -0
  109. pdd/remote_session.py +876 -0
  110. pdd/server/__init__.py +52 -0
  111. pdd/server/app.py +335 -0
  112. pdd/server/click_executor.py +587 -0
  113. pdd/server/executor.py +338 -0
  114. pdd/server/jobs.py +661 -0
  115. pdd/server/models.py +241 -0
  116. pdd/server/routes/__init__.py +31 -0
  117. pdd/server/routes/architecture.py +451 -0
  118. pdd/server/routes/auth.py +364 -0
  119. pdd/server/routes/commands.py +929 -0
  120. pdd/server/routes/config.py +42 -0
  121. pdd/server/routes/files.py +603 -0
  122. pdd/server/routes/prompts.py +1322 -0
  123. pdd/server/routes/websocket.py +473 -0
  124. pdd/server/security.py +243 -0
  125. pdd/server/terminal_spawner.py +209 -0
  126. pdd/server/token_counter.py +222 -0
  127. pdd/summarize_directory.py +236 -237
  128. pdd/sync_animation.py +8 -4
  129. pdd/sync_determine_operation.py +329 -47
  130. pdd/sync_main.py +272 -28
  131. pdd/sync_orchestration.py +136 -75
  132. pdd/template_expander.py +161 -0
  133. pdd/templates/architecture/architecture_json.prompt +41 -46
  134. pdd/trace.py +1 -1
  135. pdd/track_cost.py +0 -13
  136. pdd/unfinished_prompt.py +2 -1
  137. pdd/update_main.py +23 -5
  138. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.118.dist-info}/METADATA +15 -10
  139. pdd_cli-0.0.118.dist-info/RECORD +227 -0
  140. pdd_cli-0.0.90.dist-info/RECORD +0 -153
  141. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.118.dist-info}/WHEEL +0 -0
  142. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.118.dist-info}/entry_points.txt +0 -0
  143. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.118.dist-info}/licenses/LICENSE +0 -0
  144. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.118.dist-info}/top_level.txt +0 -0
pdd/commands/modify.py CHANGED
@@ -1,32 +1,28 @@
1
- """
2
- Modify commands (change, split, update).
3
- """
4
- import click
1
+ from __future__ import annotations
2
+
3
+ import sys
5
4
  from pathlib import Path
6
- from typing import Dict, Optional, Tuple, Union
5
+ from typing import Optional, Tuple, Any
6
+
7
+ import click
8
+ from rich.console import Console
7
9
 
10
+ # Relative imports from parent package
8
11
  from ..split_main import split_main
9
12
  from ..change_main import change_main
13
+ from ..agentic_change import run_agentic_change
10
14
  from ..update_main import update_main
11
15
  from ..track_cost import track_cost
12
16
  from ..core.errors import handle_error
13
17
 
14
- @click.command("split")
15
- @click.argument("input_prompt", type=click.Path(exists=True, dir_okay=False))
16
- @click.argument("input_code", type=click.Path(exists=True, dir_okay=False))
17
- @click.argument("example_code", type=click.Path(exists=True, dir_okay=False))
18
- @click.option(
19
- "--output-sub",
20
- type=click.Path(writable=True),
21
- default=None,
22
- help="Specify where to save the generated sub-prompt file (file or directory).",
23
- )
24
- @click.option(
25
- "--output-modified",
26
- type=click.Path(writable=True),
27
- default=None,
28
- help="Specify where to save the modified prompt file (file or directory).",
29
- )
18
+ console = Console()
19
+
20
+ @click.command()
21
+ @click.argument("input_prompt", type=click.Path(exists=True))
22
+ @click.argument("input_code", type=click.Path(exists=True))
23
+ @click.argument("example_code", type=click.Path(exists=True))
24
+ @click.option("--output-sub", help="Optional path for saving the sub-prompt.")
25
+ @click.option("--output-modified", help="Optional path for saving the modified prompt.")
30
26
  @click.pass_context
31
27
  @track_cost
32
28
  def split(
@@ -36,13 +32,15 @@ def split(
36
32
  example_code: str,
37
33
  output_sub: Optional[str],
38
34
  output_modified: Optional[str],
39
- ) -> Optional[Tuple[Dict[str, str], float, str]]:
40
- """Split large complex prompt files into smaller ones."""
41
- quiet = ctx.obj.get("quiet", False)
42
- command_name = "split"
35
+ ) -> Optional[Tuple[Any, float, str]]:
36
+ """
37
+ Split large complex prompt files into smaller, more manageable prompt files.
38
+ """
39
+ ctx.ensure_object(dict)
43
40
  try:
41
+ # Call split_main with required arguments
44
42
  result_data, total_cost, model_name = split_main(
45
- ctx=ctx,
43
+ ctx,
46
44
  input_prompt_file=input_prompt,
47
45
  input_code_file=input_code,
48
46
  example_code_file=example_code,
@@ -50,181 +48,209 @@ def split(
50
48
  output_modified=output_modified,
51
49
  )
52
50
  return result_data, total_cost, model_name
51
+
53
52
  except click.Abort:
54
53
  raise
55
54
  except Exception as e:
56
- handle_error(e, command_name, quiet)
55
+ handle_error(e, "split", ctx.obj.get("quiet", False))
57
56
  return None
58
57
 
59
58
 
60
- @click.command("change")
61
- @click.argument("change_prompt_file", type=click.Path(exists=True, dir_okay=False))
62
- @click.argument("input_code", type=click.Path(exists=True)) # Can be file or dir
63
- @click.argument("input_prompt_file", type=click.Path(exists=True, dir_okay=False), required=False)
64
- @click.option(
65
- "--budget",
66
- type=float,
67
- default=5.0,
68
- show_default=True,
69
- help="Maximum cost allowed for the change process.",
70
- )
71
- @click.option(
72
- "--output",
73
- type=click.Path(writable=True),
74
- default=None,
75
- help="Specify where to save the modified prompt file (file or directory).",
76
- )
77
- @click.option(
78
- "--csv",
79
- "use_csv",
80
- is_flag=True,
81
- default=False,
82
- help="Use a CSV file for batch change prompts.",
83
- )
59
+ @click.command()
60
+ @click.argument("args", nargs=-1)
61
+ @click.option("--manual", is_flag=True, default=False, help="Use legacy manual mode.")
62
+ @click.option("--budget", type=float, default=5.0, help="Budget for the operation.")
63
+ @click.option("--output", help="Output path.")
64
+ @click.option("--csv", is_flag=True, help="Use CSV input for batch processing.")
65
+ @click.option("--timeout-adder", type=float, default=0.0, help="Additional seconds to add to each step's timeout (agentic mode only).")
66
+ @click.option("--no-github-state", is_flag=True, default=False, help="Disable GitHub state persistence (agentic mode only).")
84
67
  @click.pass_context
85
68
  @track_cost
86
69
  def change(
87
70
  ctx: click.Context,
88
- change_prompt_file: str,
89
- input_code: str,
90
- input_prompt_file: Optional[str],
91
- output: Optional[str],
92
- use_csv: bool,
71
+ args: Tuple[str, ...],
72
+ manual: bool,
93
73
  budget: float,
94
- ) -> Optional[Tuple[Union[str, Dict], float, str]]:
95
- """Modify prompt(s) based on change instructions."""
96
- quiet = ctx.obj.get("quiet", False)
97
- command_name = "change"
74
+ output: Optional[str],
75
+ csv: bool,
76
+ timeout_adder: float,
77
+ no_github_state: bool,
78
+ ) -> Optional[Tuple[Any, float, str]]:
79
+ """
80
+ Modify an input prompt file based on a change prompt or issue.
81
+
82
+ Agentic Mode (default):
83
+ pdd change ISSUE_URL
84
+
85
+ Manual Mode (--manual):
86
+ pdd change --manual CHANGE_PROMPT_FILE INPUT_CODE_FILE [INPUT_PROMPT_FILE]
87
+ """
88
+ ctx.ensure_object(dict)
89
+
98
90
  try:
99
- # --- ADD VALIDATION LOGIC HERE ---
100
- input_code_path = Path(input_code) # Convert to Path object
101
- if use_csv:
102
- if not input_code_path.is_dir():
103
- raise click.UsageError("INPUT_CODE must be a directory when using --csv.")
104
- if input_prompt_file:
105
- raise click.UsageError("Cannot use --csv and specify an INPUT_PROMPT_FILE simultaneously.")
106
- else: # Not using CSV
107
- if not input_prompt_file:
108
- # This check might be better inside change_main, but can be here too
109
- raise click.UsageError("INPUT_PROMPT_FILE is required when not using --csv.")
110
- if not input_code_path.is_file():
111
- # This check might be better inside change_main, but can be here too
112
- raise click.UsageError("INPUT_CODE must be a file when not using --csv.")
113
- # --- END VALIDATION LOGIC ---
114
-
115
- result_data, total_cost, model_name = change_main(
116
- ctx=ctx,
117
- change_prompt_file=change_prompt_file,
118
- input_code=input_code,
119
- input_prompt_file=input_prompt_file,
120
- output=output,
121
- use_csv=use_csv,
122
- budget=budget,
123
- )
124
- return result_data, total_cost, model_name
91
+ # Set budget in context for manual mode usage
92
+ ctx.obj["budget"] = budget
93
+
94
+ quiet = ctx.obj.get("quiet", False)
95
+ verbose = ctx.obj.get("verbose", False)
96
+
97
+ if manual:
98
+ # Manual Mode Validation and Execution
99
+ if csv:
100
+ # CSV Mode: Expecting CSV_FILE and CODE_DIRECTORY (no input_prompt)
101
+ if len(args) == 3:
102
+ raise click.UsageError("Cannot use --csv and specify an INPUT_PROMPT_FILE simultaneously.")
103
+ if len(args) != 2:
104
+ raise click.UsageError("CSV mode requires 2 arguments: CSV_FILE CODE_DIRECTORY")
105
+
106
+ change_file, input_code = args
107
+ input_prompt = None
108
+
109
+ # CSV mode requires input_code to be a directory
110
+ if not Path(input_code).is_dir():
111
+ raise click.UsageError("INPUT_CODE must be a directory when using --csv")
112
+ else:
113
+ # Standard Manual Mode: Expecting 2 or 3 arguments
114
+ if len(args) == 3:
115
+ change_file, input_code, input_prompt = args
116
+ # Non-CSV mode requires input_code to be a file, not a directory
117
+ if Path(input_code).is_dir():
118
+ raise click.UsageError("INPUT_CODE must be a file when not using --csv")
119
+ elif len(args) == 2:
120
+ change_file, input_code = args
121
+ input_prompt = None
122
+ # Without CSV mode, input_prompt_file is required
123
+ raise click.UsageError("INPUT_PROMPT_FILE is required when not using --csv")
124
+ else:
125
+ raise click.UsageError(
126
+ "Manual mode requires 2 or 3 arguments: CHANGE_PROMPT INPUT_CODE [INPUT_PROMPT]"
127
+ )
128
+
129
+ # Validate file existence
130
+ if not Path(change_file).exists():
131
+ raise click.UsageError(f"Change file not found: {change_file}")
132
+ if not Path(input_code).exists():
133
+ raise click.UsageError(f"Input code path not found: {input_code}")
134
+ if input_prompt and not Path(input_prompt).exists():
135
+ raise click.UsageError(f"Input prompt file not found: {input_prompt}")
136
+
137
+ # Call change_main
138
+ result, cost, model = change_main(
139
+ ctx=ctx,
140
+ change_prompt_file=change_file,
141
+ input_code=input_code,
142
+ input_prompt_file=input_prompt,
143
+ output=output,
144
+ use_csv=csv,
145
+ budget=budget
146
+ )
147
+ return result, cost, model
148
+
149
+ else:
150
+ # Agentic Mode Validation and Execution
151
+ if len(args) != 1:
152
+ raise click.UsageError("Agentic mode requires exactly 1 argument: ISSUE_URL")
153
+
154
+ issue_url = args[0]
155
+
156
+ # Call run_agentic_change
157
+ success, message, cost, model, changed_files = run_agentic_change(
158
+ issue_url=issue_url,
159
+ verbose=verbose,
160
+ quiet=quiet,
161
+ timeout_adder=timeout_adder,
162
+ use_github_state=not no_github_state
163
+ )
164
+
165
+ # Display results using click.echo as requested
166
+ if not quiet:
167
+ status = "Success" if success else "Failed"
168
+ click.echo(f"Status: {status}")
169
+ click.echo(f"Message: {message}")
170
+ click.echo(f"Cost: ${cost:.4f}")
171
+ click.echo(f"Model: {model}")
172
+ if changed_files:
173
+ click.echo("Changed files:")
174
+ for f in changed_files:
175
+ click.echo(f" - {f}")
176
+
177
+ return message, cost, model
178
+
125
179
  except click.Abort:
126
180
  raise
127
- except (click.UsageError, Exception) as e: # Catch specific and general exceptions
128
- handle_error(e, command_name, quiet)
181
+ except Exception as e:
182
+ handle_error(e, "change", ctx.obj.get("quiet", False))
129
183
  return None
130
184
 
131
185
 
132
- @click.command("update")
133
- @click.argument("input_prompt_file", type=click.Path(exists=True, dir_okay=False), required=False)
134
- @click.argument("modified_code_file", type=click.Path(exists=True, dir_okay=False), required=False)
135
- @click.argument("input_code_file", type=click.Path(exists=True, dir_okay=False), required=False)
136
- @click.option(
137
- "--output",
138
- type=click.Path(writable=True),
139
- default=None,
140
- help="Specify where to save the updated prompt file(s). For single files: saves to this specific path or directory. For repository mode: saves all prompts to this directory. If not specified, uses the original prompt location (single file) or 'prompts' directory (repository mode).",
141
- )
142
- @click.option(
143
- "--git",
144
- "use_git",
145
- is_flag=True,
146
- default=False,
147
- help="Use git history to find the original code file.",
148
- )
149
- @click.option(
150
- "--extensions",
151
- type=str,
152
- default=None,
153
- help="Comma-separated list of file extensions to update in repo mode (e.g., 'py,js,ts').",
154
- )
155
- @click.option(
156
- "--simple",
157
- is_flag=True,
158
- default=False,
159
- help="Use legacy 2-stage LLM update instead of agentic mode.",
160
- )
186
+ @click.command()
187
+ @click.argument("files", nargs=-1)
188
+ @click.option("--extensions", help="Comma-separated extensions for repo mode.")
189
+ @click.option("--directory", help="Directory to scan for repo mode.")
190
+ @click.option("--git", is_flag=True, help="Use git history for original code.")
191
+ @click.option("--output", help="Output path for the updated prompt.")
192
+ @click.option("--simple", is_flag=True, default=False, help="Use legacy simple update.")
161
193
  @click.pass_context
162
194
  @track_cost
163
195
  def update(
164
196
  ctx: click.Context,
165
- input_prompt_file: Optional[str],
166
- modified_code_file: Optional[str],
167
- input_code_file: Optional[str],
168
- output: Optional[str],
169
- use_git: bool,
197
+ files: Tuple[str, ...],
170
198
  extensions: Optional[str],
199
+ directory: Optional[str],
200
+ git: bool,
201
+ output: Optional[str],
171
202
  simple: bool,
172
- ) -> Optional[Tuple[str, float, str]]:
203
+ ) -> Optional[Tuple[Any, float, str]]:
173
204
  """
174
- Update prompts based on code changes.
175
-
176
- This command operates in two modes:
177
-
178
- 1. **Single-File Mode:** When you provide at least a code file, it updates
179
- or generates a single prompt.
180
- - `pdd update <CODE_FILE>`: Generates a new prompt for the code.
181
- - `pdd update [PROMPT_FILE] <CODE_FILE>`: Updates prompt based on code.
182
- - `pdd update [PROMPT_FILE] <CODE_FILE> <ORIGINAL_CODE_FILE>`: Updates prompt using explicit original code.
205
+ Update the original prompt file based on code changes.
183
206
 
184
- 2. **Repository-Wide Mode:** When you provide no file arguments, it scans the
185
- entire repository, finds all code/prompt pairs, creates missing prompts,
186
- and updates them all based on the latest git changes.
187
- - `pdd update`: Updates all prompts for modified files in the repo.
207
+ Repo-wide mode (no args): Scan entire repo.
208
+ Single-file mode (1 arg): Update prompt for specific code file.
188
209
  """
189
- quiet = ctx.obj.get("quiet", False)
190
- command_name = "update"
210
+ ctx.ensure_object(dict)
191
211
  try:
192
- # In single-file generation mode, when only one positional argument is provided,
193
- # it is treated as the code file (not the prompt file). This enables the workflow:
194
- # `pdd update <CODE_FILE>` to generate a new prompt for the given code file.
195
- # So if input_prompt_file has a value but modified_code_file is None,
196
- # we reassign input_prompt_file to actual_modified_code_file.
197
- if input_prompt_file is not None and modified_code_file is None:
198
- actual_modified_code_file = input_prompt_file
199
- actual_input_prompt_file = None
200
- else:
201
- actual_modified_code_file = modified_code_file
202
- actual_input_prompt_file = input_prompt_file
203
-
204
- is_repo_mode = actual_input_prompt_file is None and actual_modified_code_file is None
212
+ # Determine mode based on argument count
213
+ is_repo_mode = len(files) == 0
205
214
 
215
+ # Validate mode-specific options
206
216
  if is_repo_mode:
207
- if any([input_code_file, use_git]):
217
+ # Repo-wide mode: --git and --output are not allowed
218
+ if git:
219
+ raise click.UsageError(
220
+ "Cannot use file-specific arguments or flags like --git in repository-wide mode"
221
+ )
222
+ else:
223
+ # Single-file mode: --extensions and --directory are not allowed
224
+ if extensions:
208
225
  raise click.UsageError(
209
- "Cannot use file-specific arguments or flags like --git or --input-code in repository-wide mode (when no files are provided)."
226
+ "--extensions can only be used in repository-wide mode"
210
227
  )
211
- elif extensions:
212
- raise click.UsageError("--extensions can only be used in repository-wide mode (when no files are provided).")
228
+ if directory:
229
+ raise click.UsageError(
230
+ "--directory can only be used in repository-wide mode"
231
+ )
232
+
233
+ # In single-file mode, the one arg is the modified code file
234
+ modified_code_file = files[0] if len(files) > 0 else None
213
235
 
214
- result, total_cost, model_name = update_main(
236
+ # Call update_main with correct parameters
237
+ result, cost, model = update_main(
215
238
  ctx=ctx,
216
- input_prompt_file=actual_input_prompt_file,
217
- modified_code_file=actual_modified_code_file,
218
- input_code_file=input_code_file,
239
+ input_prompt_file=None,
240
+ modified_code_file=modified_code_file,
241
+ input_code_file=None,
219
242
  output=output,
220
- use_git=use_git,
243
+ use_git=git,
221
244
  repo=is_repo_mode,
222
245
  extensions=extensions,
223
- simple=simple,
246
+ directory=directory,
247
+ simple=simple
224
248
  )
225
- return result, total_cost, model_name
249
+
250
+ return result, cost, model
251
+
226
252
  except click.Abort:
227
253
  raise
228
- except (click.UsageError, Exception) as exception:
229
- handle_error(exception, command_name, quiet)
254
+ except Exception as e:
255
+ handle_error(e, "update", ctx.obj.get("quiet", False))
230
256
  return None