scry-run 0.1.0__py3-none-any.whl → 0.1.1__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.
- scry_run/backends/frozen.py +6 -6
- scry_run/cli/init.py +0 -1
- scry_run/console.py +16 -9
- scry_run/generator.py +32 -1
- scry_run/meta.py +18 -17
- scry_run-0.1.1.dist-info/METADATA +105 -0
- {scry_run-0.1.0.dist-info → scry_run-0.1.1.dist-info}/RECORD +9 -9
- scry_run-0.1.0.dist-info/METADATA +0 -282
- {scry_run-0.1.0.dist-info → scry_run-0.1.1.dist-info}/WHEEL +0 -0
- {scry_run-0.1.0.dist-info → scry_run-0.1.1.dist-info}/entry_points.txt +0 -0
scry_run/backends/frozen.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Frozen backend - errors on any generation attempt.
|
|
2
2
|
|
|
3
|
-
This backend is used
|
|
4
|
-
Any attempt to generate new code will raise FrozenAppError.
|
|
3
|
+
This backend is used when code generation should be disabled and only cached methods
|
|
4
|
+
should be used. Any attempt to generate new code will raise FrozenAppError.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from typing import Optional
|
|
@@ -14,8 +14,8 @@ class FrozenAppError(RuntimeError):
|
|
|
14
14
|
"""Raised when a frozen app attempts to generate code.
|
|
15
15
|
|
|
16
16
|
This error indicates that a method was called that doesn't exist
|
|
17
|
-
in the cache of a
|
|
18
|
-
or the method needs to be
|
|
17
|
+
in the cache of a frozen app. The backend needs to be changed to allow
|
|
18
|
+
generation, or the method needs to be pre-generated and cached.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
def __init__(self, class_name: str, attr_name: str):
|
|
@@ -24,7 +24,7 @@ class FrozenAppError(RuntimeError):
|
|
|
24
24
|
super().__init__(
|
|
25
25
|
f"Frozen app cannot generate code for '{class_name}.{attr_name}'. "
|
|
26
26
|
f"This method is not in the cache. Either:\n"
|
|
27
|
-
f" 1. Run the
|
|
27
|
+
f" 1. Run the app with a real backend to generate this method first\n"
|
|
28
28
|
f" 2. Set _llm_backend to a real backend (e.g., 'claude') to unfreeze"
|
|
29
29
|
)
|
|
30
30
|
|
|
@@ -32,7 +32,7 @@ class FrozenAppError(RuntimeError):
|
|
|
32
32
|
class FrozenBackend(GeneratorBackend):
|
|
33
33
|
"""Backend that refuses to generate any code.
|
|
34
34
|
|
|
35
|
-
Used
|
|
35
|
+
Used when all methods should come from cache and generation is disabled.
|
|
36
36
|
Any generation attempt raises FrozenAppError with helpful message.
|
|
37
37
|
"""
|
|
38
38
|
|
scry_run/cli/init.py
CHANGED
|
@@ -370,6 +370,5 @@ def init(
|
|
|
370
370
|
console.print(f" [cyan]scry-run run {name}[/cyan] Run your app")
|
|
371
371
|
console.print(f" [cyan]scry-run info {name}[/cyan] View app details and cache stats")
|
|
372
372
|
console.print(f" [cyan]scry-run cache list {name}[/cyan] List generated methods")
|
|
373
|
-
console.print(f" [cyan]scry-run bake {name}[/cyan] Export as standalone package")
|
|
374
373
|
console.print()
|
|
375
374
|
console.print("[dim]Methods are generated on first use using Claude CLI.[/dim]")
|
scry_run/console.py
CHANGED
|
@@ -1,52 +1,59 @@
|
|
|
1
1
|
"""Console output utilities for consistent styling."""
|
|
2
2
|
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
3
5
|
from rich.console import Console
|
|
4
6
|
|
|
5
7
|
# Stderr console for status messages
|
|
6
8
|
err_console = Console(stderr=True, highlight=False)
|
|
7
9
|
|
|
8
10
|
|
|
11
|
+
def _timestamp() -> str:
|
|
12
|
+
"""Return current time as HH:MM:SS."""
|
|
13
|
+
return datetime.now().strftime("%H:%M:%S")
|
|
14
|
+
|
|
15
|
+
|
|
9
16
|
def status(msg: str) -> None:
|
|
10
17
|
"""Print a dim status message."""
|
|
11
|
-
err_console.print(f"[dim]\\[scry-run][/dim] {msg}")
|
|
18
|
+
err_console.print(f"[dim]{_timestamp()} \\[scry-run][/dim] {msg}")
|
|
12
19
|
|
|
13
20
|
|
|
14
21
|
def info(msg: str) -> None:
|
|
15
22
|
"""Print an info message (cyan)."""
|
|
16
|
-
err_console.print(f"[cyan]\\[scry-run][/cyan] {msg}")
|
|
23
|
+
err_console.print(f"[dim]{_timestamp()}[/dim] [cyan]\\[scry-run][/cyan] {msg}")
|
|
17
24
|
|
|
18
25
|
|
|
19
26
|
def success(msg: str) -> None:
|
|
20
27
|
"""Print a success message (green)."""
|
|
21
|
-
err_console.print(f"[green]\\[scry-run][/green] {msg}")
|
|
28
|
+
err_console.print(f"[dim]{_timestamp()}[/dim] [green]\\[scry-run][/green] {msg}")
|
|
22
29
|
|
|
23
30
|
|
|
24
31
|
def warning(msg: str) -> None:
|
|
25
32
|
"""Print a warning message (yellow)."""
|
|
26
|
-
err_console.print(f"[yellow]\\[scry-run][/yellow] {msg}")
|
|
33
|
+
err_console.print(f"[dim]{_timestamp()}[/dim] [yellow]\\[scry-run][/yellow] {msg}")
|
|
27
34
|
|
|
28
35
|
|
|
29
36
|
def error(msg: str) -> None:
|
|
30
37
|
"""Print an error message (red)."""
|
|
31
|
-
err_console.print(f"[red]\\[scry-run][/red] {msg}")
|
|
38
|
+
err_console.print(f"[dim]{_timestamp()}[/dim] [red]\\[scry-run][/red] {msg}")
|
|
32
39
|
|
|
33
40
|
|
|
34
41
|
def generating(class_name: str, attr_name: str) -> None:
|
|
35
42
|
"""Print a 'generating' message."""
|
|
36
|
-
err_console.print(f"[cyan]\\[scry-run][/cyan] Generating {class_name}.{attr_name}...")
|
|
43
|
+
err_console.print(f"[dim]{_timestamp()}[/dim] [cyan]\\[scry-run][/cyan] Generating {class_name}.{attr_name}...")
|
|
37
44
|
|
|
38
45
|
|
|
39
46
|
def generated(class_name: str, attr_name: str) -> None:
|
|
40
47
|
"""Print a 'generated' success message."""
|
|
41
|
-
err_console.print(f"[green]\\[scry-run][/green] Generated {class_name}.{attr_name} ✓")
|
|
48
|
+
err_console.print(f"[dim]{_timestamp()}[/dim] [green]\\[scry-run][/green] Generated {class_name}.{attr_name} ✓")
|
|
42
49
|
|
|
43
50
|
|
|
44
51
|
def using_cached(class_name: str, attr_name: str) -> None:
|
|
45
52
|
"""Print a 'using cached' message."""
|
|
46
|
-
err_console.print(f"[dim]\\[scry-run][/dim] Using cached {class_name}.{attr_name}")
|
|
53
|
+
err_console.print(f"[dim]{_timestamp()} \\[scry-run][/dim] Using cached {class_name}.{attr_name}")
|
|
47
54
|
|
|
48
55
|
|
|
49
56
|
def backend_selected(backend_name: str, model: str | None, reason: str) -> None:
|
|
50
57
|
"""Print backend selection message."""
|
|
51
58
|
model_str = f" (model={model})" if model else ""
|
|
52
|
-
err_console.print(f"[dim]\\[scry-run][/dim] Using backend: {backend_name}{model_str} ({reason})")
|
|
59
|
+
err_console.print(f"[dim]{_timestamp()} \\[scry-run][/dim] Using backend: {backend_name}{model_str} ({reason})")
|
scry_run/generator.py
CHANGED
|
@@ -603,8 +603,31 @@ IMPORTANT: Output ONLY the JSON object, no markdown, no explanation, no code fen
|
|
|
603
603
|
|
|
604
604
|
# Delegate to backend with retries
|
|
605
605
|
last_error: Optional[Exception] = None
|
|
606
|
+
previous_errors: list[str] = [] # Track errors for feedback
|
|
606
607
|
|
|
607
608
|
for attempt in range(self.MAX_RETRIES):
|
|
609
|
+
# Build error feedback for retry attempts
|
|
610
|
+
error_feedback = ""
|
|
611
|
+
if previous_errors:
|
|
612
|
+
error_feedback = f"""
|
|
613
|
+
|
|
614
|
+
## PREVIOUS GENERATION FAILED
|
|
615
|
+
|
|
616
|
+
This is generation attempt #{attempt + 1}. Previous attempt(s) caused errors:
|
|
617
|
+
|
|
618
|
+
{chr(10).join(f"- Attempt #{i+1}: {err}" for i, err in enumerate(previous_errors))}
|
|
619
|
+
|
|
620
|
+
Please analyze these errors and generate FIXED code that avoids them.
|
|
621
|
+
"""
|
|
622
|
+
|
|
623
|
+
# Rebuild prompt with error feedback if needed
|
|
624
|
+
if error_feedback:
|
|
625
|
+
if supports_context:
|
|
626
|
+
prompt = self._build_frame_prompt(class_name, attr_name, is_classmethod, runtime_context + error_feedback)
|
|
627
|
+
else:
|
|
628
|
+
prompt = self._build_prompt(context + error_feedback, class_name, attr_name, is_classmethod, installed_packages)
|
|
629
|
+
logger.log_generation_start(class_name, attr_name, prompt)
|
|
630
|
+
|
|
608
631
|
try:
|
|
609
632
|
result = self._backend.generate_code(prompt)
|
|
610
633
|
|
|
@@ -645,7 +668,15 @@ IMPORTANT: Output ONLY the JSON object, no markdown, no explanation, no code fen
|
|
|
645
668
|
# Log the validation error with full details
|
|
646
669
|
code_str = result.code if 'result' in dir() and hasattr(result, 'code') else None
|
|
647
670
|
logger.log_validation_error(e, code_str)
|
|
648
|
-
|
|
671
|
+
|
|
672
|
+
# Track error for feedback on next attempt
|
|
673
|
+
error_msg = f"{type(e).__name__}: {e}"
|
|
674
|
+
if code_str:
|
|
675
|
+
# Include a snippet of the problematic code
|
|
676
|
+
code_preview = code_str[:200] + "..." if len(code_str) > 200 else code_str
|
|
677
|
+
error_msg += f"\n Generated code (preview): {code_preview}"
|
|
678
|
+
previous_errors.append(error_msg)
|
|
679
|
+
|
|
649
680
|
if attempt >= self.MAX_RETRIES - 1:
|
|
650
681
|
raise
|
|
651
682
|
warning(f"Validation error, retrying ({attempt + 1}/{self.MAX_RETRIES})...")
|
scry_run/meta.py
CHANGED
|
@@ -995,6 +995,7 @@ Requirements:
|
|
|
995
995
|
MAX_RETRIES = 3
|
|
996
996
|
last_error = None
|
|
997
997
|
current_context = call_context
|
|
998
|
+
previous_errors: list[str] = [] # Track all errors for accumulated feedback
|
|
998
999
|
|
|
999
1000
|
for attempt in range(MAX_RETRIES + 1):
|
|
1000
1001
|
# Generate code
|
|
@@ -1035,28 +1036,28 @@ Requirements:
|
|
|
1035
1036
|
# Invalidate cache so _llm_generate actually generates new code
|
|
1036
1037
|
self._cls._get_cache().prune(self._cls.__name__, self._name)
|
|
1037
1038
|
|
|
1038
|
-
#
|
|
1039
|
+
# Track this error
|
|
1039
1040
|
if is_signature_error:
|
|
1040
|
-
|
|
1041
|
-
|
|
1041
|
+
previous_errors.append(f"Attempt #{attempt + 1} - TypeError (signature mismatch): {e}")
|
|
1042
|
+
else:
|
|
1043
|
+
previous_errors.append(f"Attempt #{attempt + 1} - {type(e).__name__}: {e}")
|
|
1042
1044
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
+
# Build accumulated error feedback
|
|
1046
|
+
errors_list = chr(10).join(f" {err}" for err in previous_errors)
|
|
1047
|
+
error_feedback = f"""
|
|
1048
|
+
## CRITICAL - PREVIOUS GENERATION FAILED
|
|
1045
1049
|
|
|
1046
|
-
|
|
1047
|
-
{chr(10).join(args_desc) if args_desc else "No arguments ()"}
|
|
1050
|
+
This is generation attempt #{attempt + 2}. Previous attempt(s) caused errors:
|
|
1048
1051
|
|
|
1049
|
-
|
|
1050
|
-
"""
|
|
1051
|
-
else:
|
|
1052
|
-
error_feedback = f"""
|
|
1053
|
-
## CRITICAL ERROR - RUNTIME EXCEPTION
|
|
1052
|
+
{errors_list}
|
|
1054
1053
|
|
|
1055
|
-
|
|
1056
|
-
{
|
|
1054
|
+
The code was called with:
|
|
1055
|
+
{chr(10).join(args_desc) if args_desc else "No arguments ()"}
|
|
1057
1056
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1057
|
+
You MUST analyze ALL previous errors and generate FIXED code that:
|
|
1058
|
+
1. Has the correct signature matching how it is called
|
|
1059
|
+
2. Handles edge cases that caused runtime exceptions
|
|
1060
|
+
3. Does NOT repeat the same mistakes
|
|
1060
1061
|
"""
|
|
1061
1062
|
|
|
1062
1063
|
current_context = call_context + error_feedback
|
|
@@ -1356,7 +1357,7 @@ class ScryClass(metaclass=ScryMeta):
|
|
|
1356
1357
|
_llm_cache: Optional["ScryCache"] = None
|
|
1357
1358
|
_llm_generator: Optional["CodeGenerator"] = None
|
|
1358
1359
|
_llm_model: Optional[str] = None # Model override (e.g., "opus" for Claude)
|
|
1359
|
-
_llm_backend: Optional[str] = None # Backend override (e.g., "frozen"
|
|
1360
|
+
_llm_backend: Optional[str] = None # Backend override (e.g., "frozen" to prevent generation)
|
|
1360
1361
|
_llm_use_full_context: bool = True
|
|
1361
1362
|
_llm_quiet: bool = False # Set to True to suppress generation messages
|
|
1362
1363
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scry-run
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: LLM-powered dynamic code generation via metaclasses. Define classes with docstrings, call any method—code generates automatically, caches persistently, and executes instantly.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Tener/scry-run
|
|
6
|
+
Project-URL: Repository, https://github.com/Tener/scry-run
|
|
7
|
+
Author: Krzysztof Skrzętnicki
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: ai,claude,code-generation,llm,metaclass
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: claude-agent-sdk>=0.1.0
|
|
20
|
+
Requires-Dist: click>=8.0.0
|
|
21
|
+
Requires-Dist: jinja2>=3.0.0
|
|
22
|
+
Requires-Dist: rich>=13.0.0
|
|
23
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-timeout>=2.0.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# scry-run
|
|
32
|
+
|
|
33
|
+
**Describe an app, run it.** A CLI tool that generates and runs Python applications from natural language descriptions.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv tool install scry-run
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or run without installing:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uvx scry-run --help
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Requires [Claude Code CLI](https://github.com/anthropics/claude-code) to be installed.
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Create an app
|
|
53
|
+
scry-run init --name=todoist --description='minimal web todo app'
|
|
54
|
+
|
|
55
|
+
# Run it
|
|
56
|
+
scry-run run todoist
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Demos
|
|
60
|
+
|
|
61
|
+
### Creating a simple Hello World app
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
### Building a maze game with PyGame
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
## CLI Commands
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Create a new app
|
|
73
|
+
scry-run init --name=NAME --description=DESC
|
|
74
|
+
|
|
75
|
+
# List all apps
|
|
76
|
+
scry-run list
|
|
77
|
+
|
|
78
|
+
# Run an app
|
|
79
|
+
scry-run run myapp [args...]
|
|
80
|
+
|
|
81
|
+
# Get app info
|
|
82
|
+
scry-run info myapp
|
|
83
|
+
scry-run which myapp
|
|
84
|
+
|
|
85
|
+
# Remove or reset an app
|
|
86
|
+
scry-run rm myapp
|
|
87
|
+
scry-run reset myapp
|
|
88
|
+
|
|
89
|
+
# Cache management
|
|
90
|
+
scry-run cache list myapp
|
|
91
|
+
scry-run cache show myapp MyClass.method
|
|
92
|
+
scry-run cache export myapp --output=code.py
|
|
93
|
+
scry-run cache prune myapp --all
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
| Variable | Description | Default |
|
|
99
|
+
|----------|-------------|---------|
|
|
100
|
+
| `SCRY_RUN_BACKEND` | Backend: `claude`, `frozen`, or `auto` | `auto` |
|
|
101
|
+
| `SCRY_RUN_MODEL` | Model override (e.g., `opus`) | (backend default) |
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
scry_run/__init__.py,sha256=uAFNmvmMzEpsFNJ3Uew4RUSgNPXvn_cFkTU2Bx8RmWo,2875
|
|
2
2
|
scry_run/cache.py,sha256=gzWNCRva4d1KOqrYx0eo0T9o8lbsBYmcxgnXPUfc9Dg,14163
|
|
3
3
|
scry_run/config.py,sha256=zBnxbzHKwWDpg0C1BmSm6SGv5PF7rq_cSctWIsm_oz0,4083
|
|
4
|
-
scry_run/console.py,sha256=
|
|
4
|
+
scry_run/console.py,sha256=1lVWZ-7tfbapl1wSYZ7zOWBwgKSn6LgR0QZYneILsgQ,2044
|
|
5
5
|
scry_run/context.py,sha256=os3kdrYxcgzrkPPiPzIy9Lrlp4b964eishDb7KSCaCY,10256
|
|
6
|
-
scry_run/generator.py,sha256=
|
|
6
|
+
scry_run/generator.py,sha256=GjDGBgbes58L4Amo-tuXodfs7Tx2vGn_CO1YVdJMVjo,26422
|
|
7
7
|
scry_run/home.py,sha256=-ZOgvsaJ0udH_a0_A0YYBZHjtLzGMVaU_t5NqmcBNIQ,1364
|
|
8
8
|
scry_run/logging.py,sha256=zKB_-IgRT9GXVULaFJKepX4oUVXQlt3buqjzBoh9Uyo,5684
|
|
9
|
-
scry_run/meta.py,sha256=
|
|
9
|
+
scry_run/meta.py,sha256=shKzrDc-lUWIS8MOjouoVzPuOt3rP5zpWv5BvjIGWC4,71598
|
|
10
10
|
scry_run/packages.py,sha256=U6HxWoEkFisKwLAeM_RtFvTt2qrCmxmZD38pJNVQt7g,5156
|
|
11
11
|
scry_run/backends/__init__.py,sha256=q52KwLy2KsJLxpUJKbLsCTH0ELLLQGOz_14OnhDYOig,245
|
|
12
12
|
scry_run/backends/base.py,sha256=bedYMpVL19dE_ei85wWRj8g5zsJsH607G8nAgsDpfwI,1693
|
|
13
13
|
scry_run/backends/claude.py,sha256=fqYK1F1PsqCM2-ssvmdduhwjrsVURcLeCTJLxTbAKPE,15038
|
|
14
|
-
scry_run/backends/frozen.py,sha256=
|
|
14
|
+
scry_run/backends/frozen.py,sha256=69vqlztysFXuX7Nv5nu-bDqhan8F-0mHgGCC_4kOiQA,2912
|
|
15
15
|
scry_run/backends/registry.py,sha256=pAOrZcaWHJhIn6ai-O6lBzb0QeICa3MV-kH5zcDcRrM,2180
|
|
16
16
|
scry_run/cli/__init__.py,sha256=Hje8gmqzBsbX5iW6lKVfv5ZOXamkUVx-fGnwRupgmuU,5385
|
|
17
17
|
scry_run/cli/apps.py,sha256=AP016GpSH4_mPpXq3k8r4hjBE5Kizxk9mDQNZpdAt0c,12609
|
|
18
18
|
scry_run/cli/cache.py,sha256=UkxSFZUqiyDxn2KrFojh8UT03d_lBxJmolsV7w7qTmU,10774
|
|
19
19
|
scry_run/cli/config_cmd.py,sha256=Ge8Xw8R3_LpEfCOrXgaeD-0KG4WrVslMpNdZhtReOp8,2436
|
|
20
20
|
scry_run/cli/env.py,sha256=Jxw5I6TY5sJ0Rsha86OZDPRHDS850FA4n30sg4yFKhQ,745
|
|
21
|
-
scry_run/cli/init.py,sha256=
|
|
21
|
+
scry_run/cli/init.py,sha256=awBdgL0gILM5RJBKp2ZfuvkqmMdew_drAPRqq5QSrRw,13509
|
|
22
22
|
scry_run/cli/run.py,sha256=vH89DttVCQwNWWwvUNxo9IbjnCGU2F_1OeWrMxHsvc8,2327
|
|
23
|
-
scry_run-0.1.
|
|
24
|
-
scry_run-0.1.
|
|
25
|
-
scry_run-0.1.
|
|
26
|
-
scry_run-0.1.
|
|
23
|
+
scry_run-0.1.1.dist-info/METADATA,sha256=gZKL-lU4-KH79pCG0hFXnW7WsMtt7ovQ92s9INCvm_A,2651
|
|
24
|
+
scry_run-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
25
|
+
scry_run-0.1.1.dist-info/entry_points.txt,sha256=edV5nv1PT_pjWsOcLR3DMNkV-MUBsCY-jORR4dee-Ho,47
|
|
26
|
+
scry_run-0.1.1.dist-info/RECORD,,
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: scry-run
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: LLM-powered dynamic code generation via metaclasses. Define classes with docstrings, call any method—code generates automatically, caches persistently, and executes instantly.
|
|
5
|
-
Project-URL: Homepage, https://github.com/Tener/scry-run
|
|
6
|
-
Project-URL: Repository, https://github.com/Tener/scry-run
|
|
7
|
-
Author: Krzysztof Skrzętnicki
|
|
8
|
-
License: MIT
|
|
9
|
-
Keywords: ai,claude,code-generation,llm,metaclass
|
|
10
|
-
Classifier: Development Status :: 3 - Alpha
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Classifier: Topic :: Software Development :: Code Generators
|
|
18
|
-
Requires-Python: >=3.10
|
|
19
|
-
Requires-Dist: claude-agent-sdk>=0.1.0
|
|
20
|
-
Requires-Dist: click>=8.0.0
|
|
21
|
-
Requires-Dist: jinja2>=3.0.0
|
|
22
|
-
Requires-Dist: rich>=13.0.0
|
|
23
|
-
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
24
|
-
Provides-Extra: dev
|
|
25
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
26
|
-
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
27
|
-
Requires-Dist: pytest-timeout>=2.0.0; extra == 'dev'
|
|
28
|
-
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
29
|
-
Description-Content-Type: text/markdown
|
|
30
|
-
|
|
31
|
-
# scry-run
|
|
32
|
-
|
|
33
|
-
**Write class definitions, get working code.** A Python library where any method call automatically generates its implementation via LLM.
|
|
34
|
-
|
|
35
|
-
Define your application as a class with a docstring, then call any method you want—`scry-run` generates the code on-demand, caches it, and executes it. No boilerplate, no implementation required.
|
|
36
|
-
|
|
37
|
-
## Features
|
|
38
|
-
|
|
39
|
-
- **Zero-boilerplate coding**: Define intent via class docstrings, methods generate automatically
|
|
40
|
-
- **Intelligent caching**: Generated code persists across runs—pay once, use forever
|
|
41
|
-
- **Production-ready**: Bake apps into standalone packages with frozen, pre-generated code
|
|
42
|
-
- **CLI-first**: Manage apps, inspect cache, and export generated code via intuitive commands
|
|
43
|
-
|
|
44
|
-
## Installation
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
pip install scry-run
|
|
48
|
-
# or with uv
|
|
49
|
-
uv pip install scry-run
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Run without installing (uvx)
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# From PyPI
|
|
56
|
-
uvx scry-run --help
|
|
57
|
-
uvx scry-run init --name=myapp --description="My app"
|
|
58
|
-
|
|
59
|
-
# From GitHub (latest)
|
|
60
|
-
uvx --from git+https://github.com/scry-run/scry-run scry-run --help
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Quick Start
|
|
64
|
-
|
|
65
|
-
### 1. Set up your backend
|
|
66
|
-
|
|
67
|
-
Requires Claude Code CLI to be installed.
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
# Verify claude CLI is available
|
|
71
|
-
claude --version
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### 2. Initialize a project
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
# Non-interactive
|
|
78
|
-
scry-run init --name=todoist --description='minimal web todo app'
|
|
79
|
-
|
|
80
|
-
# Interactive
|
|
81
|
-
scry-run init
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 3. Run your app
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
scry-run run todoist
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Or use it directly in Python:
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
from scry_run import ScryClass
|
|
94
|
-
|
|
95
|
-
class Todoist(ScryClass):
|
|
96
|
-
"""A minimal web todo app with task management."""
|
|
97
|
-
pass
|
|
98
|
-
|
|
99
|
-
app = Todoist()
|
|
100
|
-
|
|
101
|
-
# These methods will be generated automatically!
|
|
102
|
-
app.add_task("Buy groceries")
|
|
103
|
-
app.list_tasks()
|
|
104
|
-
app.complete_task(0)
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Demos
|
|
108
|
-
|
|
109
|
-
### Creating a simple Hello World app
|
|
110
|
-
|
|
111
|
-

|
|
112
|
-
|
|
113
|
-
### Building a maze game with PyGame
|
|
114
|
-
|
|
115
|
-

|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
## How It Works
|
|
119
|
-
|
|
120
|
-
1. When you access an undefined attribute on an `ScryClass` subclass, the metaclass intercepts it
|
|
121
|
-
2. The library collects the full codebase context and builds a prompt
|
|
122
|
-
3. The configured backend generates code with structured JSON output (code, type, docstring, dependencies)
|
|
123
|
-
4. The code is validated with Python's `ast.parse()` to ensure it's syntactically correct
|
|
124
|
-
5. Valid code is cached and executed
|
|
125
|
-
6. On subsequent accesses, the cached code is used directly
|
|
126
|
-
|
|
127
|
-
## Backend
|
|
128
|
-
|
|
129
|
-
Uses Claude Code CLI with `--print` flag for non-interactive output.
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
# If claude CLI is installed, it's used automatically
|
|
133
|
-
scry-run run myapp
|
|
134
|
-
|
|
135
|
-
# Optionally specify a model
|
|
136
|
-
export SCRY_RUN_MODEL=opus
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Configuration
|
|
140
|
-
|
|
141
|
-
### Environment Variables
|
|
142
|
-
|
|
143
|
-
| Variable | Description | Default |
|
|
144
|
-
|----------|-------------|---------|
|
|
145
|
-
| `SCRY_RUN_BACKEND` | Backend to use: `claude`, `frozen`, or `auto` | `auto` |
|
|
146
|
-
| `SCRY_RUN_MODEL` | Model override (e.g., `opus`) | (backend default) |
|
|
147
|
-
| `SCRY_RUN_MAX_GENERATIONS` | Max code generations per process | `100` |
|
|
148
|
-
|
|
149
|
-
### Class-level options
|
|
150
|
-
|
|
151
|
-
```python
|
|
152
|
-
class MyApp(ScryClass):
|
|
153
|
-
"""My application."""
|
|
154
|
-
|
|
155
|
-
# Disable LLM generation (raises AttributeError for missing attrs)
|
|
156
|
-
_llm_enabled = False
|
|
157
|
-
|
|
158
|
-
# Use minimal context instead of full codebase (faster)
|
|
159
|
-
_llm_use_full_context = False
|
|
160
|
-
|
|
161
|
-
# Suppress generation messages
|
|
162
|
-
_llm_quiet = True
|
|
163
|
-
|
|
164
|
-
# Override model for this class
|
|
165
|
-
_llm_model = "opus"
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## CLI Commands
|
|
169
|
-
|
|
170
|
-
### App Management
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
# Initialize a new app
|
|
174
|
-
scry-run init --name=NAME --description=DESC
|
|
175
|
-
|
|
176
|
-
# List all apps
|
|
177
|
-
scry-run list
|
|
178
|
-
|
|
179
|
-
# Get path to an app's main file
|
|
180
|
-
scry-run which myapp
|
|
181
|
-
|
|
182
|
-
# Run an app
|
|
183
|
-
scry-run run myapp [args...]
|
|
184
|
-
|
|
185
|
-
# Remove an app
|
|
186
|
-
scry-run rm myapp
|
|
187
|
-
scry-run rm myapp --force # Skip confirmation
|
|
188
|
-
|
|
189
|
-
# Reset an app (clear code & cache, keep name/description)
|
|
190
|
-
scry-run reset myapp
|
|
191
|
-
scry-run reset myapp --force # Skip confirmation
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Cache Management
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
# List cached entries for an app
|
|
198
|
-
scry-run cache list myapp
|
|
199
|
-
|
|
200
|
-
# Show a specific entry
|
|
201
|
-
scry-run cache show myapp MyClass.my_method
|
|
202
|
-
|
|
203
|
-
# Export cache
|
|
204
|
-
scry-run cache export myapp --output=generated.py --format=python
|
|
205
|
-
scry-run cache export myapp --output=cache.json --format=json
|
|
206
|
-
|
|
207
|
-
# Remove a specific entry
|
|
208
|
-
scry-run cache rm myapp MyClass.my_method
|
|
209
|
-
|
|
210
|
-
# Prune cache entries
|
|
211
|
-
scry-run cache prune myapp --class=MyClass --attr=my_method
|
|
212
|
-
scry-run cache prune myapp --class=MyClass # All methods of a class
|
|
213
|
-
scry-run cache prune myapp --all # Everything
|
|
214
|
-
|
|
215
|
-
# Reset cache (clear all entries)
|
|
216
|
-
scry-run cache reset myapp --force
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## API
|
|
220
|
-
|
|
221
|
-
### ScryClass
|
|
222
|
-
|
|
223
|
-
Base class to inherit from for LLM-powered code generation.
|
|
224
|
-
|
|
225
|
-
```python
|
|
226
|
-
from scry_run import ScryClass
|
|
227
|
-
|
|
228
|
-
class MyApp(ScryClass):
|
|
229
|
-
"""Description of your app - the LLM uses this!"""
|
|
230
|
-
|
|
231
|
-
def existing_method(self):
|
|
232
|
-
"""Existing methods are used as context."""
|
|
233
|
-
return "hello"
|
|
234
|
-
|
|
235
|
-
# Class methods
|
|
236
|
-
MyApp.llm_export_cache("output.py") # Export generated code
|
|
237
|
-
MyApp.llm_prune_cache("method_name") # Remove cached entry
|
|
238
|
-
MyApp.llm_disable() # Disable generation
|
|
239
|
-
MyApp.llm_enable() # Re-enable generation
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### ScryCache
|
|
243
|
-
|
|
244
|
-
Manage the code cache programmatically.
|
|
245
|
-
|
|
246
|
-
```python
|
|
247
|
-
from scry_run import ScryCache
|
|
248
|
-
|
|
249
|
-
cache = ScryCache()
|
|
250
|
-
|
|
251
|
-
# Get cached code
|
|
252
|
-
entry = cache.get("MyClass", "my_method")
|
|
253
|
-
print(entry.code)
|
|
254
|
-
|
|
255
|
-
# List all entries
|
|
256
|
-
for entry in cache.list_entries():
|
|
257
|
-
print(f"{entry.class_name}.{entry.attr_name}: {entry.docstring}")
|
|
258
|
-
|
|
259
|
-
# Export
|
|
260
|
-
cache.export_to_file("all_generated_code.py")
|
|
261
|
-
|
|
262
|
-
# Prune
|
|
263
|
-
cache.prune(class_name="MyClass", attr_name="my_method")
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## Development
|
|
267
|
-
|
|
268
|
-
```bash
|
|
269
|
-
# Clone the repo
|
|
270
|
-
git clone https://github.com/scry-run/scry-run
|
|
271
|
-
cd scry-run
|
|
272
|
-
|
|
273
|
-
# Install with dev dependencies
|
|
274
|
-
uv sync --dev
|
|
275
|
-
|
|
276
|
-
# Run tests
|
|
277
|
-
uv run pytest tests/ -v
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
## License
|
|
281
|
-
|
|
282
|
-
MIT
|
|
File without changes
|
|
File without changes
|