pdd-cli 0.0.57__py3-none-any.whl → 0.0.58__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.
Potentially problematic release.
This version of pdd-cli might be problematic. Click here for more details.
- pdd/__init__.py +1 -1
- pdd_cli-0.0.58.data/data/utils/pdd-setup.py +524 -0
- {pdd_cli-0.0.57.dist-info → pdd_cli-0.0.58.dist-info}/METADATA +3 -3
- {pdd_cli-0.0.57.dist-info → pdd_cli-0.0.58.dist-info}/RECORD +8 -7
- {pdd_cli-0.0.57.dist-info → pdd_cli-0.0.58.dist-info}/WHEEL +0 -0
- {pdd_cli-0.0.57.dist-info → pdd_cli-0.0.58.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.57.dist-info → pdd_cli-0.0.58.dist-info}/licenses/LICENSE +0 -0
- {pdd_cli-0.0.57.dist-info → pdd_cli-0.0.58.dist-info}/top_level.txt +0 -0
pdd/__init__.py
CHANGED
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
PDD Setup Script - Post-install configuration tool for PDD (Prompt Driven Development)
|
|
4
|
+
Helps new users bootstrap their PDD configuration with LLM API keys and basic settings.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import subprocess
|
|
10
|
+
import json
|
|
11
|
+
import requests
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Dict, Optional, Tuple, List
|
|
14
|
+
|
|
15
|
+
# Global variables for non-ASCII characters and colors
|
|
16
|
+
HEAVY_HORIZONTAL = "━"
|
|
17
|
+
LIGHT_HORIZONTAL = "─"
|
|
18
|
+
HEAVY_VERTICAL = "┃"
|
|
19
|
+
LIGHT_VERTICAL = "│"
|
|
20
|
+
TOP_LEFT_CORNER = "┏"
|
|
21
|
+
TOP_RIGHT_CORNER = "┓"
|
|
22
|
+
BOTTOM_LEFT_CORNER = "┗"
|
|
23
|
+
BOTTOM_RIGHT_CORNER = "┛"
|
|
24
|
+
CROSS = "┼"
|
|
25
|
+
TEE_DOWN = "┬"
|
|
26
|
+
TEE_UP = "┴"
|
|
27
|
+
TEE_RIGHT = "├"
|
|
28
|
+
TEE_LEFT = "┤"
|
|
29
|
+
BULLET = "•"
|
|
30
|
+
ARROW_RIGHT = "→"
|
|
31
|
+
CHECK_MARK = "✓"
|
|
32
|
+
CROSS_MARK = "✗"
|
|
33
|
+
|
|
34
|
+
# Color codes
|
|
35
|
+
RESET = "\033[0m"
|
|
36
|
+
WHITE = "\033[97m"
|
|
37
|
+
CYAN = "\033[96m"
|
|
38
|
+
YELLOW = "\033[93m"
|
|
39
|
+
BOLD = "\033[1m"
|
|
40
|
+
|
|
41
|
+
# Template content inline
|
|
42
|
+
HELLO_PYTHON_TEMPLATE = """Create a Python program that prints "Hello <username>" in ASCII art.
|
|
43
|
+
|
|
44
|
+
Requirements:
|
|
45
|
+
- <username> is the username of the current session, using the "whoami" command
|
|
46
|
+
- in the code, generate the full english 26 character alphabet in ascii art as a map of character values to ascii art strings, then use those to render
|
|
47
|
+
- Use only the Python standard library (no external dependencies)
|
|
48
|
+
- Create large, bold ASCII art text, using ASCII drawing characters, symbols, or any other characters that are useful
|
|
49
|
+
- The drawn text should be at least 10 rows in height
|
|
50
|
+
- Make it visually appealing with simple characters like #, *, or =
|
|
51
|
+
- Keep the code clean and readable
|
|
52
|
+
- Add a brief comment explaining what the program does
|
|
53
|
+
|
|
54
|
+
The program should be self-contained and runnable with just `python3 filename.py`."""
|
|
55
|
+
|
|
56
|
+
LLM_MODEL_CSV_TEMPLATE = """provider,model,input,output,coding_arena_elo,base_url,api_key,max_reasoning_tokens,structured_output,reasoning_type
|
|
57
|
+
OpenAI,gpt-5-nano,0.05,0.4,1249,,OPENAI_API_KEY,0,True,none
|
|
58
|
+
Google,gemini/gemini-2.5-pro,1.25,10.0,1360,,GOOGLE_API_KEY,0,True,none
|
|
59
|
+
OpenAI,gpt-5-mini,0.25,2.0,1325,,OPENAI_API_KEY,0,True,effort
|
|
60
|
+
OpenAI,gpt-5,1.25,10.0,1482,,OPENAI_API_KEY,0,True,effort
|
|
61
|
+
OpenAI,gpt-4.1,2.0,8.0,1253,,OPENAI_API_KEY,0,True,none"""
|
|
62
|
+
|
|
63
|
+
def print_colored(text: str, color: str = WHITE, bold: bool = False) -> None:
|
|
64
|
+
"""Print colored text to console"""
|
|
65
|
+
style = BOLD + color if bold else color
|
|
66
|
+
print(f"{style}{text}{RESET}")
|
|
67
|
+
|
|
68
|
+
def create_divider(char: str = LIGHT_HORIZONTAL, width: int = 80) -> str:
|
|
69
|
+
"""Create a horizontal divider line"""
|
|
70
|
+
return char * width
|
|
71
|
+
|
|
72
|
+
def create_fat_divider(width: int = 80) -> str:
|
|
73
|
+
"""Create a fat horizontal divider line"""
|
|
74
|
+
return HEAVY_HORIZONTAL * width
|
|
75
|
+
|
|
76
|
+
def print_pdd_logo():
|
|
77
|
+
"""Print the PDD logo in ASCII art"""
|
|
78
|
+
logo = "\n".join(
|
|
79
|
+
[
|
|
80
|
+
" +xxxxxxxxxxxxxxx+",
|
|
81
|
+
"xxxxxxxxxxxxxxxxxxxxx+",
|
|
82
|
+
"xxx +xx+ PROMPT",
|
|
83
|
+
"xxx x+ xx+ DRIVEN",
|
|
84
|
+
"xxx x+ xxx DEVELOPMENT©",
|
|
85
|
+
"xxx x+ xx+",
|
|
86
|
+
"xxx x+ xx+ COMMAND LINE INTERFACE",
|
|
87
|
+
"xxx x+ xxx",
|
|
88
|
+
"xxx +xx+ ",
|
|
89
|
+
"xxx +xxxxxxxxxxx+",
|
|
90
|
+
"xxx +xx+",
|
|
91
|
+
"xxx +xx+",
|
|
92
|
+
"xxx+xx+ WWW.PROMPTDRIVEN.AI",
|
|
93
|
+
"xxxx+",
|
|
94
|
+
"xx+",
|
|
95
|
+
]
|
|
96
|
+
)
|
|
97
|
+
print(f"{CYAN}{logo}{RESET}")
|
|
98
|
+
print_colored("Supported: OpenAI and Google Gemini (non-Vertex)", WHITE)
|
|
99
|
+
print_colored("from their respective API endpoints (no third-parties, such as Azure)", WHITE)
|
|
100
|
+
print()
|
|
101
|
+
|
|
102
|
+
def discover_api_keys() -> Dict[str, Optional[str]]:
|
|
103
|
+
"""Discover API keys from environment variables"""
|
|
104
|
+
keys = {
|
|
105
|
+
'OPENAI_API_KEY': os.getenv('OPENAI_API_KEY'),
|
|
106
|
+
'GOOGLE_API_KEY': os.getenv('GOOGLE_API_KEY') or os.getenv('GEMINI_API_KEY'),
|
|
107
|
+
}
|
|
108
|
+
return keys
|
|
109
|
+
|
|
110
|
+
def test_openai_key(api_key: str) -> bool:
|
|
111
|
+
"""Test OpenAI API key validity"""
|
|
112
|
+
if not api_key or not api_key.strip():
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
headers = {
|
|
117
|
+
'Authorization': f'Bearer {api_key.strip()}',
|
|
118
|
+
'Content-Type': 'application/json'
|
|
119
|
+
}
|
|
120
|
+
response = requests.get(
|
|
121
|
+
'https://api.openai.com/v1/models',
|
|
122
|
+
headers=headers,
|
|
123
|
+
timeout=10
|
|
124
|
+
)
|
|
125
|
+
return response.status_code == 200
|
|
126
|
+
except Exception:
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
def test_google_key(api_key: str) -> bool:
|
|
130
|
+
"""Test Google Gemini API key validity"""
|
|
131
|
+
if not api_key or not api_key.strip():
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
response = requests.get(
|
|
136
|
+
f'https://generativelanguage.googleapis.com/v1beta/models?key={api_key.strip()}',
|
|
137
|
+
timeout=10
|
|
138
|
+
)
|
|
139
|
+
return response.status_code == 200
|
|
140
|
+
except Exception:
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
def test_api_keys(keys: Dict[str, Optional[str]]) -> Dict[str, bool]:
|
|
144
|
+
"""Test all discovered API keys"""
|
|
145
|
+
results = {}
|
|
146
|
+
|
|
147
|
+
print_colored(f"\n{LIGHT_HORIZONTAL * 40}", CYAN)
|
|
148
|
+
print_colored("Testing discovered API keys...", CYAN, bold=True)
|
|
149
|
+
print_colored(f"{LIGHT_HORIZONTAL * 40}", CYAN)
|
|
150
|
+
|
|
151
|
+
for key_name, key_value in keys.items():
|
|
152
|
+
if key_value:
|
|
153
|
+
print(f"Testing {key_name}...", end=" ", flush=True)
|
|
154
|
+
if key_name == 'OPENAI_API_KEY':
|
|
155
|
+
valid = test_openai_key(key_value)
|
|
156
|
+
elif key_name in ['GOOGLE_API_KEY']:
|
|
157
|
+
valid = test_google_key(key_value)
|
|
158
|
+
else:
|
|
159
|
+
valid = False
|
|
160
|
+
|
|
161
|
+
if valid:
|
|
162
|
+
print_colored(f"{CHECK_MARK} Valid", CYAN)
|
|
163
|
+
results[key_name] = True
|
|
164
|
+
else:
|
|
165
|
+
print_colored(f"{CROSS_MARK} Invalid", YELLOW)
|
|
166
|
+
results[key_name] = False
|
|
167
|
+
else:
|
|
168
|
+
print_colored(f"{key_name}: Not found", YELLOW)
|
|
169
|
+
results[key_name] = False
|
|
170
|
+
|
|
171
|
+
return results
|
|
172
|
+
|
|
173
|
+
def get_user_keys(current_keys: Dict[str, Optional[str]]) -> Dict[str, Optional[str]]:
|
|
174
|
+
"""Interactive key entry/modification"""
|
|
175
|
+
print_colored(f"\n{create_fat_divider()}", YELLOW)
|
|
176
|
+
print_colored("API Key Configuration", YELLOW, bold=True)
|
|
177
|
+
print_colored(f"{create_fat_divider()}", YELLOW)
|
|
178
|
+
|
|
179
|
+
print_colored("You need only one API key to get started", WHITE)
|
|
180
|
+
print()
|
|
181
|
+
print_colored("Get API keys here:", WHITE)
|
|
182
|
+
print_colored(f" OpenAI {ARROW_RIGHT} https://platform.openai.com/api-keys", CYAN)
|
|
183
|
+
print_colored(f" Google Gemini {ARROW_RIGHT} https://aistudio.google.com/app/apikey", CYAN)
|
|
184
|
+
print()
|
|
185
|
+
print_colored("A free instant starter key is available from Google Gemini (above)", CYAN)
|
|
186
|
+
print()
|
|
187
|
+
|
|
188
|
+
new_keys = current_keys.copy()
|
|
189
|
+
|
|
190
|
+
for key_name in ['OPENAI_API_KEY', 'GOOGLE_API_KEY']:
|
|
191
|
+
current_value = current_keys.get(key_name, "")
|
|
192
|
+
status = "found" if current_value else "not found"
|
|
193
|
+
|
|
194
|
+
print_colored(f"{LIGHT_HORIZONTAL * 60}", CYAN)
|
|
195
|
+
print_colored(f"{key_name} (currently: {status})", WHITE, bold=True)
|
|
196
|
+
|
|
197
|
+
if current_value:
|
|
198
|
+
prompt = f"Enter new key or press ENTER to keep existing: "
|
|
199
|
+
else:
|
|
200
|
+
prompt = f"Enter API key (or press ENTER to skip): "
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
user_input = input(f"{WHITE}{prompt}{RESET}").strip()
|
|
204
|
+
if user_input:
|
|
205
|
+
new_keys[key_name] = user_input
|
|
206
|
+
elif not current_value:
|
|
207
|
+
new_keys[key_name] = None
|
|
208
|
+
except KeyboardInterrupt:
|
|
209
|
+
print_colored("\n\nSetup cancelled.", YELLOW)
|
|
210
|
+
sys.exit(0)
|
|
211
|
+
|
|
212
|
+
return new_keys
|
|
213
|
+
|
|
214
|
+
def detect_shell() -> str:
|
|
215
|
+
"""Detect user's default shell"""
|
|
216
|
+
try:
|
|
217
|
+
shell_path = os.getenv('SHELL', '/bin/bash')
|
|
218
|
+
shell_name = os.path.basename(shell_path)
|
|
219
|
+
return shell_name
|
|
220
|
+
except:
|
|
221
|
+
return 'bash'
|
|
222
|
+
|
|
223
|
+
def get_shell_init_file(shell: str) -> str:
|
|
224
|
+
"""Get the appropriate shell initialization file"""
|
|
225
|
+
home = Path.home()
|
|
226
|
+
|
|
227
|
+
shell_files = {
|
|
228
|
+
'bash': home / '.bashrc',
|
|
229
|
+
'zsh': home / '.zshrc',
|
|
230
|
+
'fish': home / '.config/fish/config.fish',
|
|
231
|
+
'csh': home / '.cshrc',
|
|
232
|
+
'tcsh': home / '.tcshrc',
|
|
233
|
+
'ksh': home / '.kshrc'
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return str(shell_files.get(shell, home / '.bashrc'))
|
|
237
|
+
|
|
238
|
+
def create_api_env_script(keys: Dict[str, str], shell: str) -> str:
|
|
239
|
+
"""Create shell-appropriate environment script"""
|
|
240
|
+
valid_keys = {k: v for k, v in keys.items() if v}
|
|
241
|
+
|
|
242
|
+
if shell == 'fish':
|
|
243
|
+
lines = []
|
|
244
|
+
for key, value in valid_keys.items():
|
|
245
|
+
lines.append(f'set -gx {key} "{value}"')
|
|
246
|
+
return '\n'.join(lines) + '\n'
|
|
247
|
+
elif shell in ['csh', 'tcsh']:
|
|
248
|
+
lines = []
|
|
249
|
+
for key, value in valid_keys.items():
|
|
250
|
+
lines.append(f'setenv {key} "{value}"')
|
|
251
|
+
return '\n'.join(lines) + '\n'
|
|
252
|
+
else: # bash, zsh, ksh and others
|
|
253
|
+
lines = []
|
|
254
|
+
for key, value in valid_keys.items():
|
|
255
|
+
lines.append(f'export {key}="{value}"')
|
|
256
|
+
return '\n'.join(lines) + '\n'
|
|
257
|
+
|
|
258
|
+
def save_configuration(valid_keys: Dict[str, str]) -> Tuple[List[str], bool]:
|
|
259
|
+
"""Save configuration to ~/.pdd/ directory"""
|
|
260
|
+
home = Path.home()
|
|
261
|
+
pdd_dir = home / '.pdd'
|
|
262
|
+
created_pdd_dir = False
|
|
263
|
+
saved_files = []
|
|
264
|
+
|
|
265
|
+
# Create .pdd directory if it doesn't exist
|
|
266
|
+
if not pdd_dir.exists():
|
|
267
|
+
pdd_dir.mkdir(mode=0o755)
|
|
268
|
+
created_pdd_dir = True
|
|
269
|
+
|
|
270
|
+
# Detect shell and create api-env script
|
|
271
|
+
shell = detect_shell()
|
|
272
|
+
api_env_content = create_api_env_script(valid_keys, shell)
|
|
273
|
+
|
|
274
|
+
# Write api-env file
|
|
275
|
+
api_env_file = pdd_dir / 'api-env'
|
|
276
|
+
api_env_file.write_text(api_env_content)
|
|
277
|
+
api_env_file.chmod(0o755)
|
|
278
|
+
saved_files.append(str(api_env_file))
|
|
279
|
+
|
|
280
|
+
# Create llm_model.csv with only valid providers
|
|
281
|
+
csv_lines = LLM_MODEL_CSV_TEMPLATE.strip().split('\n')
|
|
282
|
+
header = csv_lines[0]
|
|
283
|
+
valid_lines = [header]
|
|
284
|
+
|
|
285
|
+
for line in csv_lines[1:]:
|
|
286
|
+
if 'OPENAI_API_KEY' in line and 'OPENAI_API_KEY' in valid_keys:
|
|
287
|
+
valid_lines.append(line)
|
|
288
|
+
elif 'GOOGLE_API_KEY' in line and 'GOOGLE_API_KEY' in valid_keys:
|
|
289
|
+
valid_lines.append(line)
|
|
290
|
+
|
|
291
|
+
llm_model_file = pdd_dir / 'llm_model.csv'
|
|
292
|
+
llm_model_file.write_text('\n'.join(valid_lines) + '\n')
|
|
293
|
+
saved_files.append(str(llm_model_file))
|
|
294
|
+
|
|
295
|
+
# Update shell init file
|
|
296
|
+
init_file_path = get_shell_init_file(shell)
|
|
297
|
+
init_file = Path(init_file_path)
|
|
298
|
+
|
|
299
|
+
source_line = f'[ -f "{api_env_file}" ] && source "{api_env_file}"'
|
|
300
|
+
if shell == 'fish':
|
|
301
|
+
source_line = f'test -f "{api_env_file}"; and source "{api_env_file}"'
|
|
302
|
+
|
|
303
|
+
# Check if source line already exists
|
|
304
|
+
if init_file.exists():
|
|
305
|
+
content = init_file.read_text()
|
|
306
|
+
if str(api_env_file) not in content:
|
|
307
|
+
with init_file.open('a') as f:
|
|
308
|
+
f.write(f'\n# PDD API environment\n{source_line}\n')
|
|
309
|
+
else:
|
|
310
|
+
init_file.write_text(f'# PDD API environment\n{source_line}\n')
|
|
311
|
+
|
|
312
|
+
return saved_files, created_pdd_dir
|
|
313
|
+
|
|
314
|
+
def create_sample_prompt():
|
|
315
|
+
"""Create the sample prompt file"""
|
|
316
|
+
prompt_file = Path('hello_you_python.prompt')
|
|
317
|
+
prompt_file.write_text(HELLO_PYTHON_TEMPLATE)
|
|
318
|
+
return str(prompt_file)
|
|
319
|
+
|
|
320
|
+
def show_menu(keys: Dict[str, Optional[str]], test_results: Dict[str, bool]) -> str:
|
|
321
|
+
"""Show main menu and get user choice"""
|
|
322
|
+
print_colored(f"\n{create_divider()}", CYAN)
|
|
323
|
+
print_colored("Main Menu", CYAN, bold=True)
|
|
324
|
+
print_colored(f"{create_divider()}", CYAN)
|
|
325
|
+
|
|
326
|
+
# Show current status
|
|
327
|
+
print_colored("Current API Key Status:", WHITE, bold=True)
|
|
328
|
+
for key_name in ['OPENAI_API_KEY', 'GOOGLE_API_KEY']:
|
|
329
|
+
key_value = keys.get(key_name)
|
|
330
|
+
if key_value:
|
|
331
|
+
status = f"{CHECK_MARK} Valid" if test_results.get(key_name) else f"{CROSS_MARK} Invalid"
|
|
332
|
+
status_color = CYAN if test_results.get(key_name) else YELLOW
|
|
333
|
+
else:
|
|
334
|
+
status = "Not configured"
|
|
335
|
+
status_color = YELLOW
|
|
336
|
+
|
|
337
|
+
print(f" {key_name}: ", end="")
|
|
338
|
+
print_colored(status, status_color)
|
|
339
|
+
|
|
340
|
+
print()
|
|
341
|
+
print_colored("Options:", WHITE, bold=True)
|
|
342
|
+
print(f" 1. Re-enter API keys")
|
|
343
|
+
print(f" 2. Re-test current keys")
|
|
344
|
+
print(f" 3. Save configuration and exit")
|
|
345
|
+
print(f" 4. Exit without saving")
|
|
346
|
+
print()
|
|
347
|
+
|
|
348
|
+
while True:
|
|
349
|
+
try:
|
|
350
|
+
choice = input(f"{WHITE}Choose an option (1-4): {RESET}").strip()
|
|
351
|
+
if choice in ['1', '2', '3', '4']:
|
|
352
|
+
return choice
|
|
353
|
+
else:
|
|
354
|
+
print_colored("Please enter 1, 2, 3, or 4", YELLOW)
|
|
355
|
+
except KeyboardInterrupt:
|
|
356
|
+
print_colored("\n\nSetup cancelled.", YELLOW)
|
|
357
|
+
sys.exit(0)
|
|
358
|
+
|
|
359
|
+
def create_exit_summary(saved_files: List[str], created_pdd_dir: bool, sample_prompt_file: str, shell: str) -> str:
|
|
360
|
+
"""Create comprehensive exit summary"""
|
|
361
|
+
summary_lines = [
|
|
362
|
+
"\n\n\n\n\n",
|
|
363
|
+
create_fat_divider(),
|
|
364
|
+
"PDD Setup Complete!",
|
|
365
|
+
create_fat_divider(),
|
|
366
|
+
"",
|
|
367
|
+
"Files created and configured:",
|
|
368
|
+
""
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
# File descriptions with alignment
|
|
372
|
+
file_descriptions = []
|
|
373
|
+
if created_pdd_dir:
|
|
374
|
+
file_descriptions.append(("~/.pdd/", "PDD configuration directory"))
|
|
375
|
+
|
|
376
|
+
for file_path in saved_files:
|
|
377
|
+
if 'api-env' in file_path:
|
|
378
|
+
file_descriptions.append((file_path, "API environment variables"))
|
|
379
|
+
elif 'llm_model.csv' in file_path:
|
|
380
|
+
file_descriptions.append((file_path, "LLM model configuration"))
|
|
381
|
+
|
|
382
|
+
file_descriptions.append((sample_prompt_file, "Sample prompt for testing"))
|
|
383
|
+
file_descriptions.append(("PDD-SETUP-SUMMARY.txt", "This summary"))
|
|
384
|
+
|
|
385
|
+
# Find max file path length for alignment
|
|
386
|
+
max_path_len = max(len(path) for path, _ in file_descriptions)
|
|
387
|
+
|
|
388
|
+
for file_path, description in file_descriptions:
|
|
389
|
+
summary_lines.append(f"{file_path:<{max_path_len + 2}}{description}")
|
|
390
|
+
|
|
391
|
+
summary_lines.extend([
|
|
392
|
+
"",
|
|
393
|
+
create_divider(),
|
|
394
|
+
"",
|
|
395
|
+
"QUICK START:",
|
|
396
|
+
"",
|
|
397
|
+
f"1. Reload your shell environment:"
|
|
398
|
+
])
|
|
399
|
+
|
|
400
|
+
# Shell-specific source command
|
|
401
|
+
api_env_path = f"{Path.home()}/.pdd/api-env"
|
|
402
|
+
if shell == 'fish':
|
|
403
|
+
source_cmd = f"source {api_env_path}"
|
|
404
|
+
else:
|
|
405
|
+
source_cmd = f"source {api_env_path}"
|
|
406
|
+
|
|
407
|
+
summary_lines.extend([
|
|
408
|
+
f" {source_cmd}",
|
|
409
|
+
"",
|
|
410
|
+
f"2. Generate code from the sample prompt:",
|
|
411
|
+
f" pdd generate hello_you_python.prompt",
|
|
412
|
+
"",
|
|
413
|
+
create_divider(),
|
|
414
|
+
"",
|
|
415
|
+
"LEARN MORE:",
|
|
416
|
+
"",
|
|
417
|
+
f"{BULLET} PDD documentation: pdd --help",
|
|
418
|
+
f"{BULLET} PDD website: https://promptdriven.ai/",
|
|
419
|
+
f"{BULLET} Discord community: https://discord.gg/Yp4RTh8bG7",
|
|
420
|
+
"",
|
|
421
|
+
"TIPS:",
|
|
422
|
+
"",
|
|
423
|
+
f"{BULLET} IMPORTANT: Reload your shell environment using the source command above",
|
|
424
|
+
"",
|
|
425
|
+
f"{BULLET} Start with simple prompts and gradually increase complexity",
|
|
426
|
+
f"{BULLET} Try out 'pdd test' with your prompt+code to create test(s) pdd can use to automatically verify and fix your output code",
|
|
427
|
+
f"{BULLET} Try out 'pdd example' with your prompt+code to create examples which help pdd do better",
|
|
428
|
+
"",
|
|
429
|
+
f"{BULLET} As you get comfortable, learn configuration settings, including the .pddrc file, PDD_GENERATE_OUTPUT_PATH, and PDD_TEST_OUTPUT_PATH",
|
|
430
|
+
f"{BULLET} For larger projects, use Makefiles and/or 'pdd sync'",
|
|
431
|
+
f"{BULLET} For ongoing substantial projects, learn about llm_model.csv to optimize model cost, latency, and output quality",
|
|
432
|
+
"",
|
|
433
|
+
f"{BULLET} Use 'pdd --help' to explore all available commands",
|
|
434
|
+
"",
|
|
435
|
+
"Problems? Shout out on our Discord for help! https://discord.gg/Yp4RTh8bG7"
|
|
436
|
+
])
|
|
437
|
+
|
|
438
|
+
return '\n'.join(summary_lines)
|
|
439
|
+
|
|
440
|
+
def main():
|
|
441
|
+
"""Main setup workflow"""
|
|
442
|
+
# Initial greeting
|
|
443
|
+
print_pdd_logo()
|
|
444
|
+
|
|
445
|
+
# Discover environment
|
|
446
|
+
print_colored(f"{create_divider()}", CYAN)
|
|
447
|
+
print_colored("Discovering local configuration...", CYAN, bold=True)
|
|
448
|
+
print_colored(f"{create_divider()}", CYAN)
|
|
449
|
+
|
|
450
|
+
keys = discover_api_keys()
|
|
451
|
+
|
|
452
|
+
# Test discovered keys
|
|
453
|
+
test_results = test_api_keys(keys)
|
|
454
|
+
|
|
455
|
+
# Main interaction loop
|
|
456
|
+
while True:
|
|
457
|
+
choice = show_menu(keys, test_results)
|
|
458
|
+
|
|
459
|
+
if choice == '1':
|
|
460
|
+
# Re-enter keys
|
|
461
|
+
keys = get_user_keys(keys)
|
|
462
|
+
test_results = test_api_keys(keys)
|
|
463
|
+
|
|
464
|
+
elif choice == '2':
|
|
465
|
+
# Re-test keys
|
|
466
|
+
test_results = test_api_keys(keys)
|
|
467
|
+
|
|
468
|
+
elif choice == '3':
|
|
469
|
+
# Save and exit
|
|
470
|
+
valid_keys = {k: v for k, v in keys.items() if v and test_results.get(k)}
|
|
471
|
+
|
|
472
|
+
if not valid_keys:
|
|
473
|
+
print_colored("\nNo valid API keys to save!", YELLOW)
|
|
474
|
+
continue
|
|
475
|
+
|
|
476
|
+
print_colored(f"\n{create_divider()}", CYAN)
|
|
477
|
+
print_colored("Saving configuration...", CYAN, bold=True)
|
|
478
|
+
print_colored(f"{create_divider()}", CYAN)
|
|
479
|
+
|
|
480
|
+
try:
|
|
481
|
+
saved_files, created_pdd_dir = save_configuration(valid_keys)
|
|
482
|
+
sample_prompt_file = create_sample_prompt()
|
|
483
|
+
shell = detect_shell()
|
|
484
|
+
|
|
485
|
+
# Create and display summary
|
|
486
|
+
summary = create_exit_summary(saved_files, created_pdd_dir, sample_prompt_file, shell)
|
|
487
|
+
|
|
488
|
+
# Write summary to file
|
|
489
|
+
summary_file = Path('PDD-SETUP-SUMMARY.txt')
|
|
490
|
+
summary_file.write_text(summary)
|
|
491
|
+
|
|
492
|
+
# Display summary with colors
|
|
493
|
+
lines = summary.split('\n')
|
|
494
|
+
for line in lines:
|
|
495
|
+
if line == create_fat_divider():
|
|
496
|
+
print_colored(line, YELLOW, bold=True)
|
|
497
|
+
elif line == "PDD Setup Complete!":
|
|
498
|
+
print_colored(line, YELLOW, bold=True)
|
|
499
|
+
elif line == create_divider():
|
|
500
|
+
print_colored(line, CYAN)
|
|
501
|
+
elif line.startswith("QUICK START:") or line.startswith("LEARN MORE:") or line.startswith("TIPS:"):
|
|
502
|
+
print_colored(line, CYAN, bold=True)
|
|
503
|
+
elif "IMPORTANT:" in line or "Problems?" in line:
|
|
504
|
+
print_colored(line, YELLOW, bold=True)
|
|
505
|
+
else:
|
|
506
|
+
print(line)
|
|
507
|
+
|
|
508
|
+
break
|
|
509
|
+
|
|
510
|
+
except Exception as e:
|
|
511
|
+
print_colored(f"Error saving configuration: {e}", YELLOW)
|
|
512
|
+
continue
|
|
513
|
+
|
|
514
|
+
elif choice == '4':
|
|
515
|
+
# Exit without saving
|
|
516
|
+
print_colored("\nExiting without saving configuration.", YELLOW)
|
|
517
|
+
break
|
|
518
|
+
|
|
519
|
+
if __name__ == '__main__':
|
|
520
|
+
try:
|
|
521
|
+
main()
|
|
522
|
+
except KeyboardInterrupt:
|
|
523
|
+
print_colored("\n\nSetup cancelled.", YELLOW)
|
|
524
|
+
sys.exit(0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pdd-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.58
|
|
4
4
|
Summary: PDD (Prompt-Driven Development) Command Line Interface
|
|
5
5
|
Author: Greg Tanaka
|
|
6
6
|
Author-email: glt@alumni.caltech.edu
|
|
@@ -51,7 +51,7 @@ Requires-Dist: build; extra == "dev"
|
|
|
51
51
|
Requires-Dist: twine; extra == "dev"
|
|
52
52
|
Dynamic: license-file
|
|
53
53
|
|
|
54
|
-
.. image:: https://img.shields.io/badge/pdd--cli-v0.0.
|
|
54
|
+
.. image:: https://img.shields.io/badge/pdd--cli-v0.0.58-blue
|
|
55
55
|
:alt: PDD-CLI Version
|
|
56
56
|
|
|
57
57
|
.. image:: https://img.shields.io/badge/Discord-join%20chat-7289DA.svg?logo=discord&logoColor=white&link=https://discord.gg/Yp4RTh8bG7
|
|
@@ -128,7 +128,7 @@ After installation, verify:
|
|
|
128
128
|
|
|
129
129
|
pdd --version
|
|
130
130
|
|
|
131
|
-
You'll see the current PDD version (e.g., 0.0.
|
|
131
|
+
You'll see the current PDD version (e.g., 0.0.58).
|
|
132
132
|
|
|
133
133
|
Getting Started with Examples
|
|
134
134
|
-----------------------------
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
pdd/__init__.py,sha256=
|
|
1
|
+
pdd/__init__.py,sha256=PcN6Adk2Ea2dffgFJe0eyB538DRmYKrwUXjuu7IrSPQ,633
|
|
2
2
|
pdd/auto_deps_main.py,sha256=cpP3bbzVL3jomrGinpzTxzIDIC8tmDDYOwUAC1TKRaw,3970
|
|
3
3
|
pdd/auto_include.py,sha256=OJcdcwTwJNqHPHKG9P4m9Ij-PiLex0EbuwJP0uiQi_Y,7484
|
|
4
4
|
pdd/auto_update.py,sha256=w6jzTnMiYRNpwQHQxWNiIAwQ0d6xh1iOB3xgDsabWtc,5236
|
|
@@ -110,9 +110,10 @@ pdd/prompts/unfinished_prompt_LLM.prompt,sha256=vud_G9PlVv9Ig64uBC-hPEVFRk5lwpc8
|
|
|
110
110
|
pdd/prompts/update_prompt_LLM.prompt,sha256=prIc8uLp2jqnLTHt6JvWDZGanPZipivhhYeXe0lVaYw,1328
|
|
111
111
|
pdd/prompts/xml_convertor_LLM.prompt,sha256=YGRGXJeg6EhM9690f-SKqQrKqSJjLFD51UrPOlO0Frg,2786
|
|
112
112
|
pdd/templates/architecture/architecture_json.prompt,sha256=uSNSsKTL-cuMMhi5a4GSpC94DKkOFAlXh7R0CUlo-hg,8126
|
|
113
|
-
pdd_cli-0.0.
|
|
114
|
-
pdd_cli-0.0.
|
|
115
|
-
pdd_cli-0.0.
|
|
116
|
-
pdd_cli-0.0.
|
|
117
|
-
pdd_cli-0.0.
|
|
118
|
-
pdd_cli-0.0.
|
|
113
|
+
pdd_cli-0.0.58.data/data/utils/pdd-setup.py,sha256=sQ-HwwSN-ER4xz77EZqfxH8W0gG-kDtqj7LaR7SomA4,18955
|
|
114
|
+
pdd_cli-0.0.58.dist-info/licenses/LICENSE,sha256=kvTJnnxPVTYlGKSY4ZN1kzdmJ0lxRdNWxgupaB27zsU,1066
|
|
115
|
+
pdd_cli-0.0.58.dist-info/METADATA,sha256=TIrlo_oc6NbiHyi_WqFxqsRSOXrhEkYcuFoN5eCaD3s,12597
|
|
116
|
+
pdd_cli-0.0.58.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
117
|
+
pdd_cli-0.0.58.dist-info/entry_points.txt,sha256=Kr8HtNVb8uHZtQJNH4DnF8j7WNgWQbb7_Pw5hECSR-I,36
|
|
118
|
+
pdd_cli-0.0.58.dist-info/top_level.txt,sha256=xjnhIACeMcMeDfVNREgQZl4EbTni2T11QkL5r7E-sbE,4
|
|
119
|
+
pdd_cli-0.0.58.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|