Skip to content

Commit 1532660

Browse files
committed
Bump version
1 parent 2afd32c commit 1532660

File tree

11 files changed

+948
-155
lines changed

11 files changed

+948
-155
lines changed

CHANGELOG.md

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,46 @@
1+
## v0.0.98 (2025-12-31)
2+
3+
### Feat
4+
5+
- Add check for suspicious single-letter files during release process
6+
- Add cloud execution support for pdd test command
7+
18
## v0.0.97 (2025-12-30)
29

310
### Feat
411

5-
- Enhance CLI Python prompt to display examples used for grounding
6-
- Add diagnostic logging for Issue #186 (C, E, T files)
7-
- Enhance cloud execution and syntax validation
12+
- **CLI Examples Display:** After each command step, the CLI now displays examples used for grounding (slug and title), helping users know what to use in `<pin>` or `<exclude>` tags.
13+
14+
- **Suspicious Files Diagnostic Logging (Issue #186):** Added `_detect_suspicious_files()` in `agentic_fix.py` to detect and log when single-character files (C, E, T) are created during agentic operations. Logs include timestamp, context, directory, file sizes, and stack trace. Persistent log saved to `~/.pdd/suspicious_files.log`.
15+
16+
- **Cloud Example Generation:** Added cloud execution support to `context_generator_main` via async `_run_cloud_generation()` function. Uses JWT authentication with automatic local fallback on cloud failure.
17+
18+
- **Improved Syntax Repair:** Rewrote `_validate_and_fix_python_syntax()` with a binary search algorithm to find the longest valid Python prefix when LLM output contains trailing JSON garbage (e.g., `"explanation":` metadata).
19+
20+
### Fix
21+
22+
- **Nested asyncio.run() Bug (PR #204):** Fixed `pdd example` command failing to make cloud calls due to nested asyncio.run() error. The issue occurred because `CloudConfig.get_jwt_token()` uses asyncio.run() internally, causing conflicts when called from within an async context. Fixed by acquiring JWT token before entering the async context. (Thanks Jiamin Cai!)
23+
24+
- **HTTPStatusError Response Text:** Fixed error handling to check for empty `.text` instead of checking if response exists (response is always present on HTTPStatusError).
25+
26+
- **Test Overwrite Bug:** Fixed sync bug that would overwrite existing tests. Now uses append mode when merging with existing tests via the `--merge` flag.
27+
28+
- **CLI Test Fixture:** Fixed test fixture checking for "install_completion" instead of "install-completion" (Click converts underscores to hyphens in command names).
829

930
### Refactor
1031

11-
- Update prompts to support existing test files as lists
32+
- **Existing Tests as Lists:** Changed `existing_tests` parameter from string path to list of paths in prompts, enabling multiple test files to be concatenated for context.
33+
34+
- **Test File Organization:** Moved `tests/test_core_cli.py` to `tests/core/test_cli.py` for better module organization.
35+
36+
### Docs
37+
38+
- Clarified `existing_tests` parameter behavior in `cmd_test_main_python.prompt`, documenting that it accepts a list of test file paths.
39+
40+
### Tests
41+
42+
- Added regression tests for nested asyncio.run() bug in `test_context_generator_main.py`.
43+
- Updated `test_cmd_test_main.py` with coverage for test file append mode and existing_tests list handling.
1244

1345
## v0.0.96 (2025-12-29)
1446

Makefile

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,33 @@ publish:
585585
check-deps:
586586
@python scripts/check_deps.py
587587

588-
release: check-deps
588+
# Issue #186: Detect suspicious single-letter files (C, E, T)
589+
# These files sometimes appear during release operations
590+
# Files are logged but NOT removed so we can debug when it happens
591+
.PHONY: check-suspicious-files
592+
check-suspicious-files:
593+
@echo "Checking for suspicious single-letter files (Issue #186)..."
594+
@SUSPICIOUS=$$(find . -maxdepth 1 -type f \( -name 'C' -o -name 'E' -o -name 'T' -o -name '?' -o -name '??' \) ! -name '.*' 2>/dev/null); \
595+
if [ -n "$$SUSPICIOUS" ]; then \
596+
echo "⚠️ SUSPICIOUS FILES DETECTED:"; \
597+
echo "$$SUSPICIOUS"; \
598+
echo "Logging to ~/.pdd/suspicious_files.log"; \
599+
mkdir -p ~/.pdd; \
600+
echo "" >> ~/.pdd/suspicious_files.log; \
601+
echo "============================================================" >> ~/.pdd/suspicious_files.log; \
602+
echo "Timestamp: $$(date -Iseconds)" >> ~/.pdd/suspicious_files.log; \
603+
echo "Context: make check-suspicious-files" >> ~/.pdd/suspicious_files.log; \
604+
echo "Directory: $$(pwd)" >> ~/.pdd/suspicious_files.log; \
605+
echo "Files: $$SUSPICIOUS" >> ~/.pdd/suspicious_files.log; \
606+
for f in $$SUSPICIOUS; do \
607+
echo " File: $$f, Size: $$(stat -f%z "$$f" 2>/dev/null || stat -c%s "$$f" 2>/dev/null) bytes, Modified: $$(stat -f%Sm "$$f" 2>/dev/null || stat -c%y "$$f" 2>/dev/null)" >> ~/.pdd/suspicious_files.log; \
608+
done; \
609+
echo "Files left in place for debugging."; \
610+
else \
611+
echo "No suspicious files found."; \
612+
fi
613+
614+
release: check-deps check-suspicious-files
589615
@echo "Preparing release"
590616
@CURRENT_VERSION=$$(sed -n '1,120s/^version[[:space:]]*=[[:space:]]*"\([0-9.]*\)"/\1/p' pyproject.toml | head -n1); \
591617
CURRENT_TAG="v$$CURRENT_VERSION"; \
@@ -600,6 +626,8 @@ release: check-deps
600626
echo "Publishing new version"; \
601627
$(MAKE) publish; \
602628
fi
629+
@# Post-release cleanup check (Issue #186)
630+
@$(MAKE) check-suspicious-files
603631

604632
analysis:
605633
@echo "Running regression analysis"

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PDD (Prompt-Driven Development) Command Line Interface
22

3-
![PDD-CLI Version](https://img.shields.io/badge/pdd--cli-v0.0.97-blue) [![Discord](https://img.shields.io/badge/Discord-join%20chat-7289DA.svg?logo=discord&logoColor=white)](https://discord.gg/Yp4RTh8bG7)
3+
![PDD-CLI Version](https://img.shields.io/badge/pdd--cli-v0.0.98-blue) [![Discord](https://img.shields.io/badge/Discord-join%20chat-7289DA.svg?logo=discord&logoColor=white)](https://discord.gg/Yp4RTh8bG7)
44

55
## Introduction
66

@@ -285,7 +285,7 @@ export PDD_TEST_OUTPUT_PATH=/path/to/tests/
285285

286286
## Version
287287

288-
Current version: 0.0.97
288+
Current version: 0.0.98
289289

290290
To check your installed version, run:
291291
```

context/cmd_test_main_example.py

Lines changed: 84 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,100 @@
1-
# test_cli_example.py
2-
3-
"""
4-
This example demonstrates how to integrate the 'cmd_test_main' function into a
5-
Click-based command line interface (CLI). It shows how to accept CLI arguments,
6-
then invoke the command to generate or enhance unit tests.
7-
8-
Usage:
9-
1. Create a CLI script like this with the code below.
10-
2. Run it from the command line, for instance:
11-
$ python test_cli_example.py test ./prompt.txt ./my_code.py --output ./tests/test_my_code.py
12-
13-
Required Arguments:
14-
- prompt_file: Path to the text file that generated the code (e.g., a GPT prompt).
15-
- code_file: Path to the source code file to be tested.
16-
17-
Optional Arguments:
18-
- --output: Path to save the newly generated or enhanced test file. Defaults to an auto-generated path if omitted.
19-
- --language: Programming language override if you want to force tests in a certain language.
20-
- --coverage-report: Path to an existing coverage report. If provided, requires --existing-tests to enhance tests.
21-
- --existing-tests: Path to an existing test file to merge or enhance.
22-
- --target-coverage: Desired test coverage percentage (float). Only used if --coverage-report is set.
23-
- --merge: Flag to merge new tests into the existing tests specified by --existing-tests.
24-
25-
Returns:
26-
- A tuple (generated_test_code: str, total_cost: float, model_name: str)
27-
"""
28-
1+
import os
292
import click
30-
from pdd.cmd_test_main import cmd_test_main # Adjust import to match your package structure
3+
from pathlib import Path
4+
from rich.console import Console
315

6+
# Import the function to be tested
7+
# Note: In a real package structure, this would be: from pdd.cmd_test_main import cmd_test_main
8+
# We assume the pdd package is installed or in the python path.
9+
from pdd.cmd_test_main import cmd_test_main
3210

33-
@click.group()
34-
@click.option("--verbose", is_flag=True, default=False, help="Enable verbose logging.")
35-
@click.option("--strength", default=0.7, type=float, help="Controls AI generation strength.")
36-
@click.option("--temperature", default=0.7, type=float, help="Controls AI generation creativity.")
37-
@click.option("--force", is_flag=True, default=False, help="Force overwrite of existing files.")
38-
@click.option("--quiet", is_flag=True, default=False, help="Suppress non-error output.")
39-
@click.pass_context
40-
def cli(ctx, verbose, strength, temperature, force, quiet):
11+
# Setup console for output
12+
console = Console()
13+
14+
def run_example():
15+
"""
16+
Demonstrates how to use cmd_test_main to generate unit tests for a simple calculator module.
4117
"""
42-
Top-level CLI group. Sets up shared context for all subcommands.
18+
# 1. Setup paths and directories
19+
base_dir = Path("./output")
20+
base_dir.mkdir(exist_ok=True)
4321

44-
Global Options:
45-
--verbose, --strength, --temperature, --force, --quiet
22+
prompt_file = base_dir / "calculator_python.prompt"
23+
code_file = base_dir / "calculator.py"
24+
output_test_file = base_dir / "test_calculator.py"
25+
26+
# 2. Create dummy input files
27+
# Create a prompt file
28+
prompt_content = """
29+
Task: Create a simple calculator module.
30+
Requirements:
31+
- Implement add(a, b)
32+
- Implement subtract(a, b)
4633
"""
47-
ctx.ensure_object(dict)
48-
ctx.obj["verbose"] = verbose
49-
ctx.obj["strength"] = strength
50-
ctx.obj["temperature"] = temperature
51-
ctx.obj["force"] = force
52-
ctx.obj["quiet"] = quiet
34+
prompt_file.write_text(prompt_content, encoding="utf-8")
5335

36+
# Create the corresponding code file
37+
code_content = """
38+
def add(a, b):
39+
return a + b
5440
55-
@cli.command()
56-
@click.pass_context
57-
@click.argument("prompt_file", type=click.Path(exists=True))
58-
@click.argument("code_file", type=click.Path(exists=True))
59-
@click.option("--output", type=click.Path(), default=None, help="Output path for generated tests.")
60-
@click.option("--language", type=str, default=None, help="Override detected programming language.")
61-
@click.option("--coverage-report", type=click.Path(exists=True), default=None,
62-
help="Path to a coverage report for enhancing tests.")
63-
@click.option("--existing-tests", type=click.Path(exists=True), default=None,
64-
help="Existing test file to merge or build upon.")
65-
@click.option("--target-coverage", type=float, default=None, help="Desired coverage percentage.")
66-
@click.option("--merge", is_flag=True, default=False, help="Merge new tests into existing tests.")
67-
def test(
68-
ctx,
69-
prompt_file,
70-
code_file,
71-
output,
72-
language,
73-
coverage_report,
74-
existing_tests,
75-
target_coverage,
76-
merge,
77-
):
41+
def subtract(a, b):
42+
return a - b
7843
"""
79-
Generate or enhance unit tests for the provided code.
44+
code_file.write_text(code_content, encoding="utf-8")
8045

81-
Examples:
82-
python test_cli_example.py test prompt.txt my_code.py --output tests/test_my_code.py
83-
python test_cli_example.py test prompt.txt my_code.py --coverage-report coverage.xml --existing-tests tests/test_my_code.py --merge
46+
console.print("[bold green]Created input files:[/bold green]")
47+
console.print(f" Prompt: {prompt_file}")
48+
console.print(f" Code: {code_file}")
8449

85-
"""
86-
# Note: strength and temperature parameters can be passed explicitly to override ctx.obj values.
87-
# This is useful when orchestrators need to pass specific values.
88-
generated_tests, total_cost, model_name = cmd_test_main(
50+
# 3. Mock the Click Context
51+
# cmd_test_main expects a click.Context object with specific obj keys
52+
ctx = click.Context(click.Command("test"))
53+
ctx.obj = {
54+
"verbose": True,
55+
"force": True, # Force overwrite without prompting
56+
"quiet": False,
57+
"local": True, # Force local execution for this example
58+
"context": None, # Optional context override
59+
"confirm_callback": None
60+
}
61+
62+
# 4. Define arguments for cmd_test_main
63+
# Note: We set strength/temperature here, but they can also be resolved from config
64+
strength = 0.5
65+
temperature = 0.0
66+
67+
console.print("\n[bold blue]Running cmd_test_main...[/bold blue]")
68+
69+
# 5. Call the function
70+
# This will generate the test code, save it to output_test_file, and return details
71+
unit_test_code, total_cost, model_name = cmd_test_main(
8972
ctx=ctx,
90-
prompt_file=prompt_file,
91-
code_file=code_file,
92-
output=output,
93-
language=language,
94-
coverage_report=coverage_report,
95-
existing_tests=existing_tests,
96-
target_coverage=target_coverage,
97-
merge=merge,
98-
# Optional: pass strength=0.8 or temperature=0.5 to override ctx.obj values
73+
prompt_file=str(prompt_file),
74+
code_file=str(code_file),
75+
output=str(output_test_file),
76+
language="python", # Explicitly set language
77+
coverage_report=None, # Not using coverage report mode
78+
existing_tests=None, # Not augmenting existing tests
79+
target_coverage=None,
80+
merge=False,
81+
strength=strength,
82+
temperature=temperature
9983
)
10084

101-
# Provided for demonstration. You can print or further process the returned data.
102-
click.echo(f"Generated Tests:\n{generated_tests}")
103-
click.echo(f"Total Cost: ${total_cost:.6f}")
104-
click.echo(f"Model Used: {model_name}")
105-
85+
# 6. Display results
86+
console.print("\n[bold green]Execution Complete![/bold green]")
87+
console.print(f"Model Used: {model_name}")
88+
console.print(f"Estimated Cost: ${total_cost:.6f}")
89+
console.print(f"Test file saved to: {output_test_file}")
90+
91+
console.print("\n[bold]Generated Test Code Preview (first 5 lines):[/bold]")
92+
preview = "\n".join(unit_test_code.splitlines()[:5])
93+
console.print(preview)
10694

10795
if __name__ == "__main__":
108-
cli()
96+
# Ensure PDD_PATH is set if your environment requires it for config resolution
97+
if "PDD_PATH" not in os.environ:
98+
os.environ["PDD_PATH"] = os.getcwd()
99+
100+
run_example()

examples/hello/repo_root

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit 5547071b64416d2f003789cd163fc105105e5141
1+
Subproject commit 5410d97a393dbf10f91ae2ed99866cb0002b6d3c

pdd/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""PDD - Prompt Driven Development"""
22

3-
__version__ = "0.0.97"
3+
__version__ = "0.0.98"
44

55
# Strength parameter used for LLM extraction across the codebase
66
# Used in postprocessing, XML tagging, code generation, and other extraction

0 commit comments

Comments
 (0)