pdd-cli 0.0.136__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 (262) hide show
  1. pdd/__init__.py +52 -0
  2. pdd/agentic_architecture.py +270 -0
  3. pdd/agentic_architecture_orchestrator.py +676 -0
  4. pdd/agentic_bug.py +323 -0
  5. pdd/agentic_bug_orchestrator.py +567 -0
  6. pdd/agentic_change.py +242 -0
  7. pdd/agentic_change_orchestrator.py +829 -0
  8. pdd/agentic_common.py +849 -0
  9. pdd/agentic_crash.py +552 -0
  10. pdd/agentic_e2e_fix.py +322 -0
  11. pdd/agentic_e2e_fix_orchestrator.py +615 -0
  12. pdd/agentic_fix.py +451 -0
  13. pdd/agentic_langtest.py +59 -0
  14. pdd/agentic_test.py +308 -0
  15. pdd/agentic_test_generate.py +310 -0
  16. pdd/agentic_test_orchestrator.py +471 -0
  17. pdd/agentic_update.py +388 -0
  18. pdd/agentic_verify.py +184 -0
  19. pdd/architecture_sync.py +571 -0
  20. pdd/auth_service.py +398 -0
  21. pdd/auto_deps_main.py +124 -0
  22. pdd/auto_include.py +515 -0
  23. pdd/auto_update.py +226 -0
  24. pdd/bug_main.py +290 -0
  25. pdd/bug_to_unit_test.py +187 -0
  26. pdd/change.py +193 -0
  27. pdd/change_main.py +529 -0
  28. pdd/cli.py +43 -0
  29. pdd/cmd_test_main.py +426 -0
  30. pdd/code_generator.py +171 -0
  31. pdd/code_generator_main.py +1197 -0
  32. pdd/commands/__init__.py +50 -0
  33. pdd/commands/analysis.py +313 -0
  34. pdd/commands/auth.py +367 -0
  35. pdd/commands/connect.py +366 -0
  36. pdd/commands/fix.py +191 -0
  37. pdd/commands/generate.py +326 -0
  38. pdd/commands/maintenance.py +183 -0
  39. pdd/commands/misc.py +87 -0
  40. pdd/commands/modify.py +292 -0
  41. pdd/commands/report.py +149 -0
  42. pdd/commands/sessions.py +284 -0
  43. pdd/commands/templates.py +215 -0
  44. pdd/commands/utility.py +115 -0
  45. pdd/commands/which.py +297 -0
  46. pdd/comment_line.py +35 -0
  47. pdd/config_resolution.py +58 -0
  48. pdd/conflicts_in_prompts.py +149 -0
  49. pdd/conflicts_main.py +99 -0
  50. pdd/construct_paths.py +1288 -0
  51. pdd/context_generator.py +160 -0
  52. pdd/context_generator_main.py +209 -0
  53. pdd/continue_generation.py +192 -0
  54. pdd/core/__init__.py +33 -0
  55. pdd/core/cli.py +558 -0
  56. pdd/core/cloud.py +290 -0
  57. pdd/core/dump.py +602 -0
  58. pdd/core/errors.py +68 -0
  59. pdd/core/remote_session.py +61 -0
  60. pdd/core/utils.py +90 -0
  61. pdd/crash_main.py +406 -0
  62. pdd/data/language_format.csv +94 -0
  63. pdd/data/llm_model.csv +20 -0
  64. pdd/detect_change.py +147 -0
  65. pdd/detect_change_main.py +104 -0
  66. pdd/docs/prompting_guide.md +909 -0
  67. pdd/docs/whitepaper_with_benchmarks/data_and_functions/benchmark_analysis.py +495 -0
  68. pdd/docs/whitepaper_with_benchmarks/data_and_functions/creation_compare.py +528 -0
  69. pdd/edit_file.py +783 -0
  70. pdd/find_section.py +28 -0
  71. pdd/fix_code_loop.py +951 -0
  72. pdd/fix_code_module_errors.py +165 -0
  73. pdd/fix_error_loop.py +995 -0
  74. pdd/fix_errors_from_unit_tests.py +254 -0
  75. pdd/fix_main.py +563 -0
  76. pdd/fix_verification_errors.py +260 -0
  77. pdd/fix_verification_errors_loop.py +1288 -0
  78. pdd/fix_verification_main.py +689 -0
  79. pdd/frontend/dist/assets/index-B5DZHykP.css +1 -0
  80. pdd/frontend/dist/assets/index-mnK5Bbrq.js +441 -0
  81. pdd/frontend/dist/index.html +403 -0
  82. pdd/frontend/dist/logo.svg +33 -0
  83. pdd/generate_output_paths.py +697 -0
  84. pdd/generate_test.py +305 -0
  85. pdd/get_comment.py +30 -0
  86. pdd/get_extension.py +65 -0
  87. pdd/get_jwt_token.py +623 -0
  88. pdd/get_language.py +42 -0
  89. pdd/get_run_command.py +75 -0
  90. pdd/get_test_command.py +76 -0
  91. pdd/git_update.py +137 -0
  92. pdd/increase_tests.py +106 -0
  93. pdd/incremental_code_generator.py +198 -0
  94. pdd/insert_includes.py +166 -0
  95. pdd/install_completion.py +144 -0
  96. pdd/llm_invoke.py +3044 -0
  97. pdd/load_prompt_template.py +66 -0
  98. pdd/logo_animation.py +455 -0
  99. pdd/mcp_config.json +7 -0
  100. pdd/operation_log.py +351 -0
  101. pdd/path_resolution.py +140 -0
  102. pdd/pdd_completion.fish +157 -0
  103. pdd/pdd_completion.sh +186 -0
  104. pdd/pdd_completion.zsh +565 -0
  105. pdd/pin_example_hack.py +1753 -0
  106. pdd/postprocess.py +158 -0
  107. pdd/postprocess_0.py +52 -0
  108. pdd/preprocess.py +461 -0
  109. pdd/preprocess_main.py +114 -0
  110. pdd/process_csv_change.py +506 -0
  111. pdd/prompts/agentic_arch_step10_sync_LLM.prompt +224 -0
  112. pdd/prompts/agentic_arch_step11_deps_LLM.prompt +239 -0
  113. pdd/prompts/agentic_arch_step12_fix_LLM.prompt +5674 -0
  114. pdd/prompts/agentic_arch_step1_analyze_prd_LLM.prompt +93 -0
  115. pdd/prompts/agentic_arch_step2_analyze_LLM.prompt +103 -0
  116. pdd/prompts/agentic_arch_step3_research_LLM.prompt +1022 -0
  117. pdd/prompts/agentic_arch_step4_design_LLM.prompt +114 -0
  118. pdd/prompts/agentic_arch_step5_research_deps_LLM.prompt +98 -0
  119. pdd/prompts/agentic_arch_step6_generate_LLM.prompt +1035 -0
  120. pdd/prompts/agentic_arch_step7_pddrc_LLM.prompt +599 -0
  121. pdd/prompts/agentic_arch_step8_prompts_LLM.prompt +803 -0
  122. pdd/prompts/agentic_arch_step9_completeness_LLM.prompt +197 -0
  123. pdd/prompts/agentic_bug_step10_pr_LLM.prompt +185 -0
  124. pdd/prompts/agentic_bug_step1_duplicate_LLM.prompt +73 -0
  125. pdd/prompts/agentic_bug_step2_docs_LLM.prompt +129 -0
  126. pdd/prompts/agentic_bug_step3_triage_LLM.prompt +95 -0
  127. pdd/prompts/agentic_bug_step4_reproduce_LLM.prompt +97 -0
  128. pdd/prompts/agentic_bug_step5_5_prompt_classification_LLM.prompt +1090 -0
  129. pdd/prompts/agentic_bug_step5_root_cause_LLM.prompt +123 -0
  130. pdd/prompts/agentic_bug_step6_test_plan_LLM.prompt +111 -0
  131. pdd/prompts/agentic_bug_step7_generate_LLM.prompt +176 -0
  132. pdd/prompts/agentic_bug_step8_verify_LLM.prompt +124 -0
  133. pdd/prompts/agentic_bug_step9_e2e_test_LLM.prompt +293 -0
  134. pdd/prompts/agentic_change_step10_architecture_update_LLM.prompt +1086 -0
  135. pdd/prompts/agentic_change_step11_identify_issues_LLM.prompt +1051 -0
  136. pdd/prompts/agentic_change_step12_fix_issues_LLM.prompt +1029 -0
  137. pdd/prompts/agentic_change_step13_create_pr_LLM.prompt +140 -0
  138. pdd/prompts/agentic_change_step1_duplicate_LLM.prompt +73 -0
  139. pdd/prompts/agentic_change_step2_docs_LLM.prompt +101 -0
  140. pdd/prompts/agentic_change_step3_research_LLM.prompt +126 -0
  141. pdd/prompts/agentic_change_step4_clarify_LLM.prompt +164 -0
  142. pdd/prompts/agentic_change_step5_docs_change_LLM.prompt +1026 -0
  143. pdd/prompts/agentic_change_step6_devunits_LLM.prompt +1222 -0
  144. pdd/prompts/agentic_change_step7_architecture_LLM.prompt +1100 -0
  145. pdd/prompts/agentic_change_step8_analyze_LLM.prompt +1086 -0
  146. pdd/prompts/agentic_change_step9_implement_LLM.prompt +1201 -0
  147. pdd/prompts/agentic_crash_explore_LLM.prompt +49 -0
  148. pdd/prompts/agentic_e2e_fix_step1_unit_tests_LLM.prompt +88 -0
  149. pdd/prompts/agentic_e2e_fix_step2_e2e_tests_LLM.prompt +91 -0
  150. pdd/prompts/agentic_e2e_fix_step3_root_cause_LLM.prompt +89 -0
  151. pdd/prompts/agentic_e2e_fix_step4_fix_e2e_tests_LLM.prompt +96 -0
  152. pdd/prompts/agentic_e2e_fix_step5_identify_devunits_LLM.prompt +91 -0
  153. pdd/prompts/agentic_e2e_fix_step6_create_unit_tests_LLM.prompt +106 -0
  154. pdd/prompts/agentic_e2e_fix_step7_verify_tests_LLM.prompt +116 -0
  155. pdd/prompts/agentic_e2e_fix_step8_run_pdd_fix_LLM.prompt +118 -0
  156. pdd/prompts/agentic_e2e_fix_step9_verify_all_LLM.prompt +146 -0
  157. pdd/prompts/agentic_fix_explore_LLM.prompt +45 -0
  158. pdd/prompts/agentic_fix_nonpython_LLM.prompt +45 -0
  159. pdd/prompts/agentic_fix_primary_LLM.prompt +39 -0
  160. pdd/prompts/agentic_test_generate_LLM.prompt +67 -0
  161. pdd/prompts/agentic_test_step1_duplicate_LLM.prompt +73 -0
  162. pdd/prompts/agentic_test_step2_docs_LLM.prompt +95 -0
  163. pdd/prompts/agentic_test_step3_clarify_LLM.prompt +111 -0
  164. pdd/prompts/agentic_test_step4_detect_frontend_LLM.prompt +126 -0
  165. pdd/prompts/agentic_test_step5_test_plan_LLM.prompt +180 -0
  166. pdd/prompts/agentic_test_step6_generate_tests_LLM.prompt +210 -0
  167. pdd/prompts/agentic_test_step7_run_tests_LLM.prompt +164 -0
  168. pdd/prompts/agentic_test_step8_fix_iterate_LLM.prompt +169 -0
  169. pdd/prompts/agentic_test_step9_submit_pr_LLM.prompt +173 -0
  170. pdd/prompts/agentic_update_LLM.prompt +970 -0
  171. pdd/prompts/agentic_verify_explore_LLM.prompt +45 -0
  172. pdd/prompts/auto_include_LLM.prompt +249 -0
  173. pdd/prompts/bug_to_unit_test_LLM.prompt +17 -0
  174. pdd/prompts/change_LLM.prompt +3133 -0
  175. pdd/prompts/code_patcher_LLM.prompt +63 -0
  176. pdd/prompts/conflict_LLM.prompt +23 -0
  177. pdd/prompts/continue_generation_LLM.prompt +3 -0
  178. pdd/prompts/detect_change_LLM.prompt +1181 -0
  179. pdd/prompts/diff_analyzer_LLM.prompt +69 -0
  180. pdd/prompts/example_generator_LLM.prompt +31 -0
  181. pdd/prompts/extract_auto_include_LLM.prompt +6 -0
  182. pdd/prompts/extract_code_LLM.prompt +26 -0
  183. pdd/prompts/extract_conflict_LLM.prompt +19 -0
  184. pdd/prompts/extract_detect_change_LLM.prompt +19 -0
  185. pdd/prompts/extract_program_code_fix_LLM.prompt +29 -0
  186. pdd/prompts/extract_prompt_change_LLM.prompt +13 -0
  187. pdd/prompts/extract_prompt_split_LLM.prompt +12 -0
  188. pdd/prompts/extract_prompt_update_LLM.prompt +13 -0
  189. pdd/prompts/extract_promptline_LLM.prompt +17 -0
  190. pdd/prompts/extract_unit_code_fix_LLM.prompt +332 -0
  191. pdd/prompts/extract_xml_LLM.prompt +7 -0
  192. pdd/prompts/find_verification_errors_LLM.prompt +44 -0
  193. pdd/prompts/fix_code_module_errors_LLM.prompt +66 -0
  194. pdd/prompts/fix_errors_from_unit_tests_LLM.prompt +40 -0
  195. pdd/prompts/fix_verification_errors_LLM.prompt +62 -0
  196. pdd/prompts/generate_test_LLM.prompt +60 -0
  197. pdd/prompts/generate_test_from_example_LLM.prompt +723 -0
  198. pdd/prompts/increase_tests_LLM.prompt +15 -0
  199. pdd/prompts/insert_includes_LLM.prompt +1215 -0
  200. pdd/prompts/prompt_code_diff_LLM.prompt +123 -0
  201. pdd/prompts/prompt_diff_LLM.prompt +82 -0
  202. pdd/prompts/split_LLM.prompt +34 -0
  203. pdd/prompts/summarize_file_LLM.prompt +11 -0
  204. pdd/prompts/sync_analysis_LLM.prompt +82 -0
  205. pdd/prompts/trace_LLM.prompt +33 -0
  206. pdd/prompts/trim_results_LLM.prompt +83 -0
  207. pdd/prompts/trim_results_start_LLM.prompt +45 -0
  208. pdd/prompts/unfinished_prompt_LLM.prompt +102 -0
  209. pdd/prompts/update_prompt_LLM.prompt +40 -0
  210. pdd/prompts/xml_convertor_LLM.prompt +3293 -0
  211. pdd/pytest_output.py +324 -0
  212. pdd/python_env_detector.py +151 -0
  213. pdd/remote_session.py +1020 -0
  214. pdd/render_mermaid.py +236 -0
  215. pdd/server/__init__.py +52 -0
  216. pdd/server/app.py +340 -0
  217. pdd/server/click_executor.py +587 -0
  218. pdd/server/executor.py +338 -0
  219. pdd/server/jobs.py +679 -0
  220. pdd/server/models.py +241 -0
  221. pdd/server/routes/__init__.py +31 -0
  222. pdd/server/routes/architecture.py +569 -0
  223. pdd/server/routes/auth.py +364 -0
  224. pdd/server/routes/commands.py +929 -0
  225. pdd/server/routes/config.py +42 -0
  226. pdd/server/routes/files.py +860 -0
  227. pdd/server/routes/prompts.py +1344 -0
  228. pdd/server/routes/websocket.py +473 -0
  229. pdd/server/security.py +243 -0
  230. pdd/server/terminal_spawner.py +277 -0
  231. pdd/server/token_counter.py +222 -0
  232. pdd/setup_tool.py +648 -0
  233. pdd/split.py +131 -0
  234. pdd/split_main.py +117 -0
  235. pdd/summarize_directory.py +321 -0
  236. pdd/sync_animation.py +647 -0
  237. pdd/sync_determine_operation.py +2251 -0
  238. pdd/sync_main.py +716 -0
  239. pdd/sync_orchestration.py +1914 -0
  240. pdd/sync_order.py +353 -0
  241. pdd/sync_tui.py +848 -0
  242. pdd/template_expander.py +161 -0
  243. pdd/template_registry.py +264 -0
  244. pdd/templates/architecture/architecture_json.prompt +303 -0
  245. pdd/templates/architecture/example_nextjs_task_notes.prompt +505 -0
  246. pdd/templates/architecture/pdd_path_construction_guide.prompt +362 -0
  247. pdd/templates/generic/generate_pddrc_YAML.prompt +213 -0
  248. pdd/templates/generic/generate_prompt.prompt +188 -0
  249. pdd/trace.py +295 -0
  250. pdd/trace_main.py +117 -0
  251. pdd/track_cost.py +179 -0
  252. pdd/unfinished_prompt.py +169 -0
  253. pdd/update_main.py +632 -0
  254. pdd/update_model_costs.py +446 -0
  255. pdd/update_prompt.py +134 -0
  256. pdd/xml_tagger.py +137 -0
  257. pdd_cli-0.0.136.dist-info/METADATA +325 -0
  258. pdd_cli-0.0.136.dist-info/RECORD +262 -0
  259. pdd_cli-0.0.136.dist-info/WHEEL +5 -0
  260. pdd_cli-0.0.136.dist-info/entry_points.txt +2 -0
  261. pdd_cli-0.0.136.dist-info/licenses/LICENSE +7 -0
  262. pdd_cli-0.0.136.dist-info/top_level.txt +1 -0
