105 lines
3.9 KiB
Python
Executable File
105 lines
3.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""workflow-init.py
|
|
Interactive initializer for the AI workflow repo.
|
|
- Replaces placeholders like ai-workflow-test, https://gitea.brrd.tech/rob/test-workflow, rob, 40 messages, main
|
|
- Honors default syntax default
|
|
- Optionally git init + first commit
|
|
Usage:
|
|
python3 workflow-init.py [--path .] [--no-git]
|
|
"""
|
|
import argparse, os, re, sys, subprocess
|
|
from pathlib import Path
|
|
|
|
PLACEHOLDER_PATTERN = re.compile(r"\{\{([^}|]+)(?:\|([^}]*))?\}\}")
|
|
TEXT_EXTS = {".md", ".txt", ".yml", ".yaml", ".json", ".toml", ".py", ".sh", ".gitignore", ""}
|
|
|
|
def prompt(question, default=None):
|
|
val = input(f"{question}" + (f" [{default}]" if default else "") + ": ").strip()
|
|
return val or (default or "")
|
|
|
|
def is_text_file(p: Path):
|
|
if p.name.startswith(".git"): return False
|
|
if p.is_dir(): return False
|
|
if p.suffix in TEXT_EXTS: return True
|
|
try:
|
|
p.read_bytes().decode("utf-8")
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
def replace_placeholders(text: str, mapping: dict) -> str:
|
|
def sub(m):
|
|
var, default = m.group(1), m.group(2)
|
|
return mapping.get(var, default or "")
|
|
return PLACEHOLDER_PATTERN.sub(sub, text)
|
|
|
|
def replace_in_file(p: Path, mapping: dict):
|
|
try:
|
|
orig = p.read_text(encoding="utf-8")
|
|
except Exception:
|
|
return False
|
|
new = replace_placeholders(orig, mapping)
|
|
if new != orig:
|
|
p.write_text(new, encoding="utf-8")
|
|
return True
|
|
return False
|
|
|
|
def git(cmd, cwd):
|
|
return subprocess.run(["git"] + cmd, cwd=cwd, check=False, capture_output=True, text=True)
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--path", default=".", help="Repository root path")
|
|
ap.add_argument("--no-git", action="store_true", help="Do not run git init/commit")
|
|
args = ap.parse_args()
|
|
|
|
root = Path(args.path).resolve()
|
|
if not root.exists():
|
|
print(f"Path not found: {root}", file=sys.stderr); sys.exit(1)
|
|
|
|
print("Welcome! Let's initialize your AI workflow repository.\n")
|
|
|
|
mapping = {
|
|
"PROJECT_NAME": prompt("Project name", "MyProject"),
|
|
"PRIMARY_OWNER": prompt("Primary owner/handle (for CODEOWNERS)", "your-handle"),
|
|
"REPO_URL": prompt("Gitea repo URL (you can set later)", "https://gitea.example.com/you/myproject"),
|
|
"TIMEBOX": prompt("Default timebox (e.g., '40 messages or 60 minutes')", "40 messages or 60 minutes"),
|
|
"DEFAULT_BRANCH": prompt("Default branch", "main"),
|
|
}
|
|
|
|
print("\nReplacing placeholders...")
|
|
changed = 0
|
|
for p in root.rglob("*"):
|
|
if is_text_file(p):
|
|
if replace_in_file(p, mapping):
|
|
changed += 1
|
|
print(f"Updated {changed} files with your settings.")
|
|
|
|
(root / "reports").mkdir(parents=True, exist_ok=True)
|
|
(root / "project/tasks.yaml").write_text("# tasks: []\n", encoding="utf-8") if not (root / "project/tasks.yaml").exists() else None
|
|
|
|
if not args.no_git:
|
|
if not (root / ".git").exists():
|
|
print("\nInitializing git repository...")
|
|
r = git(["init"], cwd=root)
|
|
if r.returncode != 0:
|
|
print("git init failed:", r.stderr, file=sys.stderr)
|
|
if mapping["DEFAULT_BRANCH"] != "master":
|
|
r = git(["checkout", "-B", mapping["DEFAULT_BRANCH"]], cwd=root)
|
|
if r.returncode != 0:
|
|
print("git branch setup failed:", r.stderr, file=sys.stderr)
|
|
git(["add", "-A"], cwd=root)
|
|
r = git(["commit", "-m", "chore(init): bootstrap AI workflow repository"], cwd=root)
|
|
if r.returncode != 0:
|
|
print("git commit failed:", r.stderr, file=sys.stderr)
|
|
|
|
print("\nDone. Next steps:")
|
|
print(f" 1) Review {root/'project/plan.md'} and {root/'project/state.md'}")
|
|
print(f" 2) Set remote: git remote add origin {mapping['REPO_URL']}")
|
|
print(f" 3) Push: git push -u origin {mapping['DEFAULT_BRANCH']}")
|
|
print(" 4) Start Mission Control with: python3 workflow.py start-mc")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|