pdd-cli 0.0.90__py3-none-any.whl → 0.0.121__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 (151) hide show
  1. pdd/__init__.py +38 -6
  2. pdd/agentic_bug.py +323 -0
  3. pdd/agentic_bug_orchestrator.py +506 -0
  4. pdd/agentic_change.py +231 -0
  5. pdd/agentic_change_orchestrator.py +537 -0
  6. pdd/agentic_common.py +533 -770
  7. pdd/agentic_crash.py +2 -1
  8. pdd/agentic_e2e_fix.py +319 -0
  9. pdd/agentic_e2e_fix_orchestrator.py +582 -0
  10. pdd/agentic_fix.py +118 -3
  11. pdd/agentic_update.py +27 -9
  12. pdd/agentic_verify.py +3 -2
  13. pdd/architecture_sync.py +565 -0
  14. pdd/auth_service.py +210 -0
  15. pdd/auto_deps_main.py +63 -53
  16. pdd/auto_include.py +236 -3
  17. pdd/auto_update.py +125 -47
  18. pdd/bug_main.py +195 -23
  19. pdd/cmd_test_main.py +345 -197
  20. pdd/code_generator.py +4 -2
  21. pdd/code_generator_main.py +118 -32
  22. pdd/commands/__init__.py +6 -0
  23. pdd/commands/analysis.py +113 -48
  24. pdd/commands/auth.py +309 -0
  25. pdd/commands/connect.py +358 -0
  26. pdd/commands/fix.py +155 -114
  27. pdd/commands/generate.py +5 -0
  28. pdd/commands/maintenance.py +3 -2
  29. pdd/commands/misc.py +8 -0
  30. pdd/commands/modify.py +225 -163
  31. pdd/commands/sessions.py +284 -0
  32. pdd/commands/utility.py +12 -7
  33. pdd/construct_paths.py +334 -32
  34. pdd/context_generator_main.py +167 -170
  35. pdd/continue_generation.py +6 -3
  36. pdd/core/__init__.py +33 -0
  37. pdd/core/cli.py +44 -7
  38. pdd/core/cloud.py +237 -0
  39. pdd/core/dump.py +68 -20
  40. pdd/core/errors.py +4 -0
  41. pdd/core/remote_session.py +61 -0
  42. pdd/crash_main.py +219 -23
  43. pdd/data/llm_model.csv +4 -4
  44. pdd/docs/prompting_guide.md +864 -0
  45. pdd/docs/whitepaper_with_benchmarks/data_and_functions/benchmark_analysis.py +495 -0
  46. pdd/docs/whitepaper_with_benchmarks/data_and_functions/creation_compare.py +528 -0
  47. pdd/fix_code_loop.py +208 -34
  48. pdd/fix_code_module_errors.py +6 -2
  49. pdd/fix_error_loop.py +291 -38
  50. pdd/fix_main.py +208 -6
  51. pdd/fix_verification_errors_loop.py +235 -26
  52. pdd/fix_verification_main.py +269 -83
  53. pdd/frontend/dist/assets/index-B5DZHykP.css +1 -0
  54. pdd/frontend/dist/assets/index-CUWd8al1.js +450 -0
  55. pdd/frontend/dist/index.html +376 -0
  56. pdd/frontend/dist/logo.svg +33 -0
  57. pdd/generate_output_paths.py +46 -5
  58. pdd/generate_test.py +212 -151
  59. pdd/get_comment.py +19 -44
  60. pdd/get_extension.py +8 -9
  61. pdd/get_jwt_token.py +309 -20
  62. pdd/get_language.py +8 -7
  63. pdd/get_run_command.py +7 -5
  64. pdd/insert_includes.py +2 -1
  65. pdd/llm_invoke.py +531 -97
  66. pdd/load_prompt_template.py +15 -34
  67. pdd/operation_log.py +342 -0
  68. pdd/path_resolution.py +140 -0
  69. pdd/postprocess.py +122 -97
  70. pdd/preprocess.py +68 -12
  71. pdd/preprocess_main.py +33 -1
  72. pdd/prompts/agentic_bug_step10_pr_LLM.prompt +182 -0
  73. pdd/prompts/agentic_bug_step1_duplicate_LLM.prompt +73 -0
  74. pdd/prompts/agentic_bug_step2_docs_LLM.prompt +129 -0
  75. pdd/prompts/agentic_bug_step3_triage_LLM.prompt +95 -0
  76. pdd/prompts/agentic_bug_step4_reproduce_LLM.prompt +97 -0
  77. pdd/prompts/agentic_bug_step5_root_cause_LLM.prompt +123 -0
  78. pdd/prompts/agentic_bug_step6_test_plan_LLM.prompt +107 -0
  79. pdd/prompts/agentic_bug_step7_generate_LLM.prompt +172 -0
  80. pdd/prompts/agentic_bug_step8_verify_LLM.prompt +119 -0
  81. pdd/prompts/agentic_bug_step9_e2e_test_LLM.prompt +289 -0
  82. pdd/prompts/agentic_change_step10_identify_issues_LLM.prompt +1006 -0
  83. pdd/prompts/agentic_change_step11_fix_issues_LLM.prompt +984 -0
  84. pdd/prompts/agentic_change_step12_create_pr_LLM.prompt +140 -0
  85. pdd/prompts/agentic_change_step1_duplicate_LLM.prompt +73 -0
  86. pdd/prompts/agentic_change_step2_docs_LLM.prompt +101 -0
  87. pdd/prompts/agentic_change_step3_research_LLM.prompt +126 -0
  88. pdd/prompts/agentic_change_step4_clarify_LLM.prompt +164 -0
  89. pdd/prompts/agentic_change_step5_docs_change_LLM.prompt +981 -0
  90. pdd/prompts/agentic_change_step6_devunits_LLM.prompt +1005 -0
  91. pdd/prompts/agentic_change_step7_architecture_LLM.prompt +1044 -0
  92. pdd/prompts/agentic_change_step8_analyze_LLM.prompt +1027 -0
  93. pdd/prompts/agentic_change_step9_implement_LLM.prompt +1077 -0
  94. pdd/prompts/agentic_e2e_fix_step1_unit_tests_LLM.prompt +90 -0
  95. pdd/prompts/agentic_e2e_fix_step2_e2e_tests_LLM.prompt +91 -0
  96. pdd/prompts/agentic_e2e_fix_step3_root_cause_LLM.prompt +89 -0
  97. pdd/prompts/agentic_e2e_fix_step4_fix_e2e_tests_LLM.prompt +96 -0
  98. pdd/prompts/agentic_e2e_fix_step5_identify_devunits_LLM.prompt +91 -0
  99. pdd/prompts/agentic_e2e_fix_step6_create_unit_tests_LLM.prompt +106 -0
  100. pdd/prompts/agentic_e2e_fix_step7_verify_tests_LLM.prompt +116 -0
  101. pdd/prompts/agentic_e2e_fix_step8_run_pdd_fix_LLM.prompt +120 -0
  102. pdd/prompts/agentic_e2e_fix_step9_verify_all_LLM.prompt +146 -0
  103. pdd/prompts/agentic_fix_primary_LLM.prompt +2 -2
  104. pdd/prompts/agentic_update_LLM.prompt +192 -338
  105. pdd/prompts/auto_include_LLM.prompt +22 -0
  106. pdd/prompts/change_LLM.prompt +3093 -1
  107. pdd/prompts/detect_change_LLM.prompt +571 -14
  108. pdd/prompts/fix_code_module_errors_LLM.prompt +8 -0
  109. pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +1 -0
  110. pdd/prompts/generate_test_LLM.prompt +19 -1
  111. pdd/prompts/generate_test_from_example_LLM.prompt +366 -0
  112. pdd/prompts/insert_includes_LLM.prompt +262 -252
  113. pdd/prompts/prompt_code_diff_LLM.prompt +123 -0
  114. pdd/prompts/prompt_diff_LLM.prompt +82 -0
  115. pdd/remote_session.py +876 -0
  116. pdd/server/__init__.py +52 -0
  117. pdd/server/app.py +335 -0
  118. pdd/server/click_executor.py +587 -0
  119. pdd/server/executor.py +338 -0
  120. pdd/server/jobs.py +661 -0
  121. pdd/server/models.py +241 -0
  122. pdd/server/routes/__init__.py +31 -0
  123. pdd/server/routes/architecture.py +451 -0
  124. pdd/server/routes/auth.py +364 -0
  125. pdd/server/routes/commands.py +929 -0
  126. pdd/server/routes/config.py +42 -0
  127. pdd/server/routes/files.py +603 -0
  128. pdd/server/routes/prompts.py +1347 -0
  129. pdd/server/routes/websocket.py +473 -0
  130. pdd/server/security.py +243 -0
  131. pdd/server/terminal_spawner.py +217 -0
  132. pdd/server/token_counter.py +222 -0
  133. pdd/summarize_directory.py +236 -237
  134. pdd/sync_animation.py +8 -4
  135. pdd/sync_determine_operation.py +329 -47
  136. pdd/sync_main.py +272 -28
  137. pdd/sync_orchestration.py +289 -211
  138. pdd/sync_order.py +304 -0
  139. pdd/template_expander.py +161 -0
  140. pdd/templates/architecture/architecture_json.prompt +41 -46
  141. pdd/trace.py +1 -1
  142. pdd/track_cost.py +0 -13
  143. pdd/unfinished_prompt.py +2 -1
  144. pdd/update_main.py +68 -26
  145. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/METADATA +15 -10
  146. pdd_cli-0.0.121.dist-info/RECORD +229 -0
  147. pdd_cli-0.0.90.dist-info/RECORD +0 -153
  148. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/WHEEL +0 -0
  149. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/entry_points.txt +0 -0
  150. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/licenses/LICENSE +0 -0
  151. {pdd_cli-0.0.90.dist-info → pdd_cli-0.0.121.dist-info}/top_level.txt +0 -0
