CascadingDev/tools/build_installer.py

105 lines
3.8 KiB
Python

#!/usr/bin/env python3
import shutil, os
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / "install"
VER = (ROOT / "VERSION").read_text().strip() if (ROOT / "VERSION").exists() else "0.1.0"
BUNDLE = OUT / f"cascadingdev-{VER}"
def main():
# Removes the old install bundle if it already exists
if BUNDLE.exists():
shutil.rmtree(BUNDLE)
# Create the directories
(BUNDLE / "assets" / "hooks").mkdir(parents=True, exist_ok=True)
(BUNDLE / "assets" / "templates").mkdir(parents=True, exist_ok=True)
# Copy the git hook and any other runtime utilities.
shutil.copy2(ROOT / "assets" / "runtime" / "ramble.py", BUNDLE / "ramble.py")
shutil.copy2(ROOT / "assets" / "runtime" / "create_feature.py", BUNDLE / "create_feature.py")
shutil.copy2(ROOT / "assets" / "hooks" / "pre-commit", BUNDLE / "assets" / "hooks" / "pre-commit")
# copy core templates
for t in [
"feature_request.md",
"feature.discussion.md",
"feature.discussion.sum.md",
"design.discussion.md",
"design_doc.md",
"USER_GUIDE.md",
"root_gitignore",
]:
shutil.copy2(ROOT / "assets" / "templates" / t, BUNDLE / "assets" / "templates" / t)
# copy (recursively) the contents of process/ and rules/ templates folders
def copy_tree(src, dst):
if dst.exists():
shutil.rmtree(dst)
shutil.copytree(src, dst)
copy_tree(ROOT / "assets" / "templates" / "process", BUNDLE / "assets" / "templates" / "process")
copy_tree(ROOT / "assets" / "templates" / "rules", BUNDLE / "assets" / "templates" / "rules")
# copy shared AI configuration
config_src = ROOT / "config"
if config_src.exists():
copy_tree(config_src, BUNDLE / "config")
# copy agents directory
agents_src = ROOT / "agents"
if agents_src.exists():
copy_tree(agents_src, BUNDLE / "agents")
# copy automation directory (workflow.py and future orchestration scripts)
automation_src = ROOT / "automation"
if automation_src.exists():
copy_tree(automation_src, BUNDLE / "automation")
# copy agent SDK
sdk_src = ROOT / "src" / "cascadingdev"
if sdk_src.exists():
copy_tree(sdk_src, BUNDLE / "sdk" / "cascadingdev")
# write installer entrypoint
shutil.copy2(ROOT / "src" / "cascadingdev" / "setup_project.py",
BUNDLE / "setup_cascadingdev.py")
install_doc = """# CascadingDev Installer
## Requirements
- Python 3.10+ and git
- (Optional) PySide6 or PyQt5 for the Ramble GUI
## Quick Start
```bash
python setup_cascadingdev.py --target /path/to/your-project
```
### Options
- `--target PATH`: directory to create or reuse for the repo
- `--no-ramble`: skip the Ramble GUI and answer prompts in the terminal
- `--provider {mock,claude}`: select the Ramble provider (default: mock)
- `--claude-cmd CMD`: command to invoke when provider is `claude`
### Steps Performed
1. Creates the standard CascadingDev folder layout in the target.
2. Copies templates, policies, rules, and runtime scripts into place.
3. Initializes git (if needed) and installs the pre-commit hook.
4. Launches Ramble unless `--no-ramble` is provided.
5. Seeds initial feature discussions, summaries, and rules.
6. Commits the bootstrap state so the repo starts clean.
### Troubleshooting
- If the GUI fails, activate a virtualenv then `pip install PySide6`, or rerun with `--no-ramble`.
- Ensure `git` is available on PATH; the installer runs `git init` and `git commit`.
- Remove or empty the target directory if rerunning into conflicting files.
"""
(BUNDLE / "INSTALL.md").write_text(install_doc.strip() + "\n", encoding="utf-8")
(BUNDLE / "VERSION").write_text(VER, encoding="utf-8")
print(f"[✓] Built installer → {BUNDLE}")
if __name__ == "__main__":
main()