abelworkflow 0.9.2 → 1.0.0
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/README.md +54 -182
- package/bin/abelworkflow.mjs +5 -3
- package/extensions/pi-gpt-responses-compat/index.ts +1 -1
- package/lib/cli/args.mjs +76 -0
- package/lib/cli/main.mjs +385 -0
- package/lib/cli/prompts.mjs +106 -0
- package/lib/config/dotenv.mjs +102 -0
- package/lib/config/jsonc.mjs +80 -0
- package/lib/config/store.mjs +310 -0
- package/lib/config/toml.mjs +638 -0
- package/lib/installer/assets.mjs +324 -0
- package/lib/installer/install.mjs +153 -0
- package/lib/installer/links.mjs +427 -0
- package/lib/installer/state.mjs +163 -0
- package/lib/paths.mjs +99 -0
- package/lib/providers/claude.mjs +197 -0
- package/lib/providers/codex.mjs +433 -0
- package/lib/providers/pi.mjs +577 -0
- package/lib/providers/skills.mjs +105 -0
- package/lib/templates/codex/agents/default.toml +7 -0
- package/lib/templates/codex/agents/explorer.toml +7 -0
- package/lib/templates/codex/agents/planner.toml +7 -0
- package/lib/templates/codex/agents/reviewer.toml +7 -0
- package/lib/templates/codex/agents/worker.toml +7 -0
- package/lib/templates/codex/config-base.toml +11 -3
- package/lib/templates/workflow/AGENTS.md +50 -0
- package/lib/templates/workflow/commands/abel-design.md +175 -0
- package/{commands → lib/templates/workflow/commands}/abel-diagnose.md +5 -5
- package/lib/templates/workflow/commands/abel-implement.md +170 -0
- package/{commands → lib/templates/workflow/commands}/abel-init.md +3 -5
- package/{.gitignore → lib/templates/workflow/gitignore.template} +0 -2
- package/lib/tools/cli-installer.mjs +277 -0
- package/package.json +37 -10
- package/skills/context7-auto-research/SKILL.md +5 -5
- package/skills/context7-auto-research/{context7-api.js → context7-api.cjs} +5 -8
- package/skills/dev-browser/SKILL.md +53 -33
- package/skills/dev-browser/dist/scripts/start.d.ts +2 -0
- package/skills/dev-browser/dist/scripts/start.d.ts.map +1 -0
- package/skills/dev-browser/dist/scripts/start.js +118 -0
- package/skills/dev-browser/dist/scripts/start.js.map +1 -0
- package/skills/dev-browser/dist/src/client.d.ts +93 -0
- package/skills/dev-browser/dist/src/client.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/client.js +310 -0
- package/skills/dev-browser/dist/src/client.js.map +1 -0
- package/skills/dev-browser/dist/src/entrypoint.d.ts +29 -0
- package/skills/dev-browser/dist/src/entrypoint.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/entrypoint.js +106 -0
- package/skills/dev-browser/dist/src/entrypoint.js.map +1 -0
- package/skills/dev-browser/dist/src/index.d.ts +4 -0
- package/skills/dev-browser/dist/src/index.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/index.js +2 -0
- package/skills/dev-browser/dist/src/index.js.map +1 -0
- package/skills/dev-browser/dist/src/page-api.d.ts +25 -0
- package/skills/dev-browser/dist/src/page-api.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/page-api.js +104 -0
- package/skills/dev-browser/dist/src/page-api.js.map +1 -0
- package/skills/dev-browser/dist/src/relay.d.ts +27 -0
- package/skills/dev-browser/dist/src/relay.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/relay.js +521 -0
- package/skills/dev-browser/dist/src/relay.js.map +1 -0
- package/skills/dev-browser/dist/src/runtime.d.ts +45 -0
- package/skills/dev-browser/dist/src/runtime.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/runtime.js +54 -0
- package/skills/dev-browser/dist/src/runtime.js.map +1 -0
- package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts +23 -0
- package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts.map +1 -0
- package/skills/dev-browser/{src/snapshot/browser-script.ts → dist/src/snapshot/browser-script.js} +21 -30
- package/skills/dev-browser/dist/src/snapshot/browser-script.js.map +1 -0
- package/skills/dev-browser/dist/src/snapshot/index.d.ts +14 -0
- package/skills/dev-browser/dist/src/snapshot/index.d.ts.map +1 -0
- package/skills/dev-browser/{src/snapshot/index.ts → dist/src/snapshot/index.js} +2 -2
- package/skills/dev-browser/dist/src/snapshot/index.js.map +1 -0
- package/skills/dev-browser/dist/src/snapshot/inject.d.ts +13 -0
- package/skills/dev-browser/dist/src/snapshot/inject.d.ts.map +1 -0
- package/skills/dev-browser/{src/snapshot/inject.ts → dist/src/snapshot/inject.js} +2 -2
- package/skills/dev-browser/dist/src/snapshot/inject.js.map +1 -0
- package/skills/dev-browser/dist/src/standalone.d.ts +32 -0
- package/skills/dev-browser/dist/src/standalone.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/standalone.js +174 -0
- package/skills/dev-browser/dist/src/standalone.js.map +1 -0
- package/skills/dev-browser/dist/src/startup.d.ts +55 -0
- package/skills/dev-browser/dist/src/startup.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/startup.js +81 -0
- package/skills/dev-browser/dist/src/startup.js.map +1 -0
- package/skills/dev-browser/dist/src/target-registry.d.ts +29 -0
- package/skills/dev-browser/dist/src/target-registry.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/target-registry.js +135 -0
- package/skills/dev-browser/dist/src/target-registry.js.map +1 -0
- package/skills/dev-browser/dist/src/types.d.ts +27 -0
- package/skills/dev-browser/dist/src/types.d.ts.map +1 -0
- package/skills/dev-browser/dist/src/types.js +2 -0
- package/skills/dev-browser/dist/src/types.js.map +1 -0
- package/skills/dev-browser/package-lock.json +67 -1510
- package/skills/dev-browser/package.json +18 -14
- package/skills/dev-browser/references/scraping.md +94 -105
- package/skills/grok-search/.env.example +3 -3
- package/skills/grok-search/SKILL.md +1 -1
- package/skills/grok-search/defaults.json +3 -0
- package/skills/grok-search/gitignore.template +4 -0
- package/skills/grok-search/scripts/_dotenv.py +5 -1
- package/skills/grok-search/scripts/groksearch_cli.py +15 -33
- package/skills/prompt-enhancer/SKILL.md +2 -27
- package/skills/prompt-enhancer/TEMPLATE.md +0 -4
- package/.skill-lock.json +0 -29
- package/AGENTS.md +0 -45
- package/commands/abel-implement.md +0 -157
- package/commands/abel-plan.md +0 -88
- package/commands/abel-research.md +0 -126
- package/lib/cli/logic.mjs +0 -213
- package/lib/cli.mjs +0 -3016
- package/skills/confidence-check/SKILL.md +0 -34
- package/skills/confidence-check/confidence.ts +0 -276
- package/skills/dev-browser/bun.lock +0 -460
- package/skills/dev-browser/scripts/start.ts +0 -280
- package/skills/dev-browser/src/client.ts +0 -474
- package/skills/dev-browser/src/entrypoint.ts +0 -157
- package/skills/dev-browser/src/index.ts +0 -289
- package/skills/dev-browser/src/relay.ts +0 -731
- package/skills/dev-browser/src/runtime.test.ts +0 -60
- package/skills/dev-browser/src/runtime.ts +0 -171
- package/skills/dev-browser/src/startup.test.ts +0 -95
- package/skills/dev-browser/src/startup.ts +0 -153
- package/skills/dev-browser/src/types.ts +0 -35
- package/skills/dev-browser/tsconfig.json +0 -36
- package/skills/dev-browser/vitest.config.ts +0 -12
- package/skills/prompt-enhancer/.env.example +0 -12
- package/skills/prompt-enhancer/ADVANCED.md +0 -103
- package/skills/prompt-enhancer/requirements.txt +0 -2
- package/skills/prompt-enhancer/scripts/_dotenv.py +0 -28
- package/skills/prompt-enhancer/scripts/enhance.py +0 -191
- package/skills/prompt-enhancer/scripts/prompt_enhancer_entry.py +0 -253
- package/skills/sequential-think/SKILL.md +0 -198
- package/skills/sequential-think/scripts/.env.example +0 -5
- package/skills/sequential-think/scripts/sequential_think_cli.py +0 -253
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""Shared .env loader for Prompt Enhancer scripts."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def load_dotenv() -> bool:
|
|
8
|
-
env_path = Path(__file__).resolve().parent.parent / ".env"
|
|
9
|
-
if not env_path.exists():
|
|
10
|
-
return False
|
|
11
|
-
try:
|
|
12
|
-
with open(env_path, "r", encoding="utf-8") as f:
|
|
13
|
-
for line in f:
|
|
14
|
-
line = line.strip()
|
|
15
|
-
if not line or line.startswith("#") or "=" not in line:
|
|
16
|
-
continue
|
|
17
|
-
key, _, value = line.partition("=")
|
|
18
|
-
key = key.strip()
|
|
19
|
-
value = value.strip()
|
|
20
|
-
if (value.startswith('"') and value.endswith('"')) or (
|
|
21
|
-
value.startswith("'") and value.endswith("'")
|
|
22
|
-
):
|
|
23
|
-
value = value[1:-1]
|
|
24
|
-
if key and not os.environ.get(key):
|
|
25
|
-
os.environ[key] = value
|
|
26
|
-
return True
|
|
27
|
-
except IOError:
|
|
28
|
-
return False
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Prompt Enhancer CLI for OpenAI-compatible endpoints."""
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
import os
|
|
6
|
-
import sys
|
|
7
|
-
from typing import Tuple
|
|
8
|
-
|
|
9
|
-
from _dotenv import load_dotenv
|
|
10
|
-
|
|
11
|
-
load_dotenv()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
SYSTEM_PROMPT = """
|
|
15
|
-
You are an expert Prompt Engineer for Coding Agents (Claude Code, Codex, Gemini CLI).
|
|
16
|
-
Your goal is to rewrite the user's raw input into a structured, high-context prompt that maximizes the agent's effectiveness.
|
|
17
|
-
|
|
18
|
-
Guidelines:
|
|
19
|
-
1. Structure: Use a clear Markdown structure with headers.
|
|
20
|
-
2. Chain of Thought: Explicitly ask the agent to "Think step-by-step" or "Analyze the file structure first".
|
|
21
|
-
3. Context: If the user's prompt is vague, add placeholders like "[Insert relevant file(s)]" or "[Specify tech stack]" in the rewritten prompt, or simply infer them if obvious.
|
|
22
|
-
4. Format:
|
|
23
|
-
- Context: What is the current state? What files are involved?
|
|
24
|
-
- Objective: What exactly should be done?
|
|
25
|
-
- Constraints: specific libraries, coding styles, or "no placeholders".
|
|
26
|
-
- Response Format: e.g., "Return only the code block" or "Explain step-by-step".
|
|
27
|
-
|
|
28
|
-
Output Template:
|
|
29
|
-
|
|
30
|
-
# Context
|
|
31
|
-
[Refined context description]
|
|
32
|
-
|
|
33
|
-
# Objective
|
|
34
|
-
[Precise task definition]
|
|
35
|
-
|
|
36
|
-
# Step-by-Step Instructions
|
|
37
|
-
1. [Step 1]
|
|
38
|
-
2. [Step 2]
|
|
39
|
-
...
|
|
40
|
-
|
|
41
|
-
# Constraints
|
|
42
|
-
- [Constraint 1]
|
|
43
|
-
- [Constraint 2]
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def parse_args() -> argparse.Namespace:
|
|
48
|
-
parser = argparse.ArgumentParser(
|
|
49
|
-
prog="prompt_enhancer_entry.py",
|
|
50
|
-
description="Enhance a prompt through a third-party OpenAI-compatible API.",
|
|
51
|
-
)
|
|
52
|
-
parser.add_argument("--url", dest="api_url", help="Third-party OpenAI-compatible base URL.")
|
|
53
|
-
parser.add_argument("--api-key", dest="api_key", help="Third-party OpenAI-compatible API key.")
|
|
54
|
-
parser.add_argument("--model", help="Model name on the third-party endpoint.")
|
|
55
|
-
parser.add_argument("--prompt", help="Prompt text to enhance.")
|
|
56
|
-
parser.add_argument("prompt_parts", nargs="*", help=argparse.SUPPRESS)
|
|
57
|
-
return parser.parse_args()
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def debug_enabled() -> bool:
|
|
61
|
-
value = os.environ.get("PE_DEBUG", "")
|
|
62
|
-
return value.strip().lower() in {"1", "true", "yes", "on"}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def resolve_prompt(args: argparse.Namespace) -> str:
|
|
66
|
-
prompt = args.prompt.strip() if args.prompt else ""
|
|
67
|
-
if prompt:
|
|
68
|
-
return prompt
|
|
69
|
-
joined = " ".join(args.prompt_parts).strip()
|
|
70
|
-
if joined:
|
|
71
|
-
return joined
|
|
72
|
-
raise ValueError("Missing prompt. Pass --prompt \"...\" or a positional prompt.")
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def first_non_empty(*values: str) -> str:
|
|
76
|
-
for value in values:
|
|
77
|
-
stripped = value.strip()
|
|
78
|
-
if stripped:
|
|
79
|
-
return stripped
|
|
80
|
-
return ""
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def env_value(*names: str) -> str:
|
|
84
|
-
return first_non_empty(*(os.environ.get(name, "") for name in names))
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def resolve_config(args: argparse.Namespace) -> Tuple[str, str, str, str]:
|
|
88
|
-
api_url = (args.api_url or os.environ.get("PE_API_URL", "")).strip()
|
|
89
|
-
api_key = (args.api_key or os.environ.get("PE_API_KEY", "")).strip()
|
|
90
|
-
model = (args.model or os.environ.get("PE_MODEL", "")).strip()
|
|
91
|
-
|
|
92
|
-
missing = []
|
|
93
|
-
if not api_url:
|
|
94
|
-
missing.append("url")
|
|
95
|
-
if not api_key:
|
|
96
|
-
missing.append("apiKey")
|
|
97
|
-
if not model:
|
|
98
|
-
missing.append("model")
|
|
99
|
-
if missing:
|
|
100
|
-
has_openai_compatible_transport = bool(api_url or api_key)
|
|
101
|
-
if has_openai_compatible_transport:
|
|
102
|
-
raise ValueError(
|
|
103
|
-
"Missing third-party OpenAI-compatible config: "
|
|
104
|
-
+ ", ".join(missing)
|
|
105
|
-
+ ". If these fields are unavailable, use the current agent directly."
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
legacy_anthropic_key = env_value("ANTHROPIC_API_KEY")
|
|
109
|
-
if legacy_anthropic_key:
|
|
110
|
-
return "anthropic", "", legacy_anthropic_key, first_non_empty(model, "claude-sonnet-4-20250514")
|
|
111
|
-
|
|
112
|
-
legacy_openai_key = env_value("OPENAI_API_KEY")
|
|
113
|
-
if legacy_openai_key:
|
|
114
|
-
return "openai", "", legacy_openai_key, first_non_empty(model, "gpt-4o")
|
|
115
|
-
|
|
116
|
-
raise ValueError(
|
|
117
|
-
"Missing third-party OpenAI-compatible config: "
|
|
118
|
-
+ ", ".join(missing)
|
|
119
|
-
+ ". If these fields are unavailable, use the current agent directly."
|
|
120
|
-
)
|
|
121
|
-
return "openai-compatible", api_url, api_key, model
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def enhance_with_anthropic(prompt: str, api_key: str, model: str) -> str:
|
|
125
|
-
try:
|
|
126
|
-
import anthropic
|
|
127
|
-
except ImportError:
|
|
128
|
-
raise RuntimeError("Missing dependency: anthropic. Install dependencies for the configured provider.") from None
|
|
129
|
-
|
|
130
|
-
client = anthropic.Anthropic(api_key=api_key)
|
|
131
|
-
message = client.messages.create(
|
|
132
|
-
model=model,
|
|
133
|
-
max_tokens=2048,
|
|
134
|
-
system=SYSTEM_PROMPT,
|
|
135
|
-
messages=[{"role": "user", "content": prompt}],
|
|
136
|
-
)
|
|
137
|
-
return message.content[0].text
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def _extract_response_text(response) -> str:
|
|
141
|
-
content = response.choices[0].message.content
|
|
142
|
-
if isinstance(content, str):
|
|
143
|
-
return content
|
|
144
|
-
if content is None:
|
|
145
|
-
raise RuntimeError("The provider returned an empty response.")
|
|
146
|
-
return str(content)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
def enhance_with_openai(prompt: str, api_key: str, model: str, api_url: str = "") -> str:
|
|
150
|
-
try:
|
|
151
|
-
from openai import OpenAI
|
|
152
|
-
except ImportError:
|
|
153
|
-
raise RuntimeError("Missing dependency: openai. Install dependencies for the configured provider.") from None
|
|
154
|
-
|
|
155
|
-
kwargs = {"api_key": api_key}
|
|
156
|
-
if api_url:
|
|
157
|
-
kwargs["base_url"] = api_url
|
|
158
|
-
client = OpenAI(**kwargs)
|
|
159
|
-
response = client.chat.completions.create(
|
|
160
|
-
model=model,
|
|
161
|
-
messages=[
|
|
162
|
-
{"role": "system", "content": SYSTEM_PROMPT},
|
|
163
|
-
{"role": "user", "content": prompt},
|
|
164
|
-
],
|
|
165
|
-
)
|
|
166
|
-
return _extract_response_text(response)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def main() -> None:
|
|
170
|
-
try:
|
|
171
|
-
args = parse_args()
|
|
172
|
-
prompt = resolve_prompt(args)
|
|
173
|
-
provider, api_url, api_key, model = resolve_config(args)
|
|
174
|
-
if provider == "anthropic":
|
|
175
|
-
print(enhance_with_anthropic(prompt, api_key, model))
|
|
176
|
-
else:
|
|
177
|
-
print(enhance_with_openai(prompt, api_key, model, api_url))
|
|
178
|
-
except Exception as exc:
|
|
179
|
-
if debug_enabled():
|
|
180
|
-
print(f"Error: {exc}", file=sys.stderr)
|
|
181
|
-
else:
|
|
182
|
-
msg = str(exc)
|
|
183
|
-
if "Missing third-party OpenAI-compatible config" in msg:
|
|
184
|
-
print("Missing API configuration. Use the current agent directly instead, or set PE_API_URL, PE_API_KEY, PE_MODEL.", file=sys.stderr)
|
|
185
|
-
else:
|
|
186
|
-
print(msg, file=sys.stderr)
|
|
187
|
-
sys.exit(1)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if __name__ == "__main__":
|
|
191
|
-
main()
|
|
@@ -1,253 +0,0 @@
|
|
|
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 first_non_empty(*values: str) -> str:
|
|
95
|
-
for value in values:
|
|
96
|
-
stripped = value.strip()
|
|
97
|
-
if stripped:
|
|
98
|
-
return stripped
|
|
99
|
-
return ""
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def env_value(*names: str) -> str:
|
|
103
|
-
return first_non_empty(*(os.environ.get(name, "") for name in names))
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def argv_value(flag: str, argv: Optional[List[str]] = None) -> str:
|
|
107
|
-
argv = sys.argv[1:] if argv is None else argv
|
|
108
|
-
for index, token in enumerate(argv):
|
|
109
|
-
if token == flag:
|
|
110
|
-
if index + 1 < len(argv):
|
|
111
|
-
return argv[index + 1].strip()
|
|
112
|
-
return ""
|
|
113
|
-
if token.startswith(f"{flag}="):
|
|
114
|
-
return token.split("=", 1)[1].strip()
|
|
115
|
-
return ""
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def resolved_provider(argv: Optional[List[str]] = None) -> Optional[str]:
|
|
119
|
-
argv = sys.argv[1:] if argv is None else argv
|
|
120
|
-
api_url = first_non_empty(argv_value("--url", argv), os.environ.get("PE_API_URL", ""))
|
|
121
|
-
api_key = first_non_empty(argv_value("--api-key", argv), os.environ.get("PE_API_KEY", ""))
|
|
122
|
-
model = first_non_empty(argv_value("--model", argv), os.environ.get("PE_MODEL", ""))
|
|
123
|
-
|
|
124
|
-
if api_url and api_key and model:
|
|
125
|
-
return "openai"
|
|
126
|
-
if api_url or api_key:
|
|
127
|
-
return None
|
|
128
|
-
if env_value("ANTHROPIC_API_KEY"):
|
|
129
|
-
return "anthropic"
|
|
130
|
-
if env_value("OPENAI_API_KEY"):
|
|
131
|
-
return "openai"
|
|
132
|
-
return None
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def required_modules() -> List[str]:
|
|
136
|
-
provider = resolved_provider()
|
|
137
|
-
if provider == "anthropic":
|
|
138
|
-
return ["anthropic"]
|
|
139
|
-
if provider == "openai":
|
|
140
|
-
return ["openai"]
|
|
141
|
-
return []
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def install_targets(modules: List[str]) -> List[str]:
|
|
145
|
-
if not REQ_FILE.is_file():
|
|
146
|
-
return modules
|
|
147
|
-
|
|
148
|
-
requirements = {}
|
|
149
|
-
for raw_line in REQ_FILE.read_text(encoding="utf-8").splitlines():
|
|
150
|
-
line = raw_line.split("#", 1)[0].strip()
|
|
151
|
-
if not line:
|
|
152
|
-
continue
|
|
153
|
-
package = re.split(r"[<>=!~\\[; ]", line, maxsplit=1)[0].strip().lower()
|
|
154
|
-
if package:
|
|
155
|
-
requirements[package] = line
|
|
156
|
-
|
|
157
|
-
return [requirements.get(module.lower(), module) for module in modules]
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def has_required_modules(python_bin: str, modules: List[str]) -> bool:
|
|
161
|
-
if not modules:
|
|
162
|
-
return True
|
|
163
|
-
check = subprocess.run(
|
|
164
|
-
[python_bin, "-c", "; ".join(f"import {module}" for module in modules)],
|
|
165
|
-
stdout=subprocess.DEVNULL,
|
|
166
|
-
stderr=subprocess.DEVNULL,
|
|
167
|
-
)
|
|
168
|
-
return check.returncode == 0
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def install_deps(python_bin: Path, modules: Optional[List[str]] = None) -> None:
|
|
172
|
-
modules = required_modules() if modules is None else modules
|
|
173
|
-
if not modules:
|
|
174
|
-
return
|
|
175
|
-
targets = install_targets(modules)
|
|
176
|
-
if has_required_modules(str(python_bin), modules):
|
|
177
|
-
return
|
|
178
|
-
try:
|
|
179
|
-
kwargs = {
|
|
180
|
-
"check": True,
|
|
181
|
-
"stdout": subprocess.DEVNULL,
|
|
182
|
-
"stderr": subprocess.PIPE,
|
|
183
|
-
"text": True,
|
|
184
|
-
}
|
|
185
|
-
if has_uv():
|
|
186
|
-
subprocess.run(["uv", "pip", "install", "--python", str(python_bin), *targets], **kwargs)
|
|
187
|
-
return
|
|
188
|
-
subprocess.run([str(python_bin), "-m", "pip", "install", *targets], **kwargs)
|
|
189
|
-
except subprocess.CalledProcessError as exc:
|
|
190
|
-
if debug_enabled():
|
|
191
|
-
details = (exc.stderr or "").strip()
|
|
192
|
-
if details:
|
|
193
|
-
print(details, file=sys.stderr)
|
|
194
|
-
print(
|
|
195
|
-
"Warning: Failed to install prompt enhancer dependencies; continuing with existing environment.",
|
|
196
|
-
file=sys.stderr,
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def validate_venv_dir() -> None:
|
|
201
|
-
dir_path = venv_dir()
|
|
202
|
-
if dir_path.exists() and not dir_path.is_dir():
|
|
203
|
-
print(f"Error: {dir_path} exists but is not a directory.", file=sys.stderr)
|
|
204
|
-
sys.exit(1)
|
|
205
|
-
if dir_path.is_dir() and not (dir_path / "pyvenv.cfg").exists() and venv_python() is None:
|
|
206
|
-
print(f"Error: {dir_path} exists but is not a valid venv.", file=sys.stderr)
|
|
207
|
-
sys.exit(1)
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
def should_passthrough_cli() -> bool:
|
|
211
|
-
return len(sys.argv) < 2
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def passthrough_python() -> Optional[str]:
|
|
215
|
-
if sys.executable and Path(sys.executable).is_file():
|
|
216
|
-
return sys.executable
|
|
217
|
-
return find_system_python()
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
def runtime_python() -> str:
|
|
221
|
-
modules = required_modules()
|
|
222
|
-
current_python = passthrough_python()
|
|
223
|
-
if current_python and has_required_modules(current_python, modules):
|
|
224
|
-
return current_python
|
|
225
|
-
|
|
226
|
-
validate_venv_dir()
|
|
227
|
-
python_bin = venv_python()
|
|
228
|
-
if python_bin is None:
|
|
229
|
-
create_venv()
|
|
230
|
-
python_bin = venv_python()
|
|
231
|
-
if python_bin is None:
|
|
232
|
-
print("Error: Failed to locate python in venv after creation.", file=sys.stderr)
|
|
233
|
-
sys.exit(1)
|
|
234
|
-
install_deps(python_bin, modules)
|
|
235
|
-
return str(python_bin)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def main() -> None:
|
|
239
|
-
if should_passthrough_cli():
|
|
240
|
-
python_bin = passthrough_python()
|
|
241
|
-
if not python_bin:
|
|
242
|
-
print("Error: No usable python found for CLI usage output.", file=sys.stderr)
|
|
243
|
-
sys.exit(1)
|
|
244
|
-
result = subprocess.run([python_bin, str(CLI_PY)] + sys.argv[1:])
|
|
245
|
-
sys.exit(result.returncode)
|
|
246
|
-
load_dotenv()
|
|
247
|
-
python_bin = runtime_python()
|
|
248
|
-
result = subprocess.run([python_bin, str(CLI_PY)] + sys.argv[1:])
|
|
249
|
-
sys.exit(result.returncode)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if __name__ == "__main__":
|
|
253
|
-
main()
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sequential-think
|
|
3
|
-
description: |
|
|
4
|
-
Multi-step reasoning engine for complex analysis and systematic problem solving. Use when: (1) Complex debugging scenarios with multiple layers, (2) Architectural analysis and system design, (3) Problems requiring hypothesis testing and validation, (4) Multi-component failure investigation, (5) Performance bottleneck identification. Triggers: "--think", "--think-hard", "--ultrathink", "analyze step by step", "break down this problem", "systematic analysis". IMPORTANT: Do NOT use for simple single-step tasks.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Sequential Think
|
|
8
|
-
|
|
9
|
-
Structured iterative thinking for complex problem-solving. Supports both MCP server and standalone CLI.
|
|
10
|
-
|
|
11
|
-
## Execution Methods
|
|
12
|
-
|
|
13
|
-
### Method 1: MCP Tools (if available)
|
|
14
|
-
Use `mcp__sequential-thinking__sequentialthinking` tool directly.
|
|
15
|
-
|
|
16
|
-
### Method 2: CLI Script (no MCP dependency)
|
|
17
|
-
Run `scripts/sequential_think_cli.py` via Bash:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
# Process a thought
|
|
21
|
-
python scripts/sequential_think_cli.py think \
|
|
22
|
-
--thought "First, let me analyze the problem structure..." \
|
|
23
|
-
--thought-number 1 \
|
|
24
|
-
--total-thoughts 5
|
|
25
|
-
|
|
26
|
-
# Continue thinking chain
|
|
27
|
-
python scripts/sequential_think_cli.py think \
|
|
28
|
-
--thought "Based on step 1, I hypothesize that..." \
|
|
29
|
-
--thought-number 2 \
|
|
30
|
-
--total-thoughts 5
|
|
31
|
-
|
|
32
|
-
# Revise a previous thought
|
|
33
|
-
python scripts/sequential_think_cli.py think \
|
|
34
|
-
--thought "Reconsidering step 1, I realize..." \
|
|
35
|
-
--thought-number 3 \
|
|
36
|
-
--total-thoughts 5 \
|
|
37
|
-
--is-revision \
|
|
38
|
-
--revises-thought 1
|
|
39
|
-
|
|
40
|
-
# Branch into alternative path
|
|
41
|
-
python scripts/sequential_think_cli.py think \
|
|
42
|
-
--thought "Alternative approach: what if we..." \
|
|
43
|
-
--thought-number 4 \
|
|
44
|
-
--total-thoughts 6 \
|
|
45
|
-
--branch-from 2 \
|
|
46
|
-
--branch-id "alt-approach"
|
|
47
|
-
|
|
48
|
-
# Final thought (complete chain)
|
|
49
|
-
python scripts/sequential_think_cli.py think \
|
|
50
|
-
--thought "Conclusion: the solution is..." \
|
|
51
|
-
--thought-number 5 \
|
|
52
|
-
--total-thoughts 5 \
|
|
53
|
-
--no-next
|
|
54
|
-
|
|
55
|
-
# View thought history
|
|
56
|
-
python scripts/sequential_think_cli.py history [--format json|text]
|
|
57
|
-
|
|
58
|
-
# Clear thought history
|
|
59
|
-
python scripts/sequential_think_cli.py clear
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Core Principles
|
|
63
|
-
|
|
64
|
-
### Iterative Thinking Process
|
|
65
|
-
- Each tool call = one "thought" in the chain
|
|
66
|
-
- Build upon, question, or revise previous thoughts
|
|
67
|
-
- Express uncertainty when it exists
|
|
68
|
-
|
|
69
|
-
### Dynamic Thought Count
|
|
70
|
-
- Start with initial estimate of `totalThoughts`
|
|
71
|
-
- Adjust up/down as understanding evolves
|
|
72
|
-
- Add more thoughts even after reaching initial end
|
|
73
|
-
|
|
74
|
-
### Hypothesis-Driven Approach
|
|
75
|
-
1. Generate hypotheses as potential solutions emerge
|
|
76
|
-
2. Verify hypotheses based on chain-of-thought steps
|
|
77
|
-
3. Repeat until satisfied with solution
|
|
78
|
-
|
|
79
|
-
### Completion Criteria
|
|
80
|
-
- Only set `nextThoughtNeeded: false` when truly finished
|
|
81
|
-
- Must have satisfactory, verified answer
|
|
82
|
-
- Don't rush to conclusion
|
|
83
|
-
|
|
84
|
-
## When to Use
|
|
85
|
-
|
|
86
|
-
| Scenario | Use Sequential Think |
|
|
87
|
-
|----------|---------------------|
|
|
88
|
-
| Complex debugging (3+ layers) | ✅ Yes |
|
|
89
|
-
| Architectural analysis | ✅ Yes |
|
|
90
|
-
| Multi-component investigation | ✅ Yes |
|
|
91
|
-
| Performance bottleneck analysis | ✅ Yes |
|
|
92
|
-
| Root cause analysis | ✅ Yes |
|
|
93
|
-
| Simple explanation | ❌ No |
|
|
94
|
-
| Single-file change | ❌ No |
|
|
95
|
-
| Straightforward fix | ❌ No |
|
|
96
|
-
|
|
97
|
-
## Parameters
|
|
98
|
-
|
|
99
|
-
| Parameter | Type | Required | Description |
|
|
100
|
-
|-----------|------|----------|-------------|
|
|
101
|
-
| `thought` | string | Yes | Current thinking step content |
|
|
102
|
-
| `thoughtNumber` | int | Yes | Current position in sequence (1-based) |
|
|
103
|
-
| `totalThoughts` | int | Yes | Estimated total thoughts needed |
|
|
104
|
-
| `nextThoughtNeeded` | bool | No | Whether more thinking needed (default: true) |
|
|
105
|
-
| `isRevision` | bool | No | Whether this revises previous thinking |
|
|
106
|
-
| `revisesThought` | int | No | Which thought number is being reconsidered |
|
|
107
|
-
| `branchFromThought` | int | No | Branching point thought number |
|
|
108
|
-
| `branchId` | string | No | Identifier for current branch |
|
|
109
|
-
| `needsMoreThoughts` | bool | No | Signal that more thoughts needed beyond estimate |
|
|
110
|
-
|
|
111
|
-
## Output Format
|
|
112
|
-
|
|
113
|
-
```json
|
|
114
|
-
{
|
|
115
|
-
"thoughtNumber": 3,
|
|
116
|
-
"totalThoughts": 5,
|
|
117
|
-
"nextThoughtNeeded": true,
|
|
118
|
-
"branches": ["alt-approach"],
|
|
119
|
-
"thoughtHistoryLength": 3
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## Workflow Pattern
|
|
124
|
-
|
|
125
|
-
### Phase 1: Problem Decomposition
|
|
126
|
-
```
|
|
127
|
-
Thought 1: Identify problem scope and constraints
|
|
128
|
-
Thought 2: Break into sub-problems
|
|
129
|
-
Thought 3: Identify dependencies between sub-problems
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Phase 2: Hypothesis Generation
|
|
133
|
-
```
|
|
134
|
-
Thought 4: Generate initial hypothesis
|
|
135
|
-
Thought 5: Identify evidence needed to verify
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Phase 3: Verification & Iteration
|
|
139
|
-
```
|
|
140
|
-
Thought 6: Test hypothesis against evidence
|
|
141
|
-
Thought 7: Revise if needed (isRevision=true)
|
|
142
|
-
Thought 8: Branch if alternative path promising
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Phase 4: Conclusion
|
|
146
|
-
```
|
|
147
|
-
Final Thought: Synthesize findings, provide answer (nextThoughtNeeded=false)
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Best Practices
|
|
151
|
-
|
|
152
|
-
1. **Start with estimate, adjust as needed**
|
|
153
|
-
- Initial `totalThoughts` is just a guess
|
|
154
|
-
- Increase if problem more complex than expected
|
|
155
|
-
- Decrease if solution found early
|
|
156
|
-
|
|
157
|
-
2. **Use revisions for course correction**
|
|
158
|
-
- Mark `isRevision=true` when reconsidering
|
|
159
|
-
- Reference `revisesThought` for clarity
|
|
160
|
-
|
|
161
|
-
3. **Branch for alternative approaches**
|
|
162
|
-
- Use `branchFromThought` to explore alternatives
|
|
163
|
-
- Give meaningful `branchId` names
|
|
164
|
-
|
|
165
|
-
4. **Filter irrelevant information**
|
|
166
|
-
- Each thought should advance toward solution
|
|
167
|
-
- Ignore tangential details
|
|
168
|
-
|
|
169
|
-
5. **Don't rush completion**
|
|
170
|
-
- Only `nextThoughtNeeded=false` when truly done
|
|
171
|
-
- Verify hypothesis before concluding
|
|
172
|
-
|
|
173
|
-
## Anti-Patterns
|
|
174
|
-
|
|
175
|
-
| Prohibited | Correct |
|
|
176
|
-
|------------|---------|
|
|
177
|
-
| Use for simple tasks | Reserve for complex multi-step problems |
|
|
178
|
-
| Skip thought numbers | Always increment correctly |
|
|
179
|
-
| Conclude without verification | Verify hypothesis before final thought |
|
|
180
|
-
| Ignore previous thoughts | Build upon or explicitly revise |
|
|
181
|
-
| Fixed totalThoughts | Adjust as understanding evolves |
|
|
182
|
-
|
|
183
|
-
## Integration with Other Tools
|
|
184
|
-
|
|
185
|
-
### With augment-context-engine
|
|
186
|
-
```
|
|
187
|
-
augment-context-engine → align current state → Sequential Think → analyze and plan
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### With Context7
|
|
191
|
-
```
|
|
192
|
-
Sequential Think → coordinate analysis → Context7 → provide official patterns
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### With Serena
|
|
196
|
-
```
|
|
197
|
-
Serena → symbol-level exploration → Sequential Think → systematic analysis
|
|
198
|
-
```
|