pdd/commands/fix.py CHANGED
@@ -1,82 +1,49 @@
1
- """
2
- Fix command.
3
- """
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import sys
4
5
  import click
5
- from typing import Dict, List, Optional, Tuple, Any
6
+ from typing import Optional, Tuple, Any
7
+ from rich.console import Console
6
8
 
9
+ # Relative imports for internal modules
7
10
  from ..fix_main import fix_main
11
+ from ..agentic_e2e_fix import run_agentic_e2e_fix
8
12
  from ..track_cost import track_cost
13
+ from ..operation_log import log_operation
9
14
  from ..core.errors import handle_error
10
15
 
11
- @click.command("fix")
12
- @click.argument("prompt_file", type=click.Path(exists=True, dir_okay=False))
13
- @click.argument("code_file", type=click.Path(exists=True, dir_okay=False))
14
- @click.argument("unit_test_files", nargs=-1, type=click.Path(exists=True, dir_okay=False))
15
- @click.argument("error_file", type=click.Path(dir_okay=False)) # Allow non-existent for loop mode
16
- @click.option(
17
- "--output-test",
18
- type=click.Path(writable=True),
19
- default=None,
20
- help="Specify where to save the fixed unit test file (file or directory).",
21
- )
22
- @click.option(
23
- "--output-code",
24
- type=click.Path(writable=True),
25
- default=None,
26
- help="Specify where to save the fixed code file (file or directory).",
27
- )
28
- @click.option(
29
- "--output-results",
30
- type=click.Path(writable=True),
31
- default=None,
32
- help="Specify where to save the results log (file or directory).",
33
- )
34
- @click.option(
35
- "--loop",
36
- is_flag=True,
37
- default=False,
38
- help="Enable iterative fixing process."
39
- )
40
- @click.option(
41
- "--verification-program",
42
- type=click.Path(exists=True, dir_okay=False),
43
- default=None,
44
- help="Path to a Python program that verifies the fix.",
45
- )
46
- @click.option(
47
- "--max-attempts",
48
- type=int,
49
- default=3,
50
- show_default=True,
51
- help="Maximum number of fix attempts.",
52
- )
53
- @click.option(
54
- "--budget",
55
- type=float,
56
- default=5.0,
57
- show_default=True,
58
- help="Maximum cost allowed for the fixing process.",
59
- )
60
- @click.option(
61
- "--auto-submit",
62
- is_flag=True,
63
- default=False,
64
- help="Automatically submit the example if all unit tests pass.",
65
- )
66
- @click.option(
67
- "--agentic-fallback/--no-agentic-fallback",
68
- is_flag=True,
69
- default=True,
70
- help="Enable agentic fallback if the primary fix mechanism fails.",
71
- )
16
+ console = Console()
17
+
18
+ @click.command(name="fix")
19
+ @click.argument("args", nargs=-1)
20
+ @click.option("--manual", is_flag=True, help="Use manual mode with explicit file arguments.")
21
+ @click.option("--timeout-adder", type=float, default=0.0, help="Additional seconds to add to each step's timeout (Agentic mode).")
22
+ @click.option("--max-cycles", type=int, default=5, help="Maximum number of outer loop cycles (Agentic mode).")
23
+ @click.option("--resume/--no-resume", default=True, help="Resume from saved state if available (Agentic mode).")
24
+ @click.option("--force", is_flag=True, help="Override branch mismatch safety check (Agentic mode).")
25
+ @click.option("--no-github-state", is_flag=True, help="Disable GitHub issue comment-based state persistence (Agentic mode).")
26
+ @click.option("--output-test", type=click.Path(), help="Specify where to save the fixed unit test file.")
27
+ @click.option("--output-code", type=click.Path(), help="Specify where to save the fixed code file.")
28
+ @click.option("--output-results", type=click.Path(), help="Specify where to save the results log.")
29
+ @click.option("--loop", is_flag=True, help="Enable iterative fixing process.")
30
+ @click.option("--verification-program", type=click.Path(), help="Path to verification program (required for --loop).")
31
+ @click.option("--max-attempts", type=int, default=3, help="Maximum number of fix attempts.")
32
+ @click.option("--budget", type=float, default=5.0, help="Maximum cost allowed for the fixing process.")
33
+ @click.option("--auto-submit", is_flag=True, help="Automatically submit example if tests pass.")
34
+ @click.option("--agentic-fallback/--no-agentic-fallback", default=True, help="Enable agentic fallback in loop mode.")
72
35
  @click.pass_context
