Build [v1.9.19]

This commit is contained in:
Daniel Bedeleanu
2026-04-14 20:44:01 +03:00
parent fcb187974e
commit 00ee4cf9c5
38 changed files with 2059 additions and 157 deletions

View File

@@ -0,0 +1,48 @@
---
name: superpowers-workflow
description: Enforces a disciplined workflow for coding, debugging, refactoring, and automation: brainstorm -> plan -> implement with verification (prefer TDD) -> review -> finish. Use for almost any non-trivial change.
---
# Superpowers Workflow
This skill defines the default operating procedure for software and automation tasks.
## When to use this skill
Use whenever the user asks to:
- build or modify code
- debug an error or failing tests
- refactor or improve quality
- design an automation workflow (e.g., API integrations, ETL, pipelines)
- add tests, reliability, or safety checks
## Activation marker (required)
Immediately after reading this skill (before any other output), run:
python .agent/skills/superpowers-workflow/scripts/record_activation.py --skill superpowers-workflow
## Default workflow (mandatory unless explicitly unnecessary)
1. **Brainstorm (short)**: clarify goal, constraints, risks, and acceptance criteria.
2. **Write a plan**: small steps (210 minutes each) with files + verification.
3. **Implement**: make the smallest correct change; prefer tests-first when feasible.
4. **Review pass**: correctness, edge cases, security, style, maintainability.
5. **Finish**: run verification commands, summarize changes + next steps.
## Decision tree: how much process is needed?
- **Tiny change (1 file, obvious)**:
- Do a mini-brainstorm (3 bullets), then mini-plan (35 steps), then implement + verify.
- **Non-trivial change**:
- Full brainstorm + plan before editing.
- **High-risk change** (auth, money, prod data, security, migrations):
- Add explicit risk controls: rollback plan, dry-run, extra tests, logging, safe defaults.
## Output rules (how you communicate)
- Always state **assumptions** if anything is ambiguous.
- Always include **verification** (commands, tests, or observable checks).
- If you must ask questions, ask **at most 3**; then proceed with best assumptions.
## Stop conditions
Pause implementation and switch to planning if:
- requirements conflict
- critical unknowns block correctness
- the change could cause data loss or security issues without safeguards

View File

