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/server/models.py ADDED
@@ -0,0 +1,241 @@
1
+ """
2
+ Pydantic v2 models for the PDD Server REST API.
3
+
4
+ This module defines the data structures for request and response bodies used
5
+ in file operations, command execution, job management, and WebSocket messaging.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from datetime import datetime, timezone
11
+ from enum import Enum
12
+ from typing import Any, Dict, List, Literal, Optional, Union
13
+
14
+ from pydantic import BaseModel, Field, field_validator
15
+
16
+ __all__ = [
17
+ "FileMetadata",
18
+ "FileTreeNode",
19
+ "FileContent",
20
+ "WriteFileRequest",
21
+ "WriteResult",
22
+ "CommandRequest",
23
+ "JobHandle",
24
+ "JobStatus",
25
+ "JobResult",
26
+ "WSMessage",
27
+ "StdoutMessage",
28
+ "StderrMessage",
29
+ "ProgressMessage",
30
+ "InputRequestMessage",
31
+ "CompleteMessage",
32
+ "FileChangeMessage",
33
+ "ServerStatus",
34
+ "ServerConfig",
35
+ "RemoteSessionInfo",
36
+ "SessionListItem",
37
+ ]
38
+
39
+
40
+ # ============================================================================
41
+ # File Models
42
+ # ============================================================================
43
+
44
+ class FileMetadata(BaseModel):
45
+ """Metadata for a single file or directory."""
46
+ path: str = Field(..., description="Relative path from project root")
47
+ exists: bool = Field(..., description="Whether the file exists on disk")
48
+ size: Optional[int] = Field(None, description="File size in bytes")
49
+ mtime: Optional[datetime] = Field(None, description="Last modification time")
50
+ is_directory: bool = Field(False, description="True if path is a directory")
51
+
52
+ @field_validator("path")
53
+ @classmethod
54
+ def validate_path(cls, v: str) -> str:
55
+ if ".." in v:
56
+ raise ValueError("Path traversal ('..') is not allowed")
57
+ return v
58
+
59
+
60
+ class FileTreeNode(BaseModel):
61
+ """Recursive tree structure for file system navigation."""
62
+ name: str = Field(..., description="Base name of the file/directory")
63
+ path: str = Field(..., description="Relative path from project root")
64
+ type: Literal["file", "directory"] = Field(..., description="Node type")
65
+ children: Optional[List[FileTreeNode]] = Field(None, description="Child nodes if directory")
66
+ size: Optional[int] = Field(None, description="File size in bytes")
67
+ mtime: Optional[datetime] = Field(None, description="Last modification time")
68
+
69
+
70
+ class FileContent(BaseModel):
71
+ """Content of a file, potentially encoded."""
72
+ path: str = Field(..., description="Relative path from project root")
73
+ content: str = Field(..., description="File content (text or base64)")
74
+ encoding: Literal["utf-8", "base64"] = Field("utf-8", description="Content encoding")
75
+ size: int = Field(..., description="Size of content in bytes")
76
+ is_binary: bool = Field(False, description="True if content is binary data")
77
+ chunk_index: Optional[int] = Field(None, description="Index if chunked transfer")
78
+ total_chunks: Optional[int] = Field(None, description="Total chunks if chunked transfer")
79
+ checksum: Optional[str] = Field(None, description="SHA-256 checksum of content")
80
+
81
+
82
+ class WriteFileRequest(BaseModel):
83
+ """Request to write content to a file."""
84
+ path: str = Field(..., description="Relative path from project root")
85
+ content: str = Field(..., description="Content to write")
86
+ encoding: Literal["utf-8", "base64"] = Field("utf-8", description="Content encoding")
87
+ create_parents: bool = Field(True, description="Create parent directories if missing")
88
+
89
+ @field_validator("path")
90
+ @classmethod
91
+ def validate_path(cls, v: str) -> str:
92
+ if ".." in v:
93
+ raise ValueError("Path traversal ('..') is not allowed")
94
+ return v
95
+
96
+
97
+ class WriteResult(BaseModel):
98
+ """Result of a file write operation."""
99
+ success: bool = Field(..., description="Whether the write succeeded")
100
+ path: str = Field(..., description="Path written to")
101
+ mtime: Optional[datetime] = Field(None, description="New modification time")
102
+ error: Optional[str] = Field(None, description="Error message if failed")
103
+
104
+
105
+ # ============================================================================
106
+ # Command & Job Models
107
+ # ============================================================================
108
+
109
+ class CommandRequest(BaseModel):
110
+ """Request to execute a PDD command."""
111
+ command: str = Field(..., description="PDD command name (e.g., 'sync', 'generate')")
112
+ args: Dict[str, Any] = Field(default_factory=dict, description="Positional arguments")
113
+ options: Dict[str, Any] = Field(default_factory=dict, description="Command options/flags")
114
+
115
+
116
+ class JobStatus(str, Enum):
117
+ """Enumeration of possible job statuses."""
118
+ QUEUED = "queued"
119
+ RUNNING = "running"
120
+ COMPLETED = "completed"
121
+ FAILED = "failed"
122
+ CANCELLED = "cancelled"
123
+
124
+
125
+ class JobHandle(BaseModel):
126
+ """Initial response after submitting a command."""
127
+ job_id: str = Field(..., description="Unique identifier for the job")
128
+ status: JobStatus = Field(JobStatus.QUEUED, description="Current status")
129
+ created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), description="Submission timestamp")
130
+
131
+
132
+ class JobResult(BaseModel):
133
+ """Final result of a completed job."""
134
+ job_id: str = Field(..., description="Unique identifier for the job")
135
+ status: JobStatus = Field(..., description="Final status")
136
+ result: Optional[Any] = Field(None, description="Command return value")
137
+ error: Optional[str] = Field(None, description="Error message if failed")
138
+ cost: float = Field(0.0, description="Estimated cost of operation")
139
+ duration_seconds: float = Field(0.0, description="Execution duration")
140
+ completed_at: Optional[datetime] = Field(None, description="Completion timestamp")
141
+
142
+
143
+ # ============================================================================
144
+ # WebSocket Message Models
145
+ # ============================================================================
146
+
147
+ class WSMessage(BaseModel):
148
+ """Base model for all WebSocket messages."""
149
+ type: str = Field(..., description="Message type discriminator")
150
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), description="Message timestamp")
151
+ data: Optional[Any] = Field(None, description="Generic payload")
152
+
153
+
154
+ class StdoutMessage(WSMessage):
155
+ """Message containing standard output from a process."""
156
+ type: Literal["stdout"] = "stdout"
157
+ data: str = Field(..., description="Text content")
158
+ raw: Optional[str] = Field(None, description="Raw content with ANSI codes")
159
+
160
+
161
+ class StderrMessage(WSMessage):
162
+ """Message containing standard error from a process."""
163
+ type: Literal["stderr"] = "stderr"
164
+ data: str = Field(..., description="Text content")
165
+ raw: Optional[str] = Field(None, description="Raw content with ANSI codes")
166
+
167
+
168
+ class ProgressMessage(WSMessage):
169
+ """Message indicating progress of a long-running task."""
170
+ type: Literal["progress"] = "progress"
171
+ current: int = Field(..., description="Current progress value")
172
+ total: int = Field(..., description="Total progress value")
173
+ message: Optional[str] = Field(None, description="Progress description")
174
+
175
+
176
+ class InputRequestMessage(WSMessage):
177
+ """Message requesting input from the client."""
178
+ type: Literal["input_request"] = "input_request"
179
+ prompt: str = Field(..., description="Prompt text to display")
180
+ password: bool = Field(False, description="Whether input should be masked")
181
+
182
+
183
+ class CompleteMessage(WSMessage):
184
+ """Message indicating job completion."""
185
+ type: Literal["complete"] = "complete"
186
+ success: bool = Field(..., description="Whether the job succeeded")
187
+ result: Optional[Dict[str, Any]] = Field(None, description="Result data")
188
+ cost: float = Field(0.0, description="Total cost incurred")
189
+
190
+
191
+ class FileChangeMessage(WSMessage):
192
+ """Message indicating a file system event."""
193
+ type: Literal["file_change"] = "file_change"
194
+ path: str = Field(..., description="Path of the changed file")
195
+ event: Literal["created", "modified", "deleted"] = Field(..., description="Type of change")
196
+
197
+
198
+ # ============================================================================
199
+ # Server Configuration Models
200
+ # ============================================================================
201
+
202
+ class ServerStatus(BaseModel):
203
+ """General status information about the server."""
204
+ version: str = Field(..., description="Server version")
205
+ project_root: str = Field(..., description="Absolute path to project root")
206
+ uptime_seconds: float = Field(..., description="Server uptime in seconds")
207
+ active_jobs: int = Field(0, description="Number of currently running jobs")
208
+ connected_clients: int = Field(0, description="Number of active WebSocket connections")
209
+
210
+
211
+ class ServerConfig(BaseModel):
212
+ """Configuration settings for the server instance."""
213
+ host: str = Field("127.0.0.1", description="Bind host")
214
+ port: int = Field(9876, description="Bind port")
215
+ token: Optional[str] = Field(None, description="Authentication token if enabled")
216
+ allow_remote: bool = Field(False, description="Allow remote connections")
217
+ allowed_origins: Optional[List[str]] = Field(None, description="CORS allowed origins")
218
+ log_level: str = Field("info", description="Logging level")
219
+
220
+
221
+ # ============================================================================
222
+ # Remote Session Models
223
+ # ============================================================================
224
+
225
+ class RemoteSessionInfo(BaseModel):
226
+ """Information about the current server's remote session registration."""
227
+ session_id: Optional[str] = Field(None, description="Session ID if registered")
228
+ cloud_url: Optional[str] = Field(None, description="Cloud access URL (e.g., https://pdd.dev/connect/{session_id})")
229
+ registered: bool = Field(False, description="Whether session is registered with cloud")
230
+ registered_at: Optional[datetime] = Field(None, description="When session was registered")
231
+
232
+
233
+ class SessionListItem(BaseModel):
234
+ """Session item for list display."""
235
+ session_id: str = Field(..., description="Unique session identifier")
236
+ cloud_url: str = Field(..., description="Cloud access URL for remote access")
237
+ project_name: str = Field(..., description="Project directory name")
238
+ created_at: datetime = Field(..., description="When session was created")
239
+ last_heartbeat: datetime = Field(..., description="Last heartbeat timestamp")
240
+ status: Literal["active", "stale"] = Field(..., description="Session status")
241
+ metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from . import architecture
4
+ from . import auth
5
+ from . import config
6
+ from . import files
7
+ from . import commands
8
+ from . import prompts
9
+ from .architecture import router as architecture_router
10
+ from .auth import router as auth_router
11
+ from .config import router as config_router
12
+ from .files import router as files_router
13
+ from .commands import router as commands_router
14
+ from .websocket import router as websocket_router
15
+ from .prompts import router as prompts_router
16
+
17
+ __all__ = [
18
+ "architecture",
19
+ "auth",
20
+ "config",
21
+ "files",
22
+ "commands",
23
+ "prompts",
24
+ "architecture_router",
25
+ "auth_router",
26
+ "config_router",
27
+ "files_router",
28
+ "commands_router",
29
+ "websocket_router",
30
+ "prompts_router",
31
+ ]