From a778b0c0d6fa98ee2c8f5eba8e16fa543bd2ea00 Mon Sep 17 00:00:00 2001 From: Sebastien Taggart Date: Wed, 8 Apr 2026 09:56:14 -0400 Subject: [PATCH] Add --update flag to sync.sh for one-step Code Cannon updates --- README.md | 11 ++++++++++- sync.sh | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index daa005a..0177c8c 100644 --- a/README.md +++ b/README.md @@ -81,12 +81,21 @@ cp CodeCannon/templates/codecannon.yaml .codecannon.yaml CodeCannon/sync.sh ``` -To update Code Cannon to the latest version: +To update Code Cannon to the latest version, run from your project root: + +```bash +CodeCannon/sync.sh --update +``` + +This pulls the latest `main` in the CodeCannon checkout and regenerates your project's skill files in one step. If the CodeCannon checkout is on a branch other than `main`, `--update` stops with a message — update it manually and re-run `sync.sh` without `--update`. + +If you installed Code Cannon as a git submodule, you can instead pin to the new commit: ```bash git submodule update --remote CodeCannon git add CodeCannon git commit -m "Update CodeCannon submodule to latest" +CodeCannon/sync.sh ``` Or run `/setup` for a guided walkthrough that detects your project state and configures everything interactively. diff --git a/sync.sh b/sync.sh index 0c19da0..7d60df8 100755 --- a/sync.sh +++ b/sync.sh @@ -20,6 +20,7 @@ import os import re import hashlib import argparse +import subprocess from pathlib import Path CODECANNON_DIR = Path(__file__).parent @@ -340,6 +341,33 @@ def validate_placeholders(skill_files, project_config): return errors +def self_update_or_exit(): + """Update the CodeCannon checkout via git pull --ff-only. Only runs on main.""" + try: + result = subprocess.run( + ['git', '-C', str(CODECANNON_DIR), 'rev-parse', '--abbrev-ref', 'HEAD'], + capture_output=True, text=True, check=True, + ) + except (subprocess.CalledProcessError, FileNotFoundError) as e: + print(f"Error: could not determine CodeCannon branch ({CODECANNON_DIR}): {e}") + sys.exit(1) + + branch = result.stdout.strip() + if branch != 'main': + print(f"CodeCannon is on branch '{branch}', not 'main'. Skipping auto-update.") + print("Update manually if desired, then re-run without --update.") + sys.exit(1) + + print(f"Updating CodeCannon ({CODECANNON_DIR})...") + pull = subprocess.run( + ['git', '-C', str(CODECANNON_DIR), 'pull', '--ff-only'], + text=True, + ) + if pull.returncode != 0: + print("Error: git pull --ff-only failed. Resolve the issue in the CodeCannon checkout and try again.") + sys.exit(1) + + def main(): parser = argparse.ArgumentParser( description='Generate agent-specific skill files from Code Cannon skills/') @@ -353,8 +381,13 @@ def main(): help='Pre-flight check: verify all {{PLACEHOLDERS}} in skills are defined in config. Exits non-zero if any are missing. Does not write files.') parser.add_argument('--skill', default='', help='Sync only specific skill(s), comma-separated (e.g. start,submit-for-review)') + parser.add_argument('--update', action='store_true', + help='Self-update the Code Cannon checkout (git pull --ff-only on main) before syncing. Stops if not on the main branch.') args = parser.parse_args() + if args.update: + self_update_or_exit() + project_root = Path.cwd() # Load project config