@@ -0,0 +1,34 @@
from __future__ import annotations
import argparse
from datetime import datetime, timezone
from pathlib import Path
def find_repo_root(start: Path) -> Path:
# Walk upwards until we find a marker that suggests repo root
for p in [start, *start.parents]:
if (p / ".agent").exists() or (p / ".git").exists() or (p / "pyproject.toml").exists():
return p
return start
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--skill", required=True)
parser.add_argument("--run-id", default="")
args = parser.parse_args()
repo_root = find_repo_root(Path.cwd())
log_path = repo_root / "e2e_demo" / "skill-activation.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
ts = datetime.now(timezone.utc).isoformat()
line = f"{ts}\tskill={args.skill}\trun_id={args.run_id}\n"
log_path.write_text((log_path.read_text() if log_path.exists() else "") + line, encoding="utf-8")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,245 @@
#!/usr/bin/env python3
"""Spawn an isolated Gemini CLI subagent for focused task execution.
This enables parallel execution by launching independent gemini instances
with isolated context and specific skill instructions.
"""
import argparse
import json
import subprocess
import sys
import time
import uuid
from pathlib import Path
from typing import Any
def find_repo_root(start: Path) -> Path:
"""Traverse upwards to find the repository root (containing .agent/)."""
curr = start.resolve()
for _ in range(10):
if (curr / ".agent").exists():
return curr
if curr.parent == curr:
break
curr = curr.parent
return Path.cwd()
def load_skill_instructions(skill_path: Path) -> str:
"""Load skill instructions from SKILL.md file."""
if not skill_path.exists():
return ""
return skill_path.read_text(encoding="utf-8")
def spawn_subagent(
skill: str,
task: str,
repo_root: Path,
yolo: bool = True,
output_format: str = "text",
) -> dict[str, Any]:
"""
Spawn a subagent with isolated context.
Args:
skill: Skill name (e.g., 'tdd', 'debug', 'review')
task: Task description for the subagent
repo_root: Repository root path
yolo: Auto-approve all actions (default: True for parallel execution)
output_format: Output format ('text' or 'json')
Returns:
dict with keys: success, output, error, log_file, duration_s
"""
# Generate unique subagent ID
subagent_id = uuid.uuid4().hex[:8]
timestamp = time.strftime("%Y%m%d-%H%M%S")
# Setup logging directory
log_dir = repo_root / "artifacts" / "superpowers" / "subagents"
log_dir.mkdir(parents=True, exist_ok=True)
log_file = log_dir / f"{skill}-{timestamp}-{subagent_id}.log"
# Load skill instructions
skill_file = repo_root / f".agent/skills/superpowers-{skill}/SKILL.md"
skill_instructions = load_skill_instructions(skill_file)
if not skill_instructions:
return {
"success": False,
"output": "",
"error": f"Skill not found: {skill_file}",
"log_file": str(log_file),
"duration_s": 0,
}
# Construct focused prompt
prompt = f"""You are a specialized subagent focused on: {skill}
IMPORTANT: You have ISOLATED CONTEXT. Do not assume knowledge from other conversations.
Task:
{task}
Skill Instructions:
{skill_instructions}
Requirements:
1. Follow the skill instructions exactly
2. Complete the task fully
3. Output ONLY the final result at the end
4. Do not include meta-commentary or thinking process in final output
5. Write any artifacts to artifacts/superpowers/subagent-{subagent_id}/
When complete, output:
---SUBAGENT-RESULT-START---
[Your final result here]
---SUBAGENT-RESULT-END---
"""
# Build command
cmd = ["gemini"]
if yolo:
cmd.append("--yolo")
# Execute subagent
start_time = time.time()
try:
with open(log_file, "w", encoding="utf-8") as log:
log.write("=== SUBAGENT EXECUTION LOG ===\n")
log.write(f"Skill: {skill}\n")
log.write(f"ID: {subagent_id}\n")
log.write(f"Timestamp: {timestamp}\n")
log.write(f"Task: {task}\n\n")
log.write("=== PROMPT ===\n")
log.write(prompt)
log.write("\n\n=== EXECUTION ===\n")
log.flush()
result = subprocess.run(
cmd,
input=prompt,
capture_output=True,
text=True,
cwd=repo_root,
timeout=600, # 10 minute timeout
shell=True, # Required on Windows for .ps1/.cmd scripts
)
duration_s = time.time() - start_time
log.write("\n=== STDOUT ===\n")
log.write(result.stdout)
log.write("\n=== STDERR ===\n")
log.write(result.stderr)
log.write(f"\n=== EXIT CODE: {result.returncode} ===\n")
log.write(f"=== DURATION: {duration_s:.2f}s ===\n")
# Extract final result from markers
output = result.stdout
if "---SUBAGENT-RESULT-START---" in output:
parts = output.split("---SUBAGENT-RESULT-START---", 1)
if len(parts) > 1:
result_part = parts[1].split("---SUBAGENT-RESULT-END---", 1)
output = result_part[0].strip()
return {
"success": result.returncode == 0,
"output": output,
"error": result.stderr if result.returncode != 0 else "",
"log_file": str(log_file),
"duration_s": duration_s,
"subagent_id": subagent_id,
}
except subprocess.TimeoutExpired:
duration_s = time.time() - start_time
return {
"success": False,
"output": "",
"error": f"Subagent timed out after {duration_s:.0f}s",
"log_file": str(log_file),
"duration_s": duration_s,
"subagent_id": subagent_id,
}
except Exception as e:
duration_s = time.time() - start_time
return {
"success": False,
"output": "",
"error": f"Subagent execution failed: {e}",
"log_file": str(log_file),
"duration_s": duration_s,
"subagent_id": subagent_id,
}
def main() -> int:
parser = argparse.ArgumentParser(
description="Spawn a Gemini CLI subagent for parallel execution"
)
parser.add_argument(
"--skill",
required=True,
help="Skill to use (tdd, debug, review, rest-automation, python-automation)",
)
parser.add_argument(
"--task",
required=True,
help="Task description for the subagent",
)
parser.add_argument(
"--no-yolo",
action="store_true",
help="Disable auto-approval (interactive mode)",
)
parser.add_argument(
"--output-format",
choices=["text", "json"],
default="text",
help="Output format",
)
args = parser.parse_args()
repo_root = find_repo_root(Path.cwd())
if args.output_format == "text":
print(f"🤖 Spawning subagent: {args.skill}")
print(f"📋 Task: {args.task[:80]}{'...' if len(args.task) > 80 else ''}")
result = spawn_subagent(
skill=args.skill,
task=args.task,
repo_root=repo_root,
yolo=not args.no_yolo,
output_format=args.output_format,
)
if args.output_format == "json":
print(json.dumps(result, indent=2))
return 0 if result["success"] else 1
# Text output
print(f"\n{'' if result['success'] else ''} Subagent completed in {result['duration_s']:.1f}s")
print(f"📝 Full log: {result['log_file']}")
if result["success"]:
print(f"\n{'='*60}")
print("RESULT:")
print(f"{'='*60}")
print(result["output"])
return 0
else:
print(f"\n{'='*60}")
print("ERROR:")
print(f"{'='*60}")
print(result["error"])
return 1
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,28 @@
from __future__ import annotations
import argparse
import sys
from pathlib import Path
def find_repo_root(start: Path) -> Path:
for p in [start, *start.parents]:
if (p / ".agent").exists() or (p / ".git").exists():
return p
return start
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--path", required=True, help="Repo-relative path to write, e.g. artifacts/superpowers/brainstorm.md")
args = parser.parse_args()
repo_root = find_repo_root(Path.cwd())
out_path = (repo_root / args.path).resolve()
out_path.parent.mkdir(parents=True, exist_ok=True)
content = sys.stdin.read()
out_path.write_text(content, encoding="utf-8")
print(str(out_path))
return 0
if __name__ == "__main__":
raise SystemExit(main())