pdd/__init__.py ADDED
@@ -0,0 +1,52 @@
1
+ """PDD - Prompt Driven Development"""
2
+
3
+ import os
4
+
5
+ __version__ = "0.0.136"
6
+
7
+ # Strength parameter used for LLM extraction across the codebase
8
+ # Used in postprocessing, XML tagging, code generation, and other extraction
9
+ # operations. The module should have a large context window and be affordable.
10
+ EXTRACTION_STRENGTH = 0.5
11
+
12
+ DEFAULT_STRENGTH = 1.0
13
+
14
+ DEFAULT_TEMPERATURE = 0.0
15
+
16
+ DEFAULT_TIME = 0.25
17
+
18
+ # Public OAuth credentials for cloud mode
19
+ # These are safe to embed as they are public client identifiers:
20
+ # - Firebase API keys are designed to be public (client-side)
21
+ # - GitHub OAuth Client IDs are public (the secret stays server-side)
22
+ # Users still need to authenticate via GitHub OAuth to use cloud features.
23
+ _DEFAULT_FIREBASE_API_KEY = "AIzaSyC0w2jwRR82ZFgQs_YXJoEBqnnTH71X6BE"
24
+ _DEFAULT_GITHUB_CLIENT_ID = "Ov23liJ4eSm0y5W1L20u"
25
+
26
+
27
+ def _setup_cloud_defaults() -> None:
28
+ """Set up default cloud credentials if not already set.
29
+
30
+ Only sets defaults when:
31
+ 1. Not running inside cloud environment (K_SERVICE or FUNCTIONS_EMULATOR)
32
+ 2. Environment variables are not already set
33
+
34
+ This prevents infinite loops when cloud endpoints call CLI internally,
35
+ while providing a seamless experience for local users.
36
+ """
37
+ # Skip if running in cloud environment to prevent infinite loops
38
+ if os.environ.get("K_SERVICE") or os.environ.get("FUNCTIONS_EMULATOR"):
39
+ return
40
+
41
+ # Set Firebase API key if not already set
42
+ if not os.environ.get("NEXT_PUBLIC_FIREBASE_API_KEY"):
43
+ os.environ["NEXT_PUBLIC_FIREBASE_API_KEY"] = _DEFAULT_FIREBASE_API_KEY
44
+
45
+ # Set GitHub Client ID if not already set
46
+ if not os.environ.get("GITHUB_CLIENT_ID"):
47
+ os.environ["GITHUB_CLIENT_ID"] = _DEFAULT_GITHUB_CLIENT_ID
48
+
49
+
50
+ # Initialize cloud defaults on package import
51
+ _setup_cloud_defaults()
52
+
@@ -0,0 +1,270 @@
1
+ """
2
+ CLI entry point for the agentic architecture workflow.
3
+ Detects GitHub issue URLs, fetches issue content and comments via `gh api`,
4
+ ensures repository context is available, then invokes the orchestrator.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import re
11
+ import shutil
12
+ import subprocess
13
+ from pathlib import Path
14
+ from typing import List, Optional, Tuple
15
+
16
+ from rich.console import Console
17
+
18
+ # Internal imports
19
+ from .agentic_architecture_orchestrator import run_agentic_architecture_orchestrator
20
+
21
+ console = Console()
22
+
23
+
24
+ def _is_github_issue_url(url: str) -> bool:
25
+ """
26
+ Detect if the string is a valid GitHub issue URL.
27
+
28
+ Args:
29
+ url: The URL string to check.
30
+
31
+ Returns:
32
+ True if the URL matches the GitHub issue pattern, False otherwise.
33
+ """
34
+ return _parse_github_url(url) is not None
35
+
36
+
37
+ def _parse_github_url(url: str) -> Optional[Tuple[str, str, int]]:
38
+ """
39
+ Extract owner, repo, and issue number from a GitHub URL.
40
+
41
+ Supports:
42
+ - https://github.com/{owner}/{repo}/issues/{number}
43
+ - https://www.github.com/{owner}/{repo}/issues/{number}
44
+ - github.com/{owner}/{repo}/issues/{number}
45
+
46
+ Args:
47
+ url: The URL string to parse.
48
+
49
+ Returns:
50
+ Tuple of (owner, repo, issue_number) if successful, None otherwise.
51
+ """
52
+ pattern = r"(?:https?://)?(?:www\.)?github\.com/([^/]+)/([^/]+)/issues/(\d+)"
53
+ match = re.search(pattern, url)
54
+ if match:
55
+ owner, repo, number = match.groups()
56
+ return owner, repo, int(number)
57
+ return None
58
+
59
+
60
+ def _check_gh_cli() -> bool:
61
+ """Check if gh CLI tool is available on the PATH."""
62
+ return shutil.which("gh") is not None
63
+
64
+
65
+ def _run_gh_command(args: List[str]) -> Tuple[bool, str]:
66
+ """
67
+ Run a gh command and return (success, stdout/stderr).
68
+
69
+ Args:
70
+ args: List of arguments to pass to the gh command.
71
+
72
+ Returns:
73
+ Tuple of (success boolean, output string).
74
+ """
75
+ try:
76
+ result = subprocess.run(
77
+ ["gh"] + args,
78
+ capture_output=True,
79
+ text=True,
80
+ check=True
81
+ )
82
+ return True, result.stdout
83
+ except subprocess.CalledProcessError as e:
84
+ return False, e.stderr or str(e)
85
+ except FileNotFoundError:
86
+ return False, "gh CLI not found"
87
+
88
+
89
+ def _ensure_repo_context(owner: str, repo: str, current_cwd: Path, quiet: bool) -> Tuple[Path, Optional[str]]:
90
+ """
91
+ Ensure the repository is available locally.
92
+
93
+ Logic:
94
+ 1. If current_cwd is inside the target repo (checked via remote), use it.
95
+ 2. If current_cwd is a git repo but mismatch, warn and use it (user might be in a fork).
96
+ 3. If current_cwd is NOT a git repo:
97
+ a. Check if subdirectory {repo} exists and is a git repo -> use it.
98
+ b. Clone {owner}/{repo} -> use it.
99
+
100
+ Args:
101
+ owner: Repository owner.
102
+ repo: Repository name.
103
+ current_cwd: Current working directory.
104
+ quiet: Whether to suppress non-error output.
105
+
106
+ Returns:
107
+ Tuple of (path to repo root, error message if any).
108
+ """
109
+
110
+ def get_remote_url(path: Path) -> Optional[str]:
111
+ try:
112
+ res = subprocess.run(
113
+ ["git", "config", "--get", "remote.origin.url"],
114
+ cwd=path, capture_output=True, text=True
115
+ )
116
+ if res.returncode == 0:
117
+ return res.stdout.strip()
118
+ except Exception:
119
+ pass
120
+ return None
121
+
122
+ # Case 1 & 2: Already in a git repo
123
+ remote = get_remote_url(current_cwd)
124
+ if remote:
125
+ # Simple check if owner/repo is in the remote URL
126
+ # Remotes can be git@github.com:owner/repo.git or https://github.com/owner/repo.git
127
+ if f"{owner}/{repo}" in remote or f"{owner}/{repo}.git" in remote:
128
+ return current_cwd, None
129
+
130
+ # Mismatch
131
+ if not quiet:
132
+ console.print(f"[yellow]Warning: Current directory is a git repo but remote '{remote}' does not match '{owner}/{repo}'. Proceeding in current directory.[/yellow]")
133
+ return current_cwd, None
134
+
135
+ # Case 3: Not in a git repo
136
+ target_dir = current_cwd / repo
137
+
138
+ # 3a: Subdirectory exists
139
+ if target_dir.exists() and target_dir.is_dir():
140
+ if (target_dir / ".git").exists():
141
+ if not quiet:
142
+ console.print(f"[blue]Found existing repository at {target_dir}[/blue]")
143
+ return target_dir, None
144
+ else:
145
+ return current_cwd, f"Directory '{repo}' exists but is not a git repository."
146
+
147
+ # 3b: Clone
148
+ if not quiet:
149
+ console.print(f"[blue]Cloning {owner}/{repo} into {target_dir}...[/blue]")
150
+
151
+ try:
152
+ subprocess.run(
153
+ ["gh", "repo", "clone", f"{owner}/{repo}"],
154
+ cwd=current_cwd,
155
+ check=True,
156
+ capture_output=True,
157
+ text=True
158
+ )
159
+ return target_dir, None
160
+ except subprocess.CalledProcessError as e:
161
+ err_msg = e.stderr if e.stderr else str(e)
162
+ return current_cwd, f"Failed to clone repository: {err_msg}"
163
+
164
+
165
+ def run_agentic_architecture(
166
+ issue_url: str,
167
+ *,
168
+ verbose: bool = False,
169
+ quiet: bool = False,
170
+ timeout_adder: float = 0.0,
171
+ use_github_state: bool = True,
172
+ skip_prompts: bool = False
173
+ ) -> Tuple[bool, str, float, str, List[str]]:
174
+ """
175
+ Entry point for the agentic architecture workflow.
176
+
177
+ 1. Validates the GitHub issue URL.
178
+ 2. Fetches issue details and comments using `gh` CLI.
179
+ 3. Ensures the repository is available locally (clones if necessary).
180
+ 4. Invokes the architecture orchestrator.
181
+
182
+ Args:
183
+ issue_url: Full URL to the GitHub issue.
184
+ verbose: Enable verbose logging.
185
+ quiet: Suppress non-error output.
186
+ timeout_adder: Additional seconds to add to step timeouts.
187
+ use_github_state: Whether to persist state to GitHub comments.
188
+ skip_prompts: If True, skip Step 9 (prompt generation). Default False (prompts ARE generated).
189
+
190
+ Returns:
191
+ Tuple containing:
192
+ - success (bool): Whether the workflow completed successfully.
193
+ - message (str): Final status message or error description.
194
+ - total_cost (float): Total estimated cost of LLM calls.
195
+ - model_used (str): The model used for the last step.
196
+ - output_files (List[str]): List of files generated/modified.
197
+ """
198
+ cwd = Path.cwd()
199
+
200
+ # 1. Check gh CLI
201
+ if not _check_gh_cli():
202
+ return False, "gh CLI not found. Please install GitHub CLI.", 0.0, "", []
203
+
204
+ # 2. Parse URL
205
+ parsed = _parse_github_url(issue_url)
206
+ if not parsed:
207
+ return False, f"Invalid GitHub URL: {issue_url}", 0.0, "", []
208
+
209
+ owner, repo, issue_number = parsed
210
+
211
+ if not quiet:
212
+ console.print(f"[bold blue]Fetching issue #{issue_number} from {owner}/{repo}...[/bold blue]")
213
+
214
+ # 3. Fetch Issue Data
215
+ # gh api repos/{owner}/{repo}/issues/{number}
216
+ success, output = _run_gh_command(["api", f"repos/{owner}/{repo}/issues/{issue_number}"])
217
+ if not success:
218
+ return False, f"Issue not found: {output}", 0.0, "", []
219
+
220
+ try:
221
+ issue_data = json.loads(output)
222
+ except json.JSONDecodeError:
223
+ return False, "Failed to parse GitHub API response", 0.0, "", []
224
+
225
+ issue_title = issue_data.get("title", "")
226
+ issue_body = issue_data.get("body", "") or ""
227
+ issue_author = issue_data.get("user", {}).get("login", "unknown")
228
+ comments_url = issue_data.get("comments_url", "")
229
+
230
+ # 4. Fetch Comments
231
+ comments_text = ""
232
+ if comments_url:
233
+ c_success, c_output = _run_gh_command(["api", comments_url])
234
+ if c_success:
235
+ try:
236
+ comments = json.loads(c_output)
237
+ if isinstance(comments, list) and comments:
238
+ formatted_comments = []
239
+ for c in comments:
240
+ user = c.get("user", {}).get("login", "unknown")
241
+ body = c.get("body", "")
242
+ formatted_comments.append(f"User: {user}\n{body}")
243
+ comments_text = "\n\n--- Comments ---\n" + "\n\n".join(formatted_comments)
244
+ except json.JSONDecodeError:
245
+ if verbose:
246
+ console.print("[yellow]Warning: Failed to parse comments JSON[/yellow]")
247
+
248
+ full_issue_content = f"{issue_body}{comments_text}"
249
+
250
+ # 5. Ensure Repo Context
251
+ repo_path, error = _ensure_repo_context(owner, repo, cwd, quiet)
252
+ if error:
253
+ return False, error, 0.0, "", []
254
+
255
+ # 6. Invoke Orchestrator
256
+ return run_agentic_architecture_orchestrator(
257
+ issue_url=issue_url,
258
+ issue_content=full_issue_content,
259
+ repo_owner=owner,
260
+ repo_name=repo,
261
+ issue_number=issue_number,
262
+ issue_author=issue_author,
263
+ issue_title=issue_title,
264
+ cwd=repo_path,
265
+ verbose=verbose,
266
+ quiet=quiet,
267
+ timeout_adder=timeout_adder,
268
+ use_github_state=use_github_state,
269
+ skip_prompts=skip_prompts
270
+ )