pdd-cli 0.0.61__py3-none-any.whl → 0.0.63__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.py +129 -9
- pdd/data/language_format.csv +3 -0
- pdd/data/llm_model.csv +2 -2
- pdd/preprocess.py +124 -5
- pdd/templates/architecture/architecture_json.prompt +61 -7
- pdd/templates/generic/generate_prompt.prompt +47 -15
- {pdd_cli-0.0.61.dist-info → pdd_cli-0.0.63.dist-info}/METADATA +3 -3
- {pdd_cli-0.0.61.dist-info → pdd_cli-0.0.63.dist-info}/RECORD +13 -13
- {pdd_cli-0.0.61.dist-info → pdd_cli-0.0.63.dist-info}/WHEEL +0 -0
- {pdd_cli-0.0.61.dist-info → pdd_cli-0.0.63.dist-info}/entry_points.txt +0 -0
- {pdd_cli-0.0.61.dist-info → pdd_cli-0.0.63.dist-info}/licenses/LICENSE +0 -0
- {pdd_cli-0.0.61.dist-info → pdd_cli-0.0.63.dist-info}/top_level.txt +0 -0
pdd/__init__.py
CHANGED
pdd/cli.py
CHANGED
|
@@ -14,9 +14,11 @@ from typing import Any, Dict, List, Optional, Tuple
|
|
|
14
14
|
from pathlib import Path # Import Path
|
|
15
15
|
|
|
16
16
|
import click
|
|
17
|
+
from rich import box
|
|
17
18
|
from rich.console import Console
|
|
18
|
-
from rich.theme import Theme
|
|
19
19
|
from rich.markup import MarkupError, escape
|
|
20
|
+
from rich.table import Table
|
|
21
|
+
from rich.theme import Theme
|
|
20
22
|
|
|
21
23
|
# --- Relative Imports for Internal Modules ---
|
|
22
24
|
from . import DEFAULT_STRENGTH, __version__, DEFAULT_TIME
|
|
@@ -449,20 +451,138 @@ def templates_show(name: str):
|
|
|
449
451
|
try:
|
|
450
452
|
data = template_registry.show_template(name)
|
|
451
453
|
summary = data.get("summary", {})
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
454
|
+
|
|
455
|
+
def _render_key_value_table(title: Optional[str], items: List[Tuple[str, Any]], *, highlight_path: bool = False):
|
|
456
|
+
"""Render a 2-column Rich table for key/value pairs."""
|
|
457
|
+
|
|
458
|
+
table = Table(show_header=False, box=box.SIMPLE, expand=True)
|
|
459
|
+
table.add_column("Field", style="info", no_wrap=True)
|
|
460
|
+
table.add_column("Value", overflow="fold")
|
|
461
|
+
|
|
462
|
+
added_rows = False
|
|
463
|
+
for label, value in items:
|
|
464
|
+
if value in (None, "", [], {}):
|
|
465
|
+
continue
|
|
466
|
+
if isinstance(value, (list, tuple)):
|
|
467
|
+
value_str = ", ".join(str(v) for v in value)
|
|
468
|
+
else:
|
|
469
|
+
value_str = str(value)
|
|
470
|
+
|
|
471
|
+
if highlight_path and label.lower() == "path":
|
|
472
|
+
value_markup = f"[path]{escape(value_str)}[/path]"
|
|
473
|
+
else:
|
|
474
|
+
value_markup = escape(value_str)
|
|
475
|
+
|
|
476
|
+
table.add_row(label, value_markup)
|
|
477
|
+
added_rows = True
|
|
478
|
+
|
|
479
|
+
if added_rows:
|
|
480
|
+
if title:
|
|
481
|
+
console.print(f"[info]{title}[/info]")
|
|
482
|
+
console.print(table)
|
|
483
|
+
|
|
484
|
+
summary_items = [
|
|
485
|
+
("Name", summary.get("name")),
|
|
486
|
+
("Description", summary.get("description")),
|
|
487
|
+
("Version", summary.get("version")),
|
|
488
|
+
("Tags", summary.get("tags", [])),
|
|
489
|
+
("Language", summary.get("language")),
|
|
490
|
+
("Output", summary.get("output")),
|
|
491
|
+
("Path", summary.get("path")),
|
|
492
|
+
]
|
|
493
|
+
_render_key_value_table("Template Summary:", summary_items, highlight_path=True)
|
|
494
|
+
|
|
456
495
|
if data.get("variables"):
|
|
457
496
|
console.print("\n[info]Variables:[/info]")
|
|
458
|
-
|
|
459
|
-
|
|
497
|
+
variables_table = Table(box=box.SIMPLE_HEAD, show_lines=False, expand=True)
|
|
498
|
+
variables_table.add_column("Name", style="bold", no_wrap=True)
|
|
499
|
+
variables_table.add_column("Required", style="info", no_wrap=True)
|
|
500
|
+
variables_table.add_column("Type", no_wrap=True)
|
|
501
|
+
variables_table.add_column("Description", overflow="fold")
|
|
502
|
+
variables_table.add_column("Default/Examples", overflow="fold")
|
|
503
|
+
|
|
504
|
+
for var_name, var_meta in data["variables"].items():
|
|
505
|
+
required = var_meta.get("required")
|
|
506
|
+
if required is True:
|
|
507
|
+
required_str = "Yes"
|
|
508
|
+
elif required is False:
|
|
509
|
+
required_str = "No"
|
|
510
|
+
else:
|
|
511
|
+
required_str = "-"
|
|
512
|
+
|
|
513
|
+
var_type = escape(str(var_meta.get("type", "-")))
|
|
514
|
+
description = escape(str(var_meta.get("description", "")))
|
|
515
|
+
|
|
516
|
+
default_parts: List[str] = []
|
|
517
|
+
default_value = var_meta.get("default")
|
|
518
|
+
if default_value not in (None, ""):
|
|
519
|
+
default_parts.append(f"default: {default_value}")
|
|
520
|
+
|
|
521
|
+
examples_value = var_meta.get("examples")
|
|
522
|
+
if examples_value:
|
|
523
|
+
if isinstance(examples_value, (list, tuple)):
|
|
524
|
+
examples_str = ", ".join(str(example) for example in examples_value)
|
|
525
|
+
else:
|
|
526
|
+
examples_str = str(examples_value)
|
|
527
|
+
default_parts.append(f"examples: {examples_str}")
|
|
528
|
+
|
|
529
|
+
example_paths_value = var_meta.get("example_paths")
|
|
530
|
+
if example_paths_value:
|
|
531
|
+
if isinstance(example_paths_value, (list, tuple)):
|
|
532
|
+
example_paths_str = ", ".join(str(example) for example in example_paths_value)
|
|
533
|
+
else:
|
|
534
|
+
example_paths_str = str(example_paths_value)
|
|
535
|
+
default_parts.append(f"paths: {example_paths_str}")
|
|
536
|
+
|
|
537
|
+
default_examples = "\n".join(default_parts) if default_parts else "-"
|
|
538
|
+
|
|
539
|
+
variables_table.add_row(
|
|
540
|
+
escape(str(var_name)),
|
|
541
|
+
required_str,
|
|
542
|
+
var_type,
|
|
543
|
+
description,
|
|
544
|
+
escape(default_examples),
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
console.print(variables_table)
|
|
548
|
+
|
|
460
549
|
if data.get("usage"):
|
|
461
550
|
console.print("\n[info]Usage:[/info]")
|
|
462
|
-
|
|
551
|
+
usage = data["usage"]
|
|
552
|
+
if isinstance(usage, dict):
|
|
553
|
+
for group_name, entries in usage.items():
|
|
554
|
+
console.print(f"[bold]{escape(str(group_name))}[/bold]")
|
|
555
|
+
usage_table = Table(box=box.SIMPLE, show_lines=False, expand=True)
|
|
556
|
+
usage_table.add_column("Name", style="bold", no_wrap=True)
|
|
557
|
+
usage_table.add_column("Command", overflow="fold")
|
|
558
|
+
|
|
559
|
+
if isinstance(entries, (list, tuple)):
|
|
560
|
+
iterable_entries = entries
|
|
561
|
+
else:
|
|
562
|
+
iterable_entries = [entries]
|
|
563
|
+
|
|
564
|
+
for entry in iterable_entries:
|
|
565
|
+
if isinstance(entry, dict):
|
|
566
|
+
name_value = escape(str(entry.get("name", "")))
|
|
567
|
+
command_value = escape(str(entry.get("command", "")))
|
|
568
|
+
else:
|
|
569
|
+
name_value = "-"
|
|
570
|
+
command_value = escape(str(entry))
|
|
571
|
+
usage_table.add_row(name_value, f"[command]{command_value}[/command]")
|
|
572
|
+
|
|
573
|
+
if usage_table.row_count:
|
|
574
|
+
console.print(usage_table)
|
|
575
|
+
else:
|
|
576
|
+
console.print(usage)
|
|
577
|
+
|
|
463
578
|
if data.get("discover"):
|
|
464
579
|
console.print("\n[info]Discover:[/info]")
|
|
465
|
-
|
|
580
|
+
discover = data["discover"]
|
|
581
|
+
if isinstance(discover, dict):
|
|
582
|
+
discover_items = [(str(key), value) for key, value in discover.items()]
|
|
583
|
+
_render_key_value_table(None, discover_items)
|
|
584
|
+
else:
|
|
585
|
+
console.print(discover)
|
|
466
586
|
if data.get("output_schema"):
|
|
467
587
|
console.print("\n[info]Output Schema:[/info]")
|
|
468
588
|
try:
|
pdd/data/language_format.csv
CHANGED
pdd/data/llm_model.csv
CHANGED
|
@@ -2,7 +2,7 @@ provider,model,input,output,coding_arena_elo,base_url,api_key,max_reasoning_toke
|
|
|
2
2
|
OpenAI,gpt-5-nano,0.05,0.4,1249,,OPENAI_API_KEY,0,True,none
|
|
3
3
|
Google,vertex_ai/gemini-2.5-flash,0.15,0.6,1290,,VERTEX_CREDENTIALS,0,True,effort
|
|
4
4
|
Google,gemini/gemini-2.5-pro,1.25,10.0,1360,,GEMINI_API_KEY,0,True,none
|
|
5
|
-
Google,vertex_ai/claude-sonnet-4,3.0,15.0,1359,,VERTEX_CREDENTIALS,64000,True,budget
|
|
5
|
+
Google,vertex_ai/claude-sonnet-4-5,3.0,15.0,1359,,VERTEX_CREDENTIALS,64000,True,budget
|
|
6
6
|
Google,vertex_ai/gemini-2.5-pro,1.25,10.0,1405,,VERTEX_CREDENTIALS,0,True,none
|
|
7
7
|
OpenAI,gpt-5-mini,0.25,2.0,1325,,OPENAI_API_KEY,0,True,effort
|
|
8
8
|
OpenAI,gpt-5,1.25,10.0,1482,,OPENAI_API_KEY,0,True,effort
|
|
@@ -15,6 +15,6 @@ OpenAI,openai/mlx-community/Qwen3-30B-A3B-4bit,0,0,1040,http://localhost:8080,,0
|
|
|
15
15
|
OpenAI,lm_studio/openai-gpt-oss-120b-mlx-6,0.0001,0,1082,http://localhost:1234/v1,,0,True,none
|
|
16
16
|
Fireworks,fireworks_ai/accounts/fireworks/models/glm-4p5,3.0,8.0,1364,,FIREWORKS_API_KEY,0,False,none
|
|
17
17
|
OpenAI,groq/moonshotai/kimi-k2-instruct,1.0,3.0,1330,,GROQ_API_KEY,0,True,none
|
|
18
|
-
Anthropic,anthropic/claude-sonnet-4-
|
|
18
|
+
Anthropic,anthropic/claude-sonnet-4-5-20250929,3.0,15.0,1356,,ANTHROPIC_API_KEY,64000,True,budget
|
|
19
19
|
Anthropic,anthropic/claude-opus-4-1-20250805,3.0,15.0,1474,,ANTHROPIC_API_KEY,32000,True,budget
|
|
20
20
|
Anthropic,anthropic/claude-3-5-haiku-20241022,3.0,15.0,1133,,ANTHROPIC_API_KEY,8192,True,budget
|
pdd/preprocess.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
3
|
import subprocess
|
|
4
|
-
from typing import List, Optional
|
|
4
|
+
from typing import List, Optional, Tuple
|
|
5
5
|
import traceback
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
from rich.panel import Panel
|
|
@@ -11,22 +11,110 @@ from rich.traceback import install
|
|
|
11
11
|
install()
|
|
12
12
|
console = Console()
|
|
13
13
|
|
|
14
|
+
# Debug/Instrumentation controls
|
|
15
|
+
_DEBUG_PREPROCESS = str(os.getenv("PDD_PREPROCESS_DEBUG", "")).lower() in ("1", "true", "yes", "on")
|
|
16
|
+
_DEBUG_OUTPUT_FILE = os.getenv("PDD_PREPROCESS_DEBUG_FILE") # Optional path to write a debug report
|
|
17
|
+
_DEBUG_EVENTS: List[str] = []
|
|
18
|
+
|
|
19
|
+
def _dbg(msg: str) -> None:
|
|
20
|
+
if _DEBUG_PREPROCESS:
|
|
21
|
+
console.print(f"[dim][PPD][preprocess][/dim] {escape(msg)}")
|
|
22
|
+
_DEBUG_EVENTS.append(msg)
|
|
23
|
+
|
|
24
|
+
def _write_debug_report() -> None:
|
|
25
|
+
if _DEBUG_PREPROCESS and _DEBUG_OUTPUT_FILE:
|
|
26
|
+
try:
|
|
27
|
+
with open(_DEBUG_OUTPUT_FILE, "w", encoding="utf-8") as fh:
|
|
28
|
+
fh.write("Preprocess Debug Report\n\n")
|
|
29
|
+
for line in _DEBUG_EVENTS:
|
|
30
|
+
fh.write(line + "\n")
|
|
31
|
+
console.print(f"[green]Debug report written to:[/green] {_DEBUG_OUTPUT_FILE}")
|
|
32
|
+
except Exception as e:
|
|
33
|
+
# Report the error so users know why the log file wasn't written
|
|
34
|
+
console.print(f"[yellow]Warning: Could not write debug report to {_DEBUG_OUTPUT_FILE}: {e}[/yellow]")
|
|
35
|
+
elif _DEBUG_PREPROCESS and not _DEBUG_OUTPUT_FILE:
|
|
36
|
+
console.print("[dim]Debug mode enabled but PDD_PREPROCESS_DEBUG_FILE not set (output shown in console only)[/dim]")
|
|
37
|
+
|
|
38
|
+
def _extract_fence_spans(text: str) -> List[Tuple[int, int]]:
|
|
39
|
+
"""Return list of (start, end) spans for fenced code blocks ```...```.
|
|
40
|
+
|
|
41
|
+
The spans are [start, end) indices in the original text.
|
|
42
|
+
"""
|
|
43
|
+
spans: List[Tuple[int, int]] = []
|
|
44
|
+
try:
|
|
45
|
+
for m in re.finditer(r"```[\w\s]*\n[\s\S]*?```", text):
|
|
46
|
+
spans.append((m.start(), m.end()))
|
|
47
|
+
except Exception:
|
|
48
|
+
pass
|
|
49
|
+
return spans
|
|
50
|
+
|
|
51
|
+
def _is_inside_any_span(idx: int, spans: List[Tuple[int, int]]) -> bool:
|
|
52
|
+
for s, e in spans:
|
|
53
|
+
if s <= idx < e:
|
|
54
|
+
return True
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
def _scan_risky_placeholders(text: str) -> Tuple[List[Tuple[int, str]], List[Tuple[int, str]]]:
|
|
58
|
+
"""Scan for risky placeholders outside code fences.
|
|
59
|
+
|
|
60
|
+
Returns two lists of (line_no, snippet):
|
|
61
|
+
- single_brace: matches like {name} not doubled and not part of {{...}}
|
|
62
|
+
- template_brace: `${...}` occurrences (which include single { ... })
|
|
63
|
+
"""
|
|
64
|
+
single_brace: List[Tuple[int, str]] = []
|
|
65
|
+
template_brace: List[Tuple[int, str]] = []
|
|
66
|
+
try:
|
|
67
|
+
fence_spans = _extract_fence_spans(text)
|
|
68
|
+
# Single-brace variable placeholders (avoid matching {{ or }})
|
|
69
|
+
for m in re.finditer(r"(?<!\{)\{([A-Za-z_][A-Za-z0-9_]*)\}(?!\})", text):
|
|
70
|
+
if not _is_inside_any_span(m.start(), fence_spans):
|
|
71
|
+
line_no = text.count("\n", 0, m.start()) + 1
|
|
72
|
+
single_brace.append((line_no, m.group(0)))
|
|
73
|
+
# JavaScript template placeholders like ${...}
|
|
74
|
+
for m in re.finditer(r"\$\{[^\}]+\}", text):
|
|
75
|
+
if not _is_inside_any_span(m.start(), fence_spans):
|
|
76
|
+
line_no = text.count("\n", 0, m.start()) + 1
|
|
77
|
+
template_brace.append((line_no, m.group(0)))
|
|
78
|
+
except Exception:
|
|
79
|
+
pass
|
|
80
|
+
return single_brace, template_brace
|
|
81
|
+
|
|
14
82
|
def preprocess(prompt: str, recursive: bool = False, double_curly_brackets: bool = True, exclude_keys: Optional[List[str]] = None) -> str:
|
|
15
83
|
try:
|
|
16
84
|
if not prompt:
|
|
17
85
|
console.print("[bold red]Error:[/bold red] Empty prompt provided")
|
|
18
86
|
return ""
|
|
87
|
+
_DEBUG_EVENTS.clear()
|
|
88
|
+
_dbg(f"Start preprocess(recursive={recursive}, double_curly={double_curly_brackets}, exclude_keys={exclude_keys})")
|
|
89
|
+
_dbg(f"Initial length: {len(prompt)} characters")
|
|
19
90
|
console.print(Panel("Starting prompt preprocessing", style="bold blue"))
|
|
20
91
|
prompt = process_backtick_includes(prompt, recursive)
|
|
92
|
+
_dbg("After backtick includes processed")
|
|
21
93
|
prompt = process_xml_tags(prompt, recursive)
|
|
94
|
+
_dbg("After XML-like tags processed")
|
|
22
95
|
if double_curly_brackets:
|
|
23
96
|
prompt = double_curly(prompt, exclude_keys)
|
|
97
|
+
_dbg("After double_curly execution")
|
|
98
|
+
# Scan for risky placeholders remaining outside code fences
|
|
99
|
+
singles, templates = _scan_risky_placeholders(prompt)
|
|
100
|
+
if singles:
|
|
101
|
+
_dbg(f"WARNING: Found {len(singles)} single-brace placeholders outside code fences (examples):")
|
|
102
|
+
for ln, frag in singles[:5]:
|
|
103
|
+
_dbg(f" line {ln}: {frag}")
|
|
104
|
+
if templates:
|
|
105
|
+
_dbg(f"INFO: Found {len(templates)} template literals ${'{...'} outside code fences (examples):")
|
|
106
|
+
for ln, frag in templates[:5]:
|
|
107
|
+
_dbg(f" line {ln}: {frag}")
|
|
24
108
|
# Don't trim whitespace that might be significant for the tests
|
|
25
109
|
console.print(Panel("Preprocessing complete", style="bold green"))
|
|
110
|
+
_dbg(f"Final length: {len(prompt)} characters")
|
|
111
|
+
_write_debug_report()
|
|
26
112
|
return prompt
|
|
27
113
|
except Exception as e:
|
|
28
114
|
console.print(f"[bold red]Error during preprocessing:[/bold red] {str(e)}")
|
|
29
115
|
console.print(Panel(traceback.format_exc(), title="Error Details", style="red"))
|
|
116
|
+
_dbg(f"Exception: {str(e)}")
|
|
117
|
+
_write_debug_report()
|
|
30
118
|
return prompt
|
|
31
119
|
|
|
32
120
|
def get_file_path(file_name: str) -> str:
|
|
@@ -45,14 +133,17 @@ def process_backtick_includes(text: str, recursive: bool) -> str:
|
|
|
45
133
|
content = file.read()
|
|
46
134
|
if recursive:
|
|
47
135
|
content = preprocess(content, recursive=True, double_curly_brackets=False)
|
|
136
|
+
_dbg(f"Included via backticks: {file_path} (len={len(content)})")
|
|
48
137
|
return f"```{content}```"
|
|
49
138
|
except FileNotFoundError:
|
|
50
139
|
console.print(f"[bold red]Warning:[/bold red] File not found: {file_path}")
|
|
140
|
+
_dbg(f"Missing backtick include: {file_path}")
|
|
51
141
|
# First pass (recursive=True): leave the tag so a later env expansion can resolve it
|
|
52
142
|
# Second pass (recursive=False): replace with a visible placeholder
|
|
53
143
|
return match.group(0) if recursive else f"```[File not found: {file_path}]```"
|
|
54
144
|
except Exception as e:
|
|
55
145
|
console.print(f"[bold red]Error processing include:[/bold red] {str(e)}")
|
|
146
|
+
_dbg(f"Error processing backtick include {file_path}: {e}")
|
|
56
147
|
return f"```[Error processing include: {file_path}]```"
|
|
57
148
|
prev_text = ""
|
|
58
149
|
current_text = text
|
|
@@ -80,14 +171,17 @@ def process_include_tags(text: str, recursive: bool) -> str:
|
|
|
80
171
|
content = file.read()
|
|
81
172
|
if recursive:
|
|
82
173
|
content = preprocess(content, recursive=True, double_curly_brackets=False)
|
|
174
|
+
_dbg(f"Included via XML tag: {file_path} (len={len(content)})")
|
|
83
175
|
return content
|
|
84
176
|
except FileNotFoundError:
|
|
85
177
|
console.print(f"[bold red]Warning:[/bold red] File not found: {file_path}")
|
|
178
|
+
_dbg(f"Missing XML include: {file_path}")
|
|
86
179
|
# First pass (recursive=True): leave the tag so a later env expansion can resolve it
|
|
87
180
|
# Second pass (recursive=False): replace with a visible placeholder
|
|
88
181
|
return match.group(0) if recursive else f"[File not found: {file_path}]"
|
|
89
182
|
except Exception as e:
|
|
90
183
|
console.print(f"[bold red]Error processing include:[/bold red] {str(e)}")
|
|
184
|
+
_dbg(f"Error processing XML include {file_path}: {e}")
|
|
91
185
|
return f"[Error processing include: {file_path}]"
|
|
92
186
|
prev_text = ""
|
|
93
187
|
current_text = text
|
|
@@ -113,15 +207,18 @@ def process_shell_tags(text: str, recursive: bool) -> str:
|
|
|
113
207
|
# Defer execution until after env var expansion
|
|
114
208
|
return match.group(0)
|
|
115
209
|
console.print(f"Executing shell command: [cyan]{escape(command)}[/cyan]")
|
|
210
|
+
_dbg(f"Shell tag command: {command}")
|
|
116
211
|
try:
|
|
117
212
|
result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
|
|
118
213
|
return result.stdout
|
|
119
214
|
except subprocess.CalledProcessError as e:
|
|
120
215
|
error_msg = f"Command '{command}' returned non-zero exit status {e.returncode}."
|
|
121
216
|
console.print(f"[bold red]Error:[/bold red] {error_msg}")
|
|
217
|
+
_dbg(f"Shell command error: {error_msg}")
|
|
122
218
|
return f"Error: {error_msg}"
|
|
123
219
|
except Exception as e:
|
|
124
220
|
console.print(f"[bold red]Error executing shell command:[/bold red] {str(e)}")
|
|
221
|
+
_dbg(f"Shell execution exception: {e}")
|
|
125
222
|
return f"[Shell execution error: {str(e)}]"
|
|
126
223
|
return re.sub(pattern, replace_shell, text, flags=re.DOTALL)
|
|
127
224
|
|
|
@@ -133,24 +230,30 @@ def process_web_tags(text: str, recursive: bool) -> str:
|
|
|
133
230
|
# Defer network operations until after env var expansion
|
|
134
231
|
return match.group(0)
|
|
135
232
|
console.print(f"Scraping web content from: [cyan]{url}[/cyan]")
|
|
233
|
+
_dbg(f"Web tag URL: {url}")
|
|
136
234
|
try:
|
|
137
235
|
try:
|
|
138
236
|
from firecrawl import FirecrawlApp
|
|
139
237
|
except ImportError:
|
|
238
|
+
_dbg("firecrawl import failed; package not installed")
|
|
140
239
|
return f"[Error: firecrawl-py package not installed. Cannot scrape {url}]"
|
|
141
240
|
api_key = os.environ.get('FIRECRAWL_API_KEY')
|
|
142
241
|
if not api_key:
|
|
143
242
|
console.print("[bold yellow]Warning:[/bold yellow] FIRECRAWL_API_KEY not found in environment")
|
|
243
|
+
_dbg("FIRECRAWL_API_KEY not set")
|
|
144
244
|
return f"[Error: FIRECRAWL_API_KEY not set. Cannot scrape {url}]"
|
|
145
245
|
app = FirecrawlApp(api_key=api_key)
|
|
146
246
|
response = app.scrape_url(url, formats=['markdown'])
|
|
147
247
|
if hasattr(response, 'markdown'):
|
|
248
|
+
_dbg(f"Web scrape returned markdown (len={len(response.markdown)})")
|
|
148
249
|
return response.markdown
|
|
149
250
|
else:
|
|
150
251
|
console.print(f"[bold yellow]Warning:[/bold yellow] No markdown content returned for {url}")
|
|
252
|
+
_dbg("Web scrape returned no markdown content")
|
|
151
253
|
return f"[No content available for {url}]"
|
|
152
254
|
except Exception as e:
|
|
153
255
|
console.print(f"[bold red]Error scraping web content:[/bold red] {str(e)}")
|
|
256
|
+
_dbg(f"Web scraping exception: {e}")
|
|
154
257
|
return f"[Web scraping error: {str(e)}]"
|
|
155
258
|
return re.sub(pattern, replace_web, text, flags=re.DOTALL)
|
|
156
259
|
|
|
@@ -173,11 +276,14 @@ def process_include_many_tags(text: str, recursive: bool) -> str:
|
|
|
173
276
|
console.print(f"Including (many): [cyan]{full_path}[/cyan]")
|
|
174
277
|
with open(full_path, 'r', encoding='utf-8') as fh:
|
|
175
278
|
contents.append(fh.read())
|
|
279
|
+
_dbg(f"Included (many): {p}")
|
|
176
280
|
except FileNotFoundError:
|
|
177
281
|
console.print(f"[bold red]Warning:[/bold red] File not found: {p}")
|
|
282
|
+
_dbg(f"Missing include-many: {p}")
|
|
178
283
|
contents.append(f"[File not found: {p}]")
|
|
179
284
|
except Exception as e:
|
|
180
285
|
console.print(f"[bold red]Error processing include-many:[/bold red] {str(e)}")
|
|
286
|
+
_dbg(f"Error processing include-many {p}: {e}")
|
|
181
287
|
contents.append(f"[Error processing include: {p}]")
|
|
182
288
|
return "\n".join(contents)
|
|
183
289
|
return re.sub(pattern, replace_many, text, flags=re.DOTALL)
|
|
@@ -187,6 +293,7 @@ def double_curly(text: str, exclude_keys: Optional[List[str]] = None) -> str:
|
|
|
187
293
|
exclude_keys = []
|
|
188
294
|
|
|
189
295
|
console.print("Doubling curly brackets...")
|
|
296
|
+
_dbg("double_curly invoked")
|
|
190
297
|
|
|
191
298
|
# Special case handling for specific test patterns
|
|
192
299
|
if "Mix of {excluded{inner}} nesting" in text and "excluded" in exclude_keys:
|
|
@@ -210,8 +317,8 @@ def double_curly(text: str, exclude_keys: Optional[List[str]] = None) -> str:
|
|
|
210
317
|
"2": {{"id": "2", "name": "Resource Two"}}
|
|
211
318
|
}}"""
|
|
212
319
|
|
|
213
|
-
# Protect ${IDENT} placeholders so
|
|
214
|
-
#
|
|
320
|
+
# Protect ${IDENT} placeholders so we can safely double braces, then restore
|
|
321
|
+
# them as ${{IDENT}} to avoid PromptTemplate interpreting {IDENT}.
|
|
215
322
|
protected_vars: List[str] = []
|
|
216
323
|
def _protect_var(m):
|
|
217
324
|
protected_vars.append(m.group(0))
|
|
@@ -235,10 +342,22 @@ def double_curly(text: str, exclude_keys: Optional[List[str]] = None) -> str:
|
|
|
235
342
|
# Restore already doubled brackets
|
|
236
343
|
text = re.sub(r'__ALREADY_DOUBLED__(.*?)__END_ALREADY__', r'{{\1}}', text)
|
|
237
344
|
|
|
238
|
-
# Restore protected ${IDENT} placeholders
|
|
345
|
+
# Restore protected ${IDENT} placeholders as ${{IDENT}} so single braces
|
|
346
|
+
# don't leak into PromptTemplate formatting. This is safe for JS template
|
|
347
|
+
# literals and prevents missing-key errors in later formatting steps.
|
|
239
348
|
def _restore_var(m):
|
|
240
349
|
idx = int(m.group(1))
|
|
241
|
-
|
|
350
|
+
if 0 <= idx < len(protected_vars):
|
|
351
|
+
original = protected_vars[idx] # e.g., ${FOO}
|
|
352
|
+
try:
|
|
353
|
+
inner = re.match(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}", original)
|
|
354
|
+
if inner:
|
|
355
|
+
# Build as concatenation to avoid f-string brace escaping confusion
|
|
356
|
+
return "${{" + inner.group(1) + "}}" # -> ${{FOO}}
|
|
357
|
+
except Exception:
|
|
358
|
+
pass
|
|
359
|
+
return original
|
|
360
|
+
return m.group(0)
|
|
242
361
|
text = re.sub(r"__PDD_VAR_(\d+)__", _restore_var, text)
|
|
243
362
|
|
|
244
363
|
# Special handling for code blocks
|
|
@@ -66,13 +66,14 @@ output_schema:
|
|
|
66
66
|
type: array
|
|
67
67
|
items:
|
|
68
68
|
type: object
|
|
69
|
-
required: [reason, description, dependencies, priority, filename]
|
|
69
|
+
required: [reason, description, dependencies, priority, filename, filepath]
|
|
70
70
|
properties:
|
|
71
71
|
reason: { type: string }
|
|
72
72
|
description: { type: string }
|
|
73
73
|
dependencies: { type: array, items: { type: string } }
|
|
74
74
|
priority: { type: integer, minimum: 1 }
|
|
75
75
|
filename: { type: string }
|
|
76
|
+
filepath: { type: string }
|
|
76
77
|
tags: { type: array, items: { type: string } }
|
|
77
78
|
interface:
|
|
78
79
|
type: object
|
|
@@ -83,8 +84,30 @@ output_schema:
|
|
|
83
84
|
type: object
|
|
84
85
|
properties:
|
|
85
86
|
route: { type: string }
|
|
86
|
-
params:
|
|
87
|
-
|
|
87
|
+
params:
|
|
88
|
+
type: array
|
|
89
|
+
items:
|
|
90
|
+
type: object
|
|
91
|
+
required: [name, type]
|
|
92
|
+
properties:
|
|
93
|
+
name: { type: string }
|
|
94
|
+
type: { type: string }
|
|
95
|
+
description: { type: string }
|
|
96
|
+
dataSources:
|
|
97
|
+
type: array
|
|
98
|
+
items:
|
|
99
|
+
type: object
|
|
100
|
+
required: [kind, source]
|
|
101
|
+
properties:
|
|
102
|
+
kind: { enum: [api, query, stream, file, cache, message, job, other] }
|
|
103
|
+
source: { type: string }
|
|
104
|
+
method: { type: string }
|
|
105
|
+
description: { type: string }
|
|
106
|
+
auth: { type: string }
|
|
107
|
+
inputs: { type: array, items: { type: string } }
|
|
108
|
+
outputs: { type: array, items: { type: string } }
|
|
109
|
+
refreshInterval: { type: string }
|
|
110
|
+
notes: { type: string }
|
|
88
111
|
layout: { type: object }
|
|
89
112
|
module: { type: object }
|
|
90
113
|
api: { type: object }
|
|
@@ -107,8 +130,9 @@ INSTRUCTIONS:
|
|
|
107
130
|
- Use only the facts from the included documents and files. Do not invent technologies or filenames.
|
|
108
131
|
- If TECH_STACK_FILE is absent, infer a reasonable tech stack from the PRD and included files; state key assumptions within each item's description.
|
|
109
132
|
- Output a single top-level JSON array of items. Each item must include:
|
|
110
|
-
- reason, description, dependencies (filenames), priority (1 = highest), filename, optional tags.
|
|
133
|
+
- reason (briefly explain why this code module needs to exist), description, dependencies (filenames), priority (1 = highest), filename, filepath, optional tags.
|
|
111
134
|
- interface: include only the applicable sub-object (component, page, module, api, graphql, cli, job, message, or config). Omit all non-applicable sub-objects entirely.
|
|
135
|
+
- When interface.type is "page", each entry in `dataSources` must be an object with at least `kind` (e.g., api/query) and `source` (e.g., URL or identifier). Provide `method`, `description`, and any other useful metadata when known.
|
|
112
136
|
- Valid JSON only. No comments or trailing commas.
|
|
113
137
|
|
|
114
138
|
OUTPUT FORMAT (authoritative):
|
|
@@ -117,20 +141,38 @@ OUTPUT FORMAT (authoritative):
|
|
|
117
141
|
"type": "array",
|
|
118
142
|
"items": {
|
|
119
143
|
"type": "object",
|
|
120
|
-
"required": ["reason", "description", "dependencies", "priority", "filename"],
|
|
144
|
+
"required": ["reason", "description", "dependencies", "priority", "filename", "filepath"],
|
|
121
145
|
"properties": {
|
|
122
146
|
"reason": {"type": "string"},
|
|
123
147
|
"description": {"type": "string"},
|
|
124
148
|
"dependencies": {"type": "array", "items": {"type": "string"}},
|
|
125
149
|
"priority": {"type": "integer", "minimum": 1},
|
|
126
150
|
"filename": {"type": "string"},
|
|
151
|
+
"filepath": {"type": "string"},
|
|
127
152
|
"tags": {"type": "array", "items": {"type": "string"}},
|
|
128
153
|
"interface": {
|
|
129
154
|
"type": "object",
|
|
130
155
|
"properties": {
|
|
131
156
|
"type": {"enum": ["component", "page", "module", "api", "graphql", "cli", "job", "message", "config"]},
|
|
132
157
|
"component": {"type": "object"},
|
|
133
|
-
"page": {
|
|
158
|
+
"page": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"properties": {
|
|
161
|
+
"route": {"type": "string"},
|
|
162
|
+
"params": {
|
|
163
|
+
"type": "array",
|
|
164
|
+
"items": {
|
|
165
|
+
"type": "object",
|
|
166
|
+
"required": ["name", "type"],
|
|
167
|
+
"properties": {
|
|
168
|
+
"name": {"type": "string"},
|
|
169
|
+
"type": {"type": "string"},
|
|
170
|
+
"description": {"type": "string"}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
134
176
|
"module": {"type": "object"},
|
|
135
177
|
"api": {"type": "object"},
|
|
136
178
|
"graphql": {"type": "object"},
|
|
@@ -146,7 +188,7 @@ OUTPUT FORMAT (authoritative):
|
|
|
146
188
|
```
|
|
147
189
|
|
|
148
190
|
INTERFACE TYPES (emit only applicable):
|
|
149
|
-
- page: route (string), params? (array), dataSources? (array), layout? (object)
|
|
191
|
+
- page: route (string), params? (array of {name, type, description?}), dataSources? (array), layout? (object)
|
|
150
192
|
- component: props (array of {name, type, required?}), emits? (array), context? (array)
|
|
151
193
|
- module: functions (array of {name, signature, returns?, errors?, sideEffects?})
|
|
152
194
|
- api: endpoints (array of {method, path, auth?, requestSchema?, responseSchema?, errors?})
|
|
@@ -163,6 +205,18 @@ FILENAME CONVENTIONS:
|
|
|
163
205
|
- Python backend: api_Python.prompt -> api.py; orders_Python.prompt -> orders.py
|
|
164
206
|
- Choose descriptive <base> names (e.g., orders_page, orders_api) and keep names consistent across dependencies.
|
|
165
207
|
|
|
208
|
+
FILEPATH CONVENTIONS:
|
|
209
|
+
- The "filepath" field specifies the path of the output source file from the source tree root, using conventions appropriate for the language and framework.
|
|
210
|
+
- Examples (adapt to your stack):
|
|
211
|
+
- Next.js app router: app/orders/page.tsx, app/layout.tsx, app/api/orders/route.ts
|
|
212
|
+
- Next.js pages router: pages/orders.tsx, pages/api/orders.ts
|
|
213
|
+
- Python FastAPI: src/api.py, src/orders.py, src/models/order.py
|
|
214
|
+
- React components: src/components/OrderList.tsx, src/hooks/useOrders.ts
|
|
215
|
+
- Config files: .env.example, pyproject.toml, package.json
|
|
216
|
+
- Use forward slashes (/) for path separators regardless of OS.
|
|
217
|
+
- Include the appropriate file extension for the target language (.tsx, .py, .rs, .go, etc.).
|
|
218
|
+
- Follow standard directory structures for the framework (e.g., app/ for Next.js 13+, src/ for typical React/Python projects).
|
|
219
|
+
|
|
166
220
|
DEPENDENCY RULES:
|
|
167
221
|
- The "dependencies" array must list other items by their prompt filenames (the "filename" values), not code filenames.
|
|
168
222
|
- Do not reference files that are not part of this array unless they were explicitly provided via INCLUDE_FILES/DOC_FILES.
|
|
@@ -22,11 +22,11 @@ variables:
|
|
|
22
22
|
type: string
|
|
23
23
|
description: System layer or interface type for context.
|
|
24
24
|
examples: [backend, frontend, api, graphql, cli, job, message, config, module, component, page]
|
|
25
|
-
|
|
25
|
+
PRD_FILE:
|
|
26
26
|
required: false
|
|
27
27
|
type: path
|
|
28
|
-
description:
|
|
29
|
-
example_paths: [
|
|
28
|
+
description: Product requirements document providing overall context.
|
|
29
|
+
example_paths: [PRD.md, docs/product/prd.md]
|
|
30
30
|
API_DOC_FILE:
|
|
31
31
|
required: false
|
|
32
32
|
type: path
|
|
@@ -48,7 +48,7 @@ variables:
|
|
|
48
48
|
description: CSV of function inputs/outputs and dependencies for backend modules.
|
|
49
49
|
example_paths: [prompts/backend/io_dependencies.csv]
|
|
50
50
|
ARCHITECTURE_FILE:
|
|
51
|
-
required:
|
|
51
|
+
required: true
|
|
52
52
|
type: path
|
|
53
53
|
description: Architecture JSON (from architecture/architecture_json) to drive module scope, dependencies, and interface.
|
|
54
54
|
example_paths: [architecture.json]
|
|
@@ -75,14 +75,14 @@ variables:
|
|
|
75
75
|
default: py
|
|
76
76
|
usage:
|
|
77
77
|
generate:
|
|
78
|
-
- name: Minimal (
|
|
79
|
-
command: pdd generate -e MODULE=orders -e LANG_OR_FRAMEWORK=Python --output 'prompts/${MODULE}_${LANG_OR_FRAMEWORK}.prompt' pdd/templates/generic/generate_prompt.prompt
|
|
78
|
+
- name: Minimal (architecture only)
|
|
79
|
+
command: pdd generate -e MODULE=orders -e LANG_OR_FRAMEWORK=Python -e ARCHITECTURE_FILE=architecture.json --output 'prompts/${MODULE}_${LANG_OR_FRAMEWORK}.prompt' pdd/templates/generic/generate_prompt.prompt
|
|
80
80
|
- name: With project docs
|
|
81
|
-
command: pdd generate -e MODULE=orders -e LANG_OR_FRAMEWORK=Python -e
|
|
81
|
+
command: pdd generate -e MODULE=orders -e LANG_OR_FRAMEWORK=Python -e ARCHITECTURE_FILE=architecture.json -e PRD_FILE=docs/PRD.md -e API_DOC_FILE=docs/api-documentation.md -e DB_SCHEMA_FILE=context/database-schema.md --output 'prompts/${MODULE}_${LANG_OR_FRAMEWORK}.prompt' pdd/templates/generic/generate_prompt.prompt
|
|
82
82
|
- name: With CSVs and references (backend/Python)
|
|
83
|
-
command: pdd generate -e MODULE=orders -e LANG_OR_FRAMEWORK=Python -e
|
|
83
|
+
command: pdd generate -e MODULE=orders -e LANG_OR_FRAMEWORK=Python -e ARCHITECTURE_FILE=architecture.json -e PRD_FILE=docs/PRD.md -e API_DOC_FILE=docs/api-documentation.md -e DB_SCHEMA_FILE=context/database-schema.md -e BACKEND_FILES_CSV=prompts/backend/python_architecture.csv -e IO_DEPENDENCIES_CSV=prompts/backend/io_dependencies.csv -e CODE_GENERATOR_PROMPT=prompts/code_generator_python.prompt --output 'prompts/${MODULE}_${LANG_OR_FRAMEWORK}.prompt' pdd/templates/generic/generate_prompt.prompt
|
|
84
84
|
- name: Frontend (TypeScriptReact) variant
|
|
85
|
-
command: pdd generate -e MODULE=profile_page -e LANG_OR_FRAMEWORK=TypeScriptReact -e LAYER=frontend -e
|
|
85
|
+
command: pdd generate -e MODULE=profile_page -e LANG_OR_FRAMEWORK=TypeScriptReact -e LAYER=frontend -e ARCHITECTURE_FILE=architecture.json -e PRD_FILE=docs/PRD.md --output 'prompts/${MODULE}_${LANG_OR_FRAMEWORK}.prompt' pdd/templates/generic/generate_prompt.prompt
|
|
86
86
|
- name: From architecture.json
|
|
87
87
|
command: pdd generate -e MODULE=orders_api -e LANG_OR_FRAMEWORK=Python -e LAYER=api -e ARCHITECTURE_FILE=architecture.json --output 'prompts/${MODULE}_${LANG_OR_FRAMEWORK}.prompt' pdd/templates/generic/generate_prompt.prompt
|
|
88
88
|
|
|
@@ -94,8 +94,10 @@ discover:
|
|
|
94
94
|
|
|
95
95
|
% You are an expert prompt writer and software architect for PDD. Your goal is to write a high-quality prompt that will generate the code for the ${MODULE} module/component. The prompt you create will be used to produce a detailed implementation specification in a file named ${MODULE}_${LANG_OR_FRAMEWORK}.prompt, suitable for the specified stack and layer.
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
IMPORTANT: Your reply MUST begin with `<prompt>` on the very first line and end with `</prompt>` on the final line. Do not include any text, whitespace, or code fences outside this block.
|
|
98
|
+
|
|
99
|
+
% Project context (architecture required, others optional):
|
|
100
|
+
<prd><include>${PRD_FILE}</include></prd>
|
|
99
101
|
<api><include>${API_DOC_FILE}</include></api>
|
|
100
102
|
<database><include>${DB_SCHEMA_FILE}</include></database>
|
|
101
103
|
<backend_files_csv><include>${BACKEND_FILES_CSV}</include></backend_files_csv>
|
|
@@ -110,8 +112,9 @@ discover:
|
|
|
110
112
|
% Do the following:
|
|
111
113
|
- Explain concisely what you are going to do (create a prompt for the ${MODULE} module/component for the specified layer and stack).
|
|
112
114
|
- Analyze any difficulties this prompt might encounter for ${MODULE} (e.g., data modeling, API or UI contracts, transactions, idempotency, auth, state management, error handling) and briefly state mitigation strategies tailored to the given LAYER and LANG_OR_FRAMEWORK.
|
|
113
|
-
-
|
|
115
|
+
- Use the ARCHITECTURE_FILE to identify the item that corresponds to this prompt by matching `filename` to `${MODULE}_${LANG_OR_FRAMEWORK}.prompt` (or best match by basename and layer). Use that item’s `reason`, `description`, `dependencies`, `interface`, and `tags` to shape the sections below.
|
|
114
116
|
- Then create the prompt content for ${MODULE} inside XML tags named prompt, ensuring conventions fit the stack and layer.
|
|
117
|
+
- Ensure the final response consists solely of the `<prompt>...</prompt>` block; nothing else (including whitespace) may appear before `<prompt>` or after `</prompt>`.
|
|
115
118
|
|
|
116
119
|
% The prompt you generate must follow this structure:
|
|
117
120
|
1) First paragraph: describe the role and responsibility of the ${MODULE} module/component within the system (consider the LAYER if provided).
|
|
@@ -127,9 +130,9 @@ discover:
|
|
|
127
130
|
</orders_service>
|
|
128
131
|
- Prefer real example files available in the provided context (use <include-many> when listing multiple). If examples are not provided, assume dependency examples live under context/ using the pattern context/[dependency_name]_example.${DEP_EXAMPLE_EXT}.
|
|
129
132
|
- Include all necessary dependencies for the module/component (based on the provided context and references).
|
|
130
|
-
-
|
|
133
|
+
- The ARCHITECTURE_FILE lists `dependencies` referencing other prompt filenames. Convert each dependency prompt filename into a sensible dependency name (strip language suffix and `_prompt`), and map to context files with the `${DEP_EXAMPLE_EXT}` extension if present; otherwise, list the prompt filename explicitly in a "Prompt Dependencies" subsection.
|
|
131
134
|
|
|
132
|
-
% Architecture awareness (
|
|
135
|
+
% Architecture awareness (ARCHITECTURE_FILE is required):
|
|
133
136
|
- Align the "Requirements" and "Instructions" with the selected item’s `interface.type` (e.g., page, component, module, api, graphql, cli, job, message, config).
|
|
134
137
|
- For `api`, outline endpoints (method, path, auth) consistent with the architecture description; for `page`/`component`, describe route/props/data sources; for `job`, include trigger and retry policy; for `config`, list keys and sources.
|
|
135
138
|
|
|
@@ -139,4 +142,33 @@ discover:
|
|
|
139
142
|
- Do not invent technologies or files; rely on the included context. If assumptions are necessary, state them explicitly and conservatively.
|
|
140
143
|
|
|
141
144
|
% Output contract:
|
|
142
|
-
-
|
|
145
|
+
- Start the output with `<prompt>` on its own line and end with `</prompt>` on its own line.
|
|
146
|
+
- Do not emit any characters (including whitespace, markdown fences, or commentary) outside the `<prompt>...</prompt>` block.
|
|
147
|
+
- Within the tags, include the sections described above as plain text.
|
|
148
|
+
- OUTPUT FORMAT (authoritative – copy/paste and replace the bracketed placeholders, keeping every literal token):
|
|
149
|
+
```text
|
|
150
|
+
<prompt>
|
|
151
|
+
{ROLE_PARAGRAPH}
|
|
152
|
+
Requirements
|
|
153
|
+
1. {REQ_ITEM_1}
|
|
154
|
+
2. {REQ_ITEM_2}
|
|
155
|
+
Dependencies
|
|
156
|
+
<{DEPENDENCY_TAG_1}>
|
|
157
|
+
<include>{DEPENDENCY_INCLUDE_1}</include>
|
|
158
|
+
</{DEPENDENCY_TAG_1}>
|
|
159
|
+
{OPTIONAL_ADDITIONAL_DEPENDENCY_TAGS}
|
|
160
|
+
Prompt Dependencies:
|
|
161
|
+
{PROMPT_DEPENDENCIES_SECTION}
|
|
162
|
+
Instructions
|
|
163
|
+
- {INSTRUCTION_1}
|
|
164
|
+
- {INSTRUCTION_2}
|
|
165
|
+
Deliverable
|
|
166
|
+
- {DELIVERABLE_1}
|
|
167
|
+
- {DELIVERABLE_2}
|
|
168
|
+
Implementation assumptions (explicit)
|
|
169
|
+
- {ASSUMPTION_1}
|
|
170
|
+
- {ASSUMPTION_2}
|
|
171
|
+
Please produce production-ready prompt content that will generate the module consistent with the above.
|
|
172
|
+
</prompt>
|
|
173
|
+
```
|
|
174
|
+
Replace each `{PLACEHOLDER}` with concrete content while preserving the surrounding structure and literal `<prompt>` / `<include>` tags.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pdd-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.63
|
|
4
4
|
Summary: PDD (Prompt-Driven Development) Command Line Interface
|
|
5
5
|
Author: Greg Tanaka
|
|
6
6
|
Author-email: glt@alumni.caltech.edu
|
|
@@ -53,7 +53,7 @@ Requires-Dist: build; extra == "dev"
|
|
|
53
53
|
Requires-Dist: twine; extra == "dev"
|
|
54
54
|
Dynamic: license-file
|
|
55
55
|
|
|
56
|
-
.. image:: https://img.shields.io/badge/pdd--cli-v0.0.
|
|
56
|
+
.. image:: https://img.shields.io/badge/pdd--cli-v0.0.63-blue
|
|
57
57
|
:alt: PDD-CLI Version
|
|
58
58
|
|
|
59
59
|
.. image:: https://img.shields.io/badge/Discord-join%20chat-7289DA.svg?logo=discord&logoColor=white&link=https://discord.gg/Yp4RTh8bG7
|
|
@@ -130,7 +130,7 @@ After installation, verify:
|
|
|
130
130
|
|
|
131
131
|
pdd --version
|
|
132
132
|
|
|
133
|
-
You'll see the current PDD version (e.g., 0.0.
|
|
133
|
+
You'll see the current PDD version (e.g., 0.0.63).
|
|
134
134
|
|
|
135
135
|
Getting Started with Examples
|
|
136
136
|
-----------------------------
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
pdd/__init__.py,sha256=
|
|
1
|
+
pdd/__init__.py,sha256=poOT3ybYXYnjrM8EcduTkCl3sMnj5dXCF_LBZI3jQB8,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
|
|
@@ -6,7 +6,7 @@ pdd/bug_main.py,sha256=EtaGTuucQ7VgqOhyg4o6GFG7_QtTsDPTrRdGJWT648M,4841
|
|
|
6
6
|
pdd/bug_to_unit_test.py,sha256=BoQqNyKQpBQDW8-JwBH_RX4RHRSiU8Kk3EplFrkECt0,6665
|
|
7
7
|
pdd/change.py,sha256=Hg_x0pa370-e6oDiczaTgFAy3Am9ReCPkqFrvqv4U38,6114
|
|
8
8
|
pdd/change_main.py,sha256=04VHiO_D-jlfeRn6rrVH7ZTA5agXPoJGm1StGI8--XY,27804
|
|
9
|
-
pdd/cli.py,sha256=
|
|
9
|
+
pdd/cli.py,sha256=qjDBwwwE-sTWFqKTJOIiYh2nuimlTTgXtMDE0RUuVaU,60805
|
|
10
10
|
pdd/cmd_test_main.py,sha256=M-i5x26ORXurt_pu8x1sgLAyVIItbuRThiux4wBg3Ls,7768
|
|
11
11
|
pdd/code_generator.py,sha256=AxMRZKGIlLh9xWdn2FA6b3zSoZ-5TIZNIAzqjFboAQs,4718
|
|
12
12
|
pdd/code_generator_main.py,sha256=UtoskalEPpMAvCO-zd6xmr1lbQqSWQ7BvYgNJCybqok,35151
|
|
@@ -50,7 +50,7 @@ pdd/pdd_completion.sh,sha256=xgx-g6aeCCrlh6loeLyJN5jCsX15YXrWyT1U499p3C0,6490
|
|
|
50
50
|
pdd/pdd_completion.zsh,sha256=V9-V8jqw3osjlXNOvjYMJf0E771-_EQe-Cboo1xzPvY,17090
|
|
51
51
|
pdd/postprocess.py,sha256=mNw3iSDxE-eTYo3QwJCj_EmdEnnB5ysUN62YPapC_IM,4433
|
|
52
52
|
pdd/postprocess_0.py,sha256=OW17GyCFLYErCyWh2tL4syuho3q2yFf2wyekQ4BLdPM,2168
|
|
53
|
-
pdd/preprocess.py,sha256=
|
|
53
|
+
pdd/preprocess.py,sha256=tmZiYlpiJHFDPuwlYtl1htQ7ZA77roGdPRvO4sHXYGU,18162
|
|
54
54
|
pdd/preprocess_main.py,sha256=WGhOB9qEu7MmFoyXNml_AmqGii73LJWngx4kTlZ526k,3262
|
|
55
55
|
pdd/process_csv_change.py,sha256=ckNqVPRooWVyIvmqjdEgo2PDLnpoQ6Taa2dUaWGRlzU,27926
|
|
56
56
|
pdd/pytest_output.py,sha256=IrRKYneW_F6zv9WaJwKFGnOBLFBFjk1CnhO_EVAjb9E,6612
|
|
@@ -72,8 +72,8 @@ pdd/update_main.py,sha256=SWCd7Us3YatrDR7B66dQCpRCIgQoMHysPzxa4dedVmk,4385
|
|
|
72
72
|
pdd/update_model_costs.py,sha256=RfeOlAHtc1FCx47A7CjrH2t5WXQclQ_9uYtNjtQh75I,22998
|
|
73
73
|
pdd/update_prompt.py,sha256=zc-HiI1cwGBkJHVmNDyoSZa13lZH90VdB9l8ajdj6Kk,4543
|
|
74
74
|
pdd/xml_tagger.py,sha256=5Bc3HRm7iz_XjBdzQIcMb8KocUQ8PELI2NN5Gw4amd4,4825
|
|
75
|
-
pdd/data/language_format.csv,sha256=
|
|
76
|
-
pdd/data/llm_model.csv,sha256=
|
|
75
|
+
pdd/data/language_format.csv,sha256=i4AfibdhmMnx_xAnv5jHA8TGSftjOJnLcKE53kS7kLY,1010
|
|
76
|
+
pdd/data/llm_model.csv,sha256=u7naNW110fejsV443qlzs0_TmCAzxa8EJogjmmJSAZs,1702
|
|
77
77
|
pdd/prompts/auto_include_LLM.prompt,sha256=sNF2rdJu9wJ8c0lwjCfZ9ZReX8zGXRUNehRs1ZiyDoc,12108
|
|
78
78
|
pdd/prompts/bug_to_unit_test_LLM.prompt,sha256=KdMkvRVnjVSf0NTYIaDXIMT93xPttXEwkMpjWx5leLs,1588
|
|
79
79
|
pdd/prompts/change_LLM.prompt,sha256=5rgWIL16p3VRURd2_lNtcbu_MVRqPhI8gFIBt1gkzDQ,2164
|
|
@@ -110,11 +110,11 @@ pdd/prompts/trim_results_start_LLM.prompt,sha256=OKz8fAf1cYWKWgslFOHEkUpfaUDARh3
|
|
|
110
110
|
pdd/prompts/unfinished_prompt_LLM.prompt,sha256=vud_G9PlVv9Ig64uBC-hPEVFRk5lwpc8pW6tOIxJM4I,5082
|
|
111
111
|
pdd/prompts/update_prompt_LLM.prompt,sha256=prIc8uLp2jqnLTHt6JvWDZGanPZipivhhYeXe0lVaYw,1328
|
|
112
112
|
pdd/prompts/xml_convertor_LLM.prompt,sha256=YGRGXJeg6EhM9690f-SKqQrKqSJjLFD51UrPOlO0Frg,2786
|
|
113
|
-
pdd/templates/architecture/architecture_json.prompt,sha256=
|
|
114
|
-
pdd/templates/generic/generate_prompt.prompt,sha256=
|
|
115
|
-
pdd_cli-0.0.
|
|
116
|
-
pdd_cli-0.0.
|
|
117
|
-
pdd_cli-0.0.
|
|
118
|
-
pdd_cli-0.0.
|
|
119
|
-
pdd_cli-0.0.
|
|
120
|
-
pdd_cli-0.0.
|
|
113
|
+
pdd/templates/architecture/architecture_json.prompt,sha256=lmEM6f1EGK73wivONssvlSNXuTy2nYv-p-oRqBg1iFg,10745
|
|
114
|
+
pdd/templates/generic/generate_prompt.prompt,sha256=4PhcNczpYpwSiaGt0r2f-vhSO3JFqeU1fTEy6YpPudQ,10758
|
|
115
|
+
pdd_cli-0.0.63.dist-info/licenses/LICENSE,sha256=kvTJnnxPVTYlGKSY4ZN1kzdmJ0lxRdNWxgupaB27zsU,1066
|
|
116
|
+
pdd_cli-0.0.63.dist-info/METADATA,sha256=LtF3JdpNk8hnTDvVoNhJzqdoOMINHkdVM9Luxda6sV4,12687
|
|
117
|
+
pdd_cli-0.0.63.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
118
|
+
pdd_cli-0.0.63.dist-info/entry_points.txt,sha256=Kr8HtNVb8uHZtQJNH4DnF8j7WNgWQbb7_Pw5hECSR-I,36
|
|
119
|
+
pdd_cli-0.0.63.dist-info/top_level.txt,sha256=xjnhIACeMcMeDfVNREgQZl4EbTni2T11QkL5r7E-sbE,4
|
|
120
|
+
pdd_cli-0.0.63.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|