36
+ @log_operation(operation="fix", clears_run_report=True)
73
37
  @track_cost
74
38
  def fix(
75
39
  ctx: click.Context,
76
- prompt_file: str,
77
- code_file: str,
78
- unit_test_files: Tuple[str, ...],
79
- error_file: str,
40
+ args: Tuple[str, ...],
41
+ manual: bool,
42
+ timeout_adder: float,
43
+ max_cycles: int,
44
+ resume: bool,
45
+ force: bool,
46
+ no_github_state: bool,
80
47
  output_test: Optional[str],
81
48
  output_code: Optional[str],
82
49
  output_results: Optional[str],
@@ -86,55 +53,129 @@ def fix(
86
53
  budget: float,
87
54
  auto_submit: bool,
88
55
  agentic_fallback: bool,
89
- ) -> Optional[Tuple[Dict[str, Any], float, str]]:
90
- """Fix code based on a prompt and unit test errors.
56
+ ) -> Optional[Tuple[Any, float, str]]:
57
+ """
58
+ Fix errors in code and unit tests.
91
59
 
92
- Accepts one or more UNIT_TEST_FILES. Each test file is processed separately,
93
- allowing the AI to run and fix tests individually rather than as a concatenated blob.
60
+ Supports two modes:
61
+ 1. Agentic E2E Fix: pdd fix <GITHUB_ISSUE_URL>
62
+ 2. Manual Mode: pdd fix --manual PROMPT_FILE CODE_FILE UNIT_TEST_FILE... ERROR_FILE
94
63
  """
95
64
  try:
96
- all_results: List[Dict[str, Any]] = []
97
- total_cost = 0.0
98
- model_name = ""
65
+ if not args:
66
+ raise click.UsageError("Missing arguments. See 'pdd fix --help'.")
99
67
 
100
- # Process each unit test file separately
101
- for unit_test_file in unit_test_files:
102
- success, fixed_unit_test, fixed_code, attempts, cost, model = fix_main(
103
- ctx=ctx,
104
- prompt_file=prompt_file,
105
- code_file=code_file,
106
- unit_test_file=unit_test_file,
107
- error_file=error_file,
108
- output_test=output_test,
109
- output_code=output_code,
110
- output_results=output_results,
111
- loop=loop,
112
- verification_program=verification_program,
113
- max_attempts=max_attempts,
114
- budget=budget,
115
- auto_submit=auto_submit,
116
- agentic_fallback=agentic_fallback,
68
+ # Determine mode based on first argument
69
+ # If it looks like a URL and --manual is not set, use Agentic mode
70
+ is_url = args[0].startswith("http") or "github.com" in args[0]
71
+
72
+ # --- Agentic E2E Fix Mode ---
73
+ if is_url and not manual:
74
+ if len(args) > 1:
75
+ console.print("[yellow]Warning: Extra arguments ignored in Agentic E2E Fix mode.[/yellow]")
76
+
77
+ issue_url = args[0]
78
+ verbose = ctx.obj.get("verbose", False) if ctx.obj else False
79
+ quiet = ctx.obj.get("quiet", False) if ctx.obj else False
80
+
81
+ # Call the agentic fix workflow
82
+ success, message, cost, model, _ = run_agentic_e2e_fix(
83
+ issue_url=issue_url,
84
+ timeout_adder=timeout_adder,
85
+ max_cycles=max_cycles,
86
+ resume=resume,
87
+ force=force,
88
+ verbose=verbose,
89
+ quiet=quiet,
90
+ use_github_state=not no_github_state
117
91
  )
118
- all_results.append({
119
- "success": success,
120
- "fixed_unit_test": fixed_unit_test,
121
- "fixed_code": fixed_code,
122
- "attempts": attempts,
123
- "unit_test_file": unit_test_file,
124
- })
125
- total_cost += cost
126
- model_name = model
92
+
93
+ if not success:
94
+ console.print(f"[bold red]Agentic fix failed:[/bold red] {message}")
95
+ else:
96
+ console.print(f"[bold green]Agentic fix completed:[/bold green] {message}")
97
+
98
+ return message, cost, model
99
+
100
+ # --- Manual Mode ---
101
+ else:
102
+ # Validate arguments for manual mode
103
+ # Expected structure:
104
+ # - Loop mode: PROMPT_FILE CODE_FILE UNIT_TEST_FILE [UNIT_TEST_FILE...]
105
+ # - Non-loop mode: PROMPT_FILE CODE_FILE UNIT_TEST_FILE [UNIT_TEST_FILE...] ERROR_FILE
106
+ min_args = 3 if loop else 4
107
+ if len(args) < min_args:
108
+ if loop:
109
+ raise click.UsageError(
110
+ "Loop mode requires at least 3 arguments: PROMPT_FILE CODE_FILE UNIT_TEST_FILE..."
111
+ )
112
+ else:
113
+ raise click.UsageError(
114
+ "Non-loop mode requires at least 4 arguments: PROMPT_FILE CODE_FILE UNIT_TEST_FILE... ERROR_FILE"
115
+ )
116
+
117
+ prompt_file = args[0]
118
+ code_file = args[1]
119
+
120
+ # In loop mode, error_file is optional (generated during loop)
121
+ # In non-loop mode, last argument is the error_file
122
+ if loop:
123
+ error_file = None
124
+ unit_test_files = args[2:] # All remaining args are test files
125
+ else:
126
+ error_file = args[-1]
127
+ unit_test_files = args[2:-1] # All args between code file and error file
128
+
129
+ total_cost = 0.0
130
+ last_model = "unknown"
131
+ all_success = True
132
+ results_summary = []
133
+
134
+ # Process each unit test file
135
+ for i, test_file in enumerate(unit_test_files):
136
+ if len(unit_test_files) > 1:
137
+ console.print(f"[bold blue]Processing test file {i+1}/{len(unit_test_files)}: {test_file}[/bold blue]")
138
+
139
+ # Call the core fix logic
140
+ # Note: If multiple test files are processed, output_test will overwrite
141
+ # the same location if specified, as per documentation warning.
142
+ success, _, _, _, cost, model = fix_main(
143
+ ctx=ctx,
144
+ prompt_file=prompt_file,
145
+ code_file=code_file,
146
+ unit_test_file=test_file,
147
+ error_file=error_file,
148
+ output_test=output_test,
149
+ output_code=output_code,
150
+ output_results=output_results,
151
+ loop=loop,
152
+ verification_program=verification_program,
153
+ max_attempts=max_attempts,
154
+ budget=budget,
155
+ auto_submit=auto_submit,
156
+ agentic_fallback=agentic_fallback,
157
+ strength=None, # Use context defaults inside fix_main
158
+ temperature=None # Use context defaults inside fix_main
159
+ )
160
+
161
+ total_cost += cost
162
+ last_model = model
163
+ if not success:
164
+ all_success = False
165
+
166
+ status = "Fixed" if success else "Failed"
167
+ results_summary.append(f"{test_file}: {status}")
168
+
169
+ # Construct return message
170
+ summary_str = "\n".join(results_summary)
171
+ if all_success:
172
+ return f"All files processed successfully.\n{summary_str}", total_cost, last_model
173
+ else:
174
+ return f"Some files failed to fix.\n{summary_str}", total_cost, last_model
127
175
 
128
- # Aggregate results
129
- overall_success = all(r["success"] for r in all_results)
130
- result = {
131
- "success": overall_success,
132
- "results": all_results,
133
- "total_attempts": sum(r["attempts"] for r in all_results),
134
- }
135
- return result, total_cost, model_name
136
- except click.Abort:
176
+ except (click.Abort, click.UsageError, click.BadArgumentUsage, click.FileError, click.BadParameter):
137
177
  raise
138
- except Exception as exception:
139
- handle_error(exception, "fix", ctx.obj.get("quiet", False))
140
- ctx.exit(1)
178
+ except Exception as e:
179
+ quiet = ctx.obj.get("quiet", False) if ctx.obj else False
180
+ handle_error(e, "fix", quiet)
181
+ sys.exit(1)
pdd/commands/generate.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Generate, test, and example commands.
3
3
  """
4
+ from __future__ import annotations
4
5
  import click
5
6
  from typing import Dict, Optional, Tuple, List
6
7
 
@@ -9,6 +10,7 @@ from ..context_generator_main import context_generator_main
9
10
  from ..cmd_test_main import cmd_test_main
10
11
  from ..track_cost import track_cost
11
12
  from ..core.errors import handle_error, console
13
+ from ..operation_log import log_operation
12
14
 
13
15
  class GenerateCommand(click.Command):
14
16
  """Ensure help shows PROMPT_FILE as required even when validated at runtime."""
@@ -69,6 +71,7 @@ class GenerateCommand(click.Command):
69
71
  help="Do not automatically include test files found in the default tests directory.",
70
72
  )
71
73
  @click.pass_context
74
+ @log_operation("generate", clears_run_report=True, updates_fingerprint=True)
72
75
  @track_cost
73
76
  def generate(
74
77
  ctx: click.Context,
@@ -159,6 +162,7 @@ def generate(
159
162
  help="Specify where to save the generated example code (file or directory).",
160
163
  )
161
164
  @click.pass_context
165
+ @log_operation("example", updates_fingerprint=True)
162
166
  @track_cost
163
167
  def example(
164
168
  ctx: click.Context,
@@ -222,6 +226,7 @@ def example(
222
226
  help="Merge new tests with existing test file instead of creating a separate file.",
223
227
  )
224
228
  @click.pass_context
229
+ @log_operation("test", updates_run_report=True)
225
230
  @track_cost
226
231
  def test(
227
232
  ctx: click.Context,
@@ -39,8 +39,9 @@ from ..core.utils import _run_setup_utility
39
39
  )
40
40
  @click.option(
41
41
  "--target-coverage",
42
+ type=float,
42
43
  default=None,
43
- help="Desired code coverage percentage. Default: 10.0 or .pddrc value.",
44
+ help="Desired code coverage percentage. Default: 90.0 or .pddrc value.",
44
45
  )
45
46
  @click.option(
46
47
  "--dry-run",
@@ -64,7 +65,7 @@ def sync(
64
65
  budget: Optional[float],
65
66
  skip_verify: bool,
66
67
  skip_tests: bool,
67
- target_coverage: float,
68
+ target_coverage: Optional[float],
68
69
  dry_run: bool,
69
70
  log: bool,
70
71
  ) -> Optional[Tuple[str, float, str]]:
pdd/commands/misc.py CHANGED
@@ -39,6 +39,12 @@ from ..core.errors import handle_error
39
39
  default=None,
40
40
  help="List of keys to exclude from curly bracket doubling.",
41
41
  )
42
+ @click.option(
43
+ "--pdd-tags",
44
+ is_flag=True,
45
+ default=False,
46
+ help="Inject PDD metadata tags (<pdd-reason>, <pdd-interface>, <pdd-dependency>) from architecture.json.",
47
+ )
42
48
  @click.pass_context
43
49
  # No @track_cost as preprocessing is local, but return dummy tuple for callback
44
50
  def preprocess(
@@ -49,6 +55,7 @@ def preprocess(
49
55
  recursive: bool,
50
56
  double: bool,
51
57
  exclude: Optional[Tuple[str, ...]],
58
+ pdd_tags: bool,
52
59
  ) -> Optional[Tuple[str, float, str]]:
53
60
  """Preprocess a prompt file to prepare it for LLM use."""
54
61
  try:
@@ -62,6 +69,7 @@ def preprocess(
62
69
  recursive=recursive,
63
70
  double=double,
64
71
  exclude=list(exclude) if exclude else [],
72
+ pdd_tags=pdd_tags,
65
73
  )
66
74
 
67
75
  # Handle the result from preprocess_main