abelworkflow 0.1.0 → 0.1.1
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.
- package/.gitignore +2 -0
- package/README.md +64 -39
- package/bin/abelworkflow.mjs +0 -0
- package/lib/cli.mjs +1366 -66
- package/package.json +1 -1
- package/skills/grok-search/SKILL.md +20 -91
- package/skills/grok-search/scripts/_dotenv.py +28 -0
- package/skills/grok-search/scripts/groksearch_cli.py +2 -2
- package/skills/grok-search/scripts/groksearch_entry.py +25 -10
- package/skills/prompt-enhancer/.env.example +14 -0
- package/skills/prompt-enhancer/ADVANCED.md +40 -13
- package/skills/prompt-enhancer/SKILL.md +28 -54
- package/skills/prompt-enhancer/requirements.txt +2 -0
- package/skills/prompt-enhancer/scripts/_dotenv.py +28 -0
- package/skills/prompt-enhancer/scripts/enhance.py +52 -42
- package/skills/prompt-enhancer/scripts/prompt_enhancer_entry.py +212 -0
- package/skills/context7-auto-research/.env +0 -4
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Prompt Enhancer Script - Standalone Python script for enhancing prompts.
|
|
4
|
-
Can be used with or without an API key.
|
|
5
|
-
"""
|
|
2
|
+
"""Prompt Enhancer CLI."""
|
|
6
3
|
|
|
7
|
-
import sys
|
|
8
4
|
import os
|
|
9
|
-
import
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from _dotenv import load_dotenv
|
|
8
|
+
|
|
9
|
+
load_dotenv()
|
|
10
|
+
|
|
10
11
|
|
|
11
12
|
SYSTEM_PROMPT = """
|
|
12
13
|
You are an expert Prompt Engineer for Coding Agents (Claude Code, Codex, Gemini CLI).
|
|
@@ -41,21 +42,34 @@ Output Template:
|
|
|
41
42
|
"""
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
def debug_enabled() -> bool:
|
|
46
|
+
"""Return True when debug logging is explicitly enabled."""
|
|
47
|
+
value = os.environ.get("PE_DEBUG", "")
|
|
48
|
+
return value.strip().lower() in {"1", "true", "yes", "on"}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_env_or_default(name: str, default: str) -> str:
|
|
52
|
+
"""Return default when an env var is missing or blank."""
|
|
53
|
+
value = os.environ.get(name)
|
|
54
|
+
if value is None:
|
|
55
|
+
return default
|
|
56
|
+
|
|
57
|
+
value = value.strip()
|
|
58
|
+
return value or default
|
|
59
|
+
|
|
60
|
+
|
|
44
61
|
def enhance_with_anthropic(prompt: str, api_key: str) -> str:
|
|
45
62
|
"""Enhance prompt using Anthropic API."""
|
|
46
63
|
try:
|
|
47
64
|
import anthropic
|
|
48
65
|
except ImportError:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)
|
|
54
|
-
import anthropic
|
|
55
|
-
|
|
66
|
+
raise RuntimeError(
|
|
67
|
+
"Missing dependency: anthropic. Install dependencies for the configured provider."
|
|
68
|
+
) from None
|
|
69
|
+
|
|
56
70
|
client = anthropic.Anthropic(api_key=api_key)
|
|
57
71
|
message = client.messages.create(
|
|
58
|
-
model=
|
|
72
|
+
model=get_env_or_default("PE_MODEL", "claude-sonnet-4-20250514"),
|
|
59
73
|
max_tokens=2048,
|
|
60
74
|
system=SYSTEM_PROMPT,
|
|
61
75
|
messages=[{"role": "user", "content": prompt}]
|
|
@@ -68,16 +82,13 @@ def enhance_with_openai(prompt: str, api_key: str) -> str:
|
|
|
68
82
|
try:
|
|
69
83
|
import openai
|
|
70
84
|
except ImportError:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
)
|
|
76
|
-
import openai
|
|
77
|
-
|
|
85
|
+
raise RuntimeError(
|
|
86
|
+
"Missing dependency: openai. Install dependencies for the configured provider."
|
|
87
|
+
) from None
|
|
88
|
+
|
|
78
89
|
client = openai.OpenAI(api_key=api_key)
|
|
79
90
|
response = client.chat.completions.create(
|
|
80
|
-
model=
|
|
91
|
+
model=get_env_or_default("PE_MODEL", "gpt-4o"),
|
|
81
92
|
messages=[
|
|
82
93
|
{"role": "system", "content": SYSTEM_PROMPT},
|
|
83
94
|
{"role": "user", "content": prompt}
|
|
@@ -89,54 +100,53 @@ def enhance_with_openai(prompt: str, api_key: str) -> str:
|
|
|
89
100
|
def enhance_locally(prompt: str) -> str:
|
|
90
101
|
"""Enhance prompt using local template (no API)."""
|
|
91
102
|
return f"""# Context
|
|
92
|
-
[
|
|
103
|
+
[Add only the known repo, file, stack, or runtime context. If unknown, use placeholders like [files], [stack], or [environment].]
|
|
93
104
|
|
|
94
105
|
# Objective
|
|
95
106
|
{prompt}
|
|
96
107
|
|
|
97
108
|
# Step-by-Step Instructions
|
|
98
|
-
1.
|
|
99
|
-
2.
|
|
100
|
-
3.
|
|
101
|
-
4.
|
|
102
|
-
5.
|
|
109
|
+
1. Restate the task precisely without changing the user's intent.
|
|
110
|
+
2. Carry forward every explicit constraint from the original prompt.
|
|
111
|
+
3. Add only the minimum missing execution context needed to act.
|
|
112
|
+
4. If important details are unknown, leave placeholders instead of inventing requirements.
|
|
113
|
+
5. Return the rewritten prompt in this structure.
|
|
103
114
|
|
|
104
115
|
# Constraints
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
116
|
+
- Preserve the user's intent and explicit constraints.
|
|
117
|
+
- Do not invent product, compatibility, or implementation requirements.
|
|
118
|
+
- Keep the result concise, specific, and actionable for a coding agent.
|
|
108
119
|
"""
|
|
109
120
|
|
|
110
121
|
|
|
111
122
|
def main():
|
|
112
123
|
if len(sys.argv) < 2:
|
|
113
|
-
print("Usage:
|
|
114
|
-
print("Example:
|
|
124
|
+
print("Usage: prompt_enhancer_entry.py <prompt>", file=sys.stderr)
|
|
125
|
+
print("Example: prompt_enhancer_entry.py 'Write a login component'", file=sys.stderr)
|
|
126
|
+
print("Environment: ANTHROPIC_API_KEY | OPENAI_API_KEY | PE_MODEL", file=sys.stderr)
|
|
115
127
|
sys.exit(1)
|
|
116
|
-
|
|
128
|
+
|
|
117
129
|
prompt = " ".join(sys.argv[1:])
|
|
118
|
-
|
|
130
|
+
|
|
119
131
|
# Try Anthropic first, then OpenAI, then local
|
|
120
132
|
anthropic_key = os.environ.get("ANTHROPIC_API_KEY")
|
|
121
133
|
openai_key = os.environ.get("OPENAI_API_KEY")
|
|
122
|
-
|
|
134
|
+
|
|
123
135
|
try:
|
|
124
136
|
if anthropic_key:
|
|
125
137
|
result = enhance_with_anthropic(prompt, anthropic_key)
|
|
126
138
|
elif openai_key:
|
|
127
139
|
result = enhance_with_openai(prompt, openai_key)
|
|
128
140
|
else:
|
|
129
|
-
# No API key - use local template
|
|
130
|
-
print("Note: No API key found, using local template.", file=sys.stderr)
|
|
131
141
|
result = enhance_locally(prompt)
|
|
132
|
-
|
|
142
|
+
|
|
133
143
|
print(result)
|
|
134
144
|
except Exception as e:
|
|
135
|
-
|
|
136
|
-
|
|
145
|
+
if debug_enabled():
|
|
146
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
147
|
+
print("\nFalling back to local template...", file=sys.stderr)
|
|
137
148
|
print(enhance_locally(prompt))
|
|
138
149
|
|
|
139
150
|
|
|
140
151
|
if __name__ == "__main__":
|
|
141
152
|
main()
|
|
142
|
-
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Cross-platform bootstrap entrypoint for Prompt Enhancer."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import List, Optional
|
|
11
|
+
|
|
12
|
+
from _dotenv import load_dotenv
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
ROOT_DIR = Path(__file__).resolve().parent.parent
|
|
16
|
+
REQ_FILE = ROOT_DIR / "requirements.txt"
|
|
17
|
+
CLI_PY = ROOT_DIR / "scripts" / "enhance.py"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def debug_enabled() -> bool:
|
|
21
|
+
value = os.environ.get("PE_DEBUG", "")
|
|
22
|
+
return value.strip().lower() in {"1", "true", "yes", "on"}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def venv_dir() -> Path:
|
|
26
|
+
configured = os.environ.get("PROMPT_ENHANCER_VENV_DIR")
|
|
27
|
+
if not configured:
|
|
28
|
+
return ROOT_DIR / ".venv"
|
|
29
|
+
dir_path = Path(configured).expanduser()
|
|
30
|
+
if dir_path.is_absolute():
|
|
31
|
+
return dir_path
|
|
32
|
+
return ROOT_DIR / dir_path
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def venv_python() -> Optional[Path]:
|
|
36
|
+
dir_path = venv_dir()
|
|
37
|
+
candidates = []
|
|
38
|
+
if sys.platform == "win32":
|
|
39
|
+
candidates.extend(
|
|
40
|
+
[
|
|
41
|
+
dir_path / "Scripts" / "python.exe",
|
|
42
|
+
dir_path / "Scripts" / "python",
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
candidates.append(dir_path / "bin" / "python")
|
|
46
|
+
for candidate in candidates:
|
|
47
|
+
if candidate.is_file():
|
|
48
|
+
return candidate
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def python_spec() -> Optional[str]:
|
|
53
|
+
for name in ("PROMPT_ENHANCER_PYTHON", "AGENTS_SKILLS_PYTHON"):
|
|
54
|
+
value = os.environ.get(name)
|
|
55
|
+
if value:
|
|
56
|
+
return value
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def has_uv() -> bool:
|
|
61
|
+
return shutil.which("uv") is not None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def find_system_python() -> Optional[str]:
|
|
65
|
+
env_python = os.environ.get("AGENTS_SKILLS_PYTHON")
|
|
66
|
+
if env_python and Path(env_python).is_file():
|
|
67
|
+
return env_python
|
|
68
|
+
if sys.executable and Path(sys.executable).is_file():
|
|
69
|
+
return sys.executable
|
|
70
|
+
for command in ("python3", "python"):
|
|
71
|
+
found = shutil.which(command)
|
|
72
|
+
if found:
|
|
73
|
+
return found
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def create_venv() -> None:
|
|
78
|
+
dir_path = venv_dir()
|
|
79
|
+
if has_uv():
|
|
80
|
+
command = ["uv", "venv"]
|
|
81
|
+
spec = python_spec()
|
|
82
|
+
if spec:
|
|
83
|
+
command.extend(["--python", spec])
|
|
84
|
+
command.append(str(dir_path))
|
|
85
|
+
subprocess.run(command, check=True)
|
|
86
|
+
return
|
|
87
|
+
python_bin = find_system_python()
|
|
88
|
+
if not python_bin:
|
|
89
|
+
print("Error: No usable uv or python found. Cannot create virtual environment.", file=sys.stderr)
|
|
90
|
+
sys.exit(1)
|
|
91
|
+
subprocess.run([python_bin, "-m", "venv", str(dir_path)], check=True)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def required_modules() -> List[str]:
|
|
95
|
+
modules = []
|
|
96
|
+
if os.environ.get("ANTHROPIC_API_KEY"):
|
|
97
|
+
modules.append("anthropic")
|
|
98
|
+
if os.environ.get("OPENAI_API_KEY"):
|
|
99
|
+
modules.append("openai")
|
|
100
|
+
return modules
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def install_targets(modules: List[str]) -> List[str]:
|
|
104
|
+
if not REQ_FILE.is_file():
|
|
105
|
+
return modules
|
|
106
|
+
|
|
107
|
+
requirements = {}
|
|
108
|
+
for raw_line in REQ_FILE.read_text(encoding="utf-8").splitlines():
|
|
109
|
+
line = raw_line.split("#", 1)[0].strip()
|
|
110
|
+
if not line:
|
|
111
|
+
continue
|
|
112
|
+
package = re.split(r"[<>=!~\\[; ]", line, maxsplit=1)[0].strip().lower()
|
|
113
|
+
if package:
|
|
114
|
+
requirements[package] = line
|
|
115
|
+
|
|
116
|
+
return [requirements.get(module.lower(), module) for module in modules]
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def has_required_modules(python_bin: str, modules: List[str]) -> bool:
|
|
120
|
+
if not modules:
|
|
121
|
+
return True
|
|
122
|
+
check = subprocess.run(
|
|
123
|
+
[python_bin, "-c", "; ".join(f"import {module}" for module in modules)],
|
|
124
|
+
stdout=subprocess.DEVNULL,
|
|
125
|
+
stderr=subprocess.DEVNULL,
|
|
126
|
+
)
|
|
127
|
+
return check.returncode == 0
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def install_deps(python_bin: Path, modules: Optional[List[str]] = None) -> None:
|
|
131
|
+
modules = required_modules() if modules is None else modules
|
|
132
|
+
if not modules:
|
|
133
|
+
return
|
|
134
|
+
targets = install_targets(modules)
|
|
135
|
+
if has_required_modules(str(python_bin), modules):
|
|
136
|
+
return
|
|
137
|
+
try:
|
|
138
|
+
kwargs = {
|
|
139
|
+
"check": True,
|
|
140
|
+
"stdout": subprocess.DEVNULL,
|
|
141
|
+
"stderr": subprocess.PIPE,
|
|
142
|
+
"text": True,
|
|
143
|
+
}
|
|
144
|
+
if has_uv():
|
|
145
|
+
subprocess.run(["uv", "pip", "install", "--python", str(python_bin), *targets], **kwargs)
|
|
146
|
+
return
|
|
147
|
+
subprocess.run([str(python_bin), "-m", "pip", "install", *targets], **kwargs)
|
|
148
|
+
except subprocess.CalledProcessError as exc:
|
|
149
|
+
if debug_enabled():
|
|
150
|
+
details = (exc.stderr or "").strip()
|
|
151
|
+
if details:
|
|
152
|
+
print(details, file=sys.stderr)
|
|
153
|
+
print(
|
|
154
|
+
"Warning: Failed to install prompt enhancer dependencies; continuing with existing environment.",
|
|
155
|
+
file=sys.stderr,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def validate_venv_dir() -> None:
|
|
160
|
+
dir_path = venv_dir()
|
|
161
|
+
if dir_path.exists() and not dir_path.is_dir():
|
|
162
|
+
print(f"Error: {dir_path} exists but is not a directory.", file=sys.stderr)
|
|
163
|
+
sys.exit(1)
|
|
164
|
+
if dir_path.is_dir() and not (dir_path / "pyvenv.cfg").exists() and venv_python() is None:
|
|
165
|
+
print(f"Error: {dir_path} exists but is not a valid venv.", file=sys.stderr)
|
|
166
|
+
sys.exit(1)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def should_passthrough_cli() -> bool:
|
|
170
|
+
return len(sys.argv) < 2
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def passthrough_python() -> Optional[str]:
|
|
174
|
+
if sys.executable and Path(sys.executable).is_file():
|
|
175
|
+
return sys.executable
|
|
176
|
+
return find_system_python()
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def runtime_python() -> str:
|
|
180
|
+
modules = required_modules()
|
|
181
|
+
current_python = passthrough_python()
|
|
182
|
+
if current_python and has_required_modules(current_python, modules):
|
|
183
|
+
return current_python
|
|
184
|
+
|
|
185
|
+
validate_venv_dir()
|
|
186
|
+
python_bin = venv_python()
|
|
187
|
+
if python_bin is None:
|
|
188
|
+
create_venv()
|
|
189
|
+
python_bin = venv_python()
|
|
190
|
+
if python_bin is None:
|
|
191
|
+
print("Error: Failed to locate python in venv after creation.", file=sys.stderr)
|
|
192
|
+
sys.exit(1)
|
|
193
|
+
install_deps(python_bin, modules)
|
|
194
|
+
return str(python_bin)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def main() -> None:
|
|
198
|
+
if should_passthrough_cli():
|
|
199
|
+
python_bin = passthrough_python()
|
|
200
|
+
if not python_bin:
|
|
201
|
+
print("Error: No usable python found for CLI usage output.", file=sys.stderr)
|
|
202
|
+
sys.exit(1)
|
|
203
|
+
result = subprocess.run([python_bin, str(CLI_PY)] + sys.argv[1:])
|
|
204
|
+
sys.exit(result.returncode)
|
|
205
|
+
load_dotenv()
|
|
206
|
+
python_bin = runtime_python()
|
|
207
|
+
result = subprocess.run([python_bin, str(CLI_PY)] + sys.argv[1:])
|
|
208
|
+
sys.exit(result.returncode)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
if __name__ == "__main__":
|
|
212
|
+
main()
|