diff --git a/.github/agents/analyser.md b/.github/agents/analyser.md index 24d176ed..6ce8ca32 100644 --- a/.github/agents/analyser.md +++ b/.github/agents/analyser.md @@ -1,7 +1,7 @@ --- name: analyser description: Ongoing technical journal for repository analysis -model: claude-sonnet-4.5 +model: gpt-4.1 --- You are a senior software architect performing a critical, journal-style review of this repository. @@ -19,7 +19,7 @@ Journal mode: - Each run should add new observations or refine previous ones if warranted. Output: -- Write exclusively to `REPOSITORY_ANALYSIS.md`. +- Append exclusively to `REPOSITORY_ANALYSIS.md` using shell (e.g. `cat >> REPOSITORY_ANALYSIS.md`). - Append a new section with the following structure: ## YYYY-MM-DD — Analysis Entry diff --git a/.github/workflows/autopilot.yml b/.github/workflows/autopilot.yml index cd40d84f..b895737d 100644 --- a/.github/workflows/autopilot.yml +++ b/.github/workflows/autopilot.yml @@ -1,9 +1,10 @@ name: Autopilot on: + push: workflow_dispatch: schedule: - - cron: '0 0 * * 1' # Weekly on Monday + - cron: '0 0 * * 1' # Weekly on Monday permissions: contents: write @@ -11,253 +12,346 @@ permissions: pull-requests: write jobs: - # ── Job 1: Run the analyser agent and commit updated REPOSITORY_ANALYSIS.md ── - analyse: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - lfs: true - token: ${{ secrets.GH_PAT || github.token }} - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" + # ── Job 1: Deterministic repository analysis using GitHub Models ── - - name: Install Claude CLI - run: npm install -g @anthropic-ai/claude-code - - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} - - - name: Run analyse-repo - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - UV_EXTRA_INDEX_URL: ${{ secrets.UV_EXTRA_INDEX_URL }} - run: make analyse-repo - - - name: Commit and push updated analysis - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --global url."https://x-access-token:${GH_PAT}@github.com/".insteadOf "https://github.com/" - git add REPOSITORY_ANALYSIS.md - if ! git diff --staged --quiet; then - git commit -m "chore: update REPOSITORY_ANALYSIS.md [autopilot] [skip ci]" - git push origin ${{ github.ref_name }} - else - echo "No changes to REPOSITORY_ANALYSIS.md, skipping commit." - fi - - # ── Job 2: Parse the latest analysis entry and create up to 3 GitHub issues ── - create-issues: - needs: analyse + analyse: runs-on: ubuntu-latest outputs: - issue_numbers: ${{ steps.create.outputs.issue_numbers }} + has_analysis: ${{ steps.analysis.outputs.has_analysis }} steps: - name: Checkout repository uses: actions/checkout@v6.0.2 with: - ref: ${{ github.ref }} - - - name: Create autopilot label if missing - env: - GH_TOKEN: ${{ secrets.GH_PAT || github.token }} - run: | - gh label create autopilot \ - --color 0075ca \ - --description "Autopilot-generated issue" \ - --repo "${{ github.repository }}" 2>/dev/null || true + lfs: true + token: ${{ secrets.GH_PAT || github.token }} - - name: Parse analysis and create issues - id: create + - name: Run repository analysis (GitHub Models) + id: analysis env: - GH_TOKEN: ${{ secrets.GH_PAT || github.token }} + GITHUB_TOKEN: ${{ secrets.GH_PAT || github.token }} run: | python3 << 'PYEOF' - import os - import re - import json - import subprocess - import sys - - with open("REPOSITORY_ANALYSIS.md") as f: - content = f.read() - - # Find the most recent dated entry (## YYYY-MM-DD …) - date_pattern = re.compile(r'^(## \d{4}-\d{2}-\d{2}[^\n]*)', re.MULTILINE) - entry_starts = [m.start() for m in date_pattern.finditer(content)] - if not entry_starts: - print("ERROR: No dated entry found in REPOSITORY_ANALYSIS.md") - sys.exit(1) - - # Latest entry is the first occurrence - entry_text = content[entry_starts[0] : entry_starts[1] if len(entry_starts) > 1 else len(content)] - date_header = date_pattern.search(entry_text).group(1) - - def extract_bullets(section_text): - """Return a list of full bullet strings from a markdown bullet list.""" - bullets = [] - current = [] - for line in section_text.splitlines(): - if re.match(r'^- ', line): - if current: - bullets.append('\n'.join(current)) - current = [line[2:]] # strip leading "- " - elif current and (line.startswith(' ') or line == ''): - current.append(line) - else: - if current: - bullets.append('\n'.join(current)) - current = [] - if current: - bullets.append('\n'.join(current)) - return bullets - - # Extract Weaknesses section - weaknesses = [] - w_match = re.search( - r'### Weaknesses\n(.*?)(?=\n### |\Z)', - entry_text, - re.DOTALL, + import json, subprocess, datetime, os, urllib.request, sys + + # --- Collect repo snapshot (controlled scope) --- + files = subprocess.check_output( + "git ls-files", shell=True, text=True + ).splitlines() + + files = [f for f in files if f.endswith((".py", ".md", ".toml"))][:200] + + content = "" + for f in files: + try: + with open(f) as fh: + content += f"\n\n# FILE: {f}\n" + fh.read()[:2000] + except: + pass + + prompt = """ + Analyze this repository. + + Return STRICT JSON: + + { + "summary": "...", + "weaknesses": ["..."], + "risks": ["..."], + "opportunities": ["..."] + } + + No text outside JSON. + """ + + payload = json.dumps({ + "model": "gpt-4.1", + "messages": [ + {"role": "user", "content": prompt + content} + ], + "temperature": 0 + }).encode() + + req = urllib.request.Request( + "https://models.inference.ai.azure.com/chat/completions", + data=payload, + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}" + } ) - if w_match: - weaknesses = extract_bullets(w_match.group(1)) - # Extract Risks / Technical Debt section - risks = [] - r_match = re.search( - r'### Risks / Technical Debt\n(.*?)(?=\n### |\Z)', - entry_text, - re.DOTALL, - ) - if r_match: - risks = extract_bullets(r_match.group(1)) + try: + with urllib.request.urlopen(req) as resp: + result = json.loads(resp.read()) + except Exception as e: + print("Model call failed:", e) + print("has_analysis=false") + with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: + gho.write('has_analysis=false\n') + sys.exit(0) - # Prioritise Weaknesses, then Risks, take up to 3 - items = (weaknesses + risks)[:3] + raw = result["choices"][0]["message"]["content"] - if not items: - print("No weaknesses or risks found in the latest entry.") + try: + data = json.loads(raw) + except: + print("Invalid JSON from model") with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: - gho.write('issue_numbers=[]\n') + gho.write('has_analysis=false\n') sys.exit(0) - issue_numbers = [] - for item in items: - # Title: bold phrase or first sentence (max 100 chars) - bold = re.match(r'\*\*([^*]+)\*\*', item) - if bold: - title = bold.group(1).rstrip('.') - else: - title = item.split('.')[0].strip()[:100] + # --- Validate schema --- + for key in ["summary", "weaknesses", "risks", "opportunities"]: + if key not in data: + raise ValueError(f"Missing key: {key}") - body = f"- {item}\n\n---\n*Source: {date_header}*" + date = datetime.date.today().isoformat() + data["date"] = date - result = subprocess.run( - [ - 'gh', 'issue', 'create', - '--title', title, - '--body', body, - '--label', 'autopilot', - ], - capture_output=True, - text=True, - check=True, - ) - # gh prints the issue URL; extract the number from the URL - url = result.stdout.strip() - num = int(url.rstrip('/').split('/')[-1]) - issue_numbers.append(num) - print(f"Created issue #{num}: {title}") + # --- Save JSON --- + with open("analysis.json", "w") as f: + json.dump(data, f, indent=2) - with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: - gho.write(f'issue_numbers={json.dumps(issue_numbers)}\n') - PYEOF + # --- Append markdown (derived artifact) --- + md = f"""## {date} - # ── Job 3: Spawn Claude to solve each issue and open a PR ── - solve-issues: - needs: create-issues - if: needs.create-issues.outputs.issue_numbers != '[]' - runs-on: ubuntu-latest - strategy: - matrix: - issue: ${{ fromJson(needs.create-issues.outputs.issue_numbers) }} - fail-fast: false - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - lfs: true - token: ${{ secrets.GH_PAT || github.token }} + ### Summary + {data['summary']} - - name: Install uv - uses: astral-sh/setup-uv@v7.6.0 - with: - version: "0.10.12" + ### Weaknesses + {chr(10).join('- ' + w for w in data['weaknesses'])} - - name: Install Claude CLI - run: npm install -g @anthropic-ai/claude-code + ### Risks / Technical Debt + {chr(10).join('- ' + r for r in data['risks'])} - - name: Configure git auth for private packages - uses: ./.github/actions/configure-git-auth - with: - token: ${{ secrets.GH_PAT }} + ### Opportunities + {chr(10).join('- ' + o for o in data['opportunities'])} + """ - - name: Configure git identity + with open("REPOSITORY_ANALYSIS.md", "a") as f: + f.write("\n\n" + md) + + with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: + gho.write('has_analysis=true\n') + PYEOF + + - name: Commit analysis + if: steps.analysis.outputs.has_analysis == 'true' env: GH_PAT: ${{ secrets.GH_PAT || github.token }} run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --global url."https://x-access-token:${GH_PAT}@github.com/".insteadOf "https://github.com/" - - - name: Fetch issue details - id: issue - env: - GH_TOKEN: ${{ secrets.GH_PAT || github.token }} - run: | - ISSUE_JSON=$(gh issue view ${{ matrix.issue }} --json title,body) - ISSUE_TITLE=$(echo "$ISSUE_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['title'])") - ISSUE_BODY=$(echo "$ISSUE_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['body'])") - echo "title=$ISSUE_TITLE" >> "$GITHUB_OUTPUT" - # Body may be multiline — write to a temp file instead - echo "$ISSUE_BODY" > /tmp/issue_body.txt - - - name: Solve issue with Claude and open PR - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GH_TOKEN: ${{ secrets.GH_PAT || github.token }} - ISSUE_NUMBER: ${{ matrix.issue }} - ISSUE_TITLE: ${{ steps.issue.outputs.title }} - run: | - BRANCH="autopilot/fix-issue-${ISSUE_NUMBER}" - ISSUE_BODY=$(cat /tmp/issue_body.txt) - - claude --print \ - --allowedTools "Bash,Write,Edit" \ - "You are working on the repository at $(pwd). - - GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE} - - Issue description: - ${ISSUE_BODY} - - Your task: - 1. Create a new branch: git checkout -b ${BRANCH} - 2. Analyse the issue and make the minimal necessary code changes to fix it. - 3. Run 'make test' to verify the fix passes all tests. - 4. Commit your changes with a descriptive message referencing the issue. - 5. Push the branch: git push origin ${BRANCH} - 6. Open a pull request using: gh pr create --title 'fix: ${ISSUE_TITLE}' --body 'Fixes #${ISSUE_NUMBER} - - Automated fix generated by the autopilot workflow.' --head ${BRANCH} --base ${{ github.ref_name }} + git add analysis.json REPOSITORY_ANALYSIS.md + if ! git diff --staged --quiet; then + git commit -m "chore: update analysis [autopilot v2] [skip ci]" + git push origin ${{ github.ref_name }} + fi - Keep changes minimal and focused on addressing the issue described." +# # ── Job 2: Parse the latest analysis entry and create up to 3 GitHub issues ── +# create-issues: +# needs: analyse +# runs-on: ubuntu-latest +# outputs: +# issue_numbers: ${{ steps.create.outputs.issue_numbers }} +# steps: +# - name: Checkout repository +# uses: actions/checkout@v6.0.2 +# with: +# ref: ${{ github.ref }} +# +# - name: Create autopilot label if missing +# env: +# GH_TOKEN: ${{ secrets.GH_PAT || github.token }} +# run: | +# gh label create autopilot \ +# --color 0075ca \ +# --description "Autopilot-generated issue" \ +# --repo "${{ github.repository }}" 2>/dev/null || true +# +# - name: Parse analysis and create issues +# id: create +# env: +# GH_TOKEN: ${{ secrets.GH_PAT || github.token }} +# run: | +# python3 << 'PYEOF' +# import os +# import re +# import json +# import subprocess +# import sys +# +# with open("REPOSITORY_ANALYSIS.md") as f: +# content = f.read() +# +# # Find the most recent dated entry (## YYYY-MM-DD …) +# date_pattern = re.compile(r'^(## \d{4}-\d{2}-\d{2}[^\n]*)', re.MULTILINE) +# entry_starts = [m.start() for m in date_pattern.finditer(content)] +# if not entry_starts: +# print("ERROR: No dated entry found in REPOSITORY_ANALYSIS.md") +# sys.exit(1) +# +# # Latest entry is the first occurrence +# entry_text = content[entry_starts[0] : entry_starts[1] if len(entry_starts) > 1 else len(content)] +# date_header = date_pattern.search(entry_text).group(1) +# +# def extract_bullets(section_text): +# """Return a list of full bullet strings from a markdown bullet list.""" +# bullets = [] +# current = [] +# for line in section_text.splitlines(): +# if re.match(r'^- ', line): +# if current: +# bullets.append('\n'.join(current)) +# current = [line[2:]] # strip leading "- " +# elif current and (line.startswith(' ') or line == ''): +# current.append(line) +# else: +# if current: +# bullets.append('\n'.join(current)) +# current = [] +# if current: +# bullets.append('\n'.join(current)) +# return bullets +# +# # Extract Weaknesses section +# weaknesses = [] +# w_match = re.search( +# r'### Weaknesses\n(.*?)(?=\n### |\Z)', +# entry_text, +# re.DOTALL, +# ) +# if w_match: +# weaknesses = extract_bullets(w_match.group(1)) +# +# # Extract Risks / Technical Debt section +# risks = [] +# r_match = re.search( +# r'### Risks / Technical Debt\n(.*?)(?=\n### |\Z)', +# entry_text, +# re.DOTALL, +# ) +# if r_match: +# risks = extract_bullets(r_match.group(1)) +# +# # Prioritise Weaknesses, then Risks, take up to 3 +# items = (weaknesses + risks)[:3] +# +# if not items: +# print("No weaknesses or risks found in the latest entry.") +# with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: +# gho.write('issue_numbers=[]\n') +# sys.exit(0) +# +# issue_numbers = [] +# for item in items: +# # Title: bold phrase or first sentence (max 100 chars) +# bold = re.match(r'\*\*([^*]+)\*\*', item) +# if bold: +# title = bold.group(1).rstrip('.') +# else: +# title = item.split('.')[0].strip()[:100] +# +# body = f"- {item}\n\n---\n*Source: {date_header}*" +# +# result = subprocess.run( +# [ +# 'gh', 'issue', 'create', +# '--title', title, +# '--body', body, +# '--label', 'autopilot', +# ], +# capture_output=True, +# text=True, +# check=True, +# ) +# # gh prints the issue URL; extract the number from the URL +# url = result.stdout.strip() +# num = int(url.rstrip('/').split('/')[-1]) +# issue_numbers.append(num) +# print(f"Created issue #{num}: {title}") +# +# with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: +# gho.write(f'issue_numbers={json.dumps(issue_numbers)}\n') +# PYEOF +# +# # ── Job 3: Spawn Claude to solve each issue and open a PR ── +# solve-issues: +# needs: create-issues +# if: needs.create-issues.outputs.issue_numbers != '[]' +# runs-on: ubuntu-latest +# strategy: +# matrix: +# issue: ${{ fromJson(needs.create-issues.outputs.issue_numbers) }} +# fail-fast: false +# steps: +# - name: Checkout repository +# uses: actions/checkout@v6.0.2 +# with: +# lfs: true +# token: ${{ secrets.GH_PAT || github.token }} +# +# - name: Install uv +# uses: astral-sh/setup-uv@v7.6.0 +# with: +# version: "0.10.12" +# +# - name: Install Claude CLI +# run: npm install -g @anthropic-ai/claude-code +# +# - name: Configure git auth for private packages +# uses: ./.github/actions/configure-git-auth +# with: +# token: ${{ secrets.GH_PAT }} +# +# - name: Configure git identity +# env: +# GH_PAT: ${{ secrets.GH_PAT || github.token }} +# run: | +# git config user.name "github-actions[bot]" +# git config user.email "41898282+github-actions[bot]@users.noreply.github.com" +# git config --global url."https://x-access-token:${GH_PAT}@github.com/".insteadOf "https://github.com/" +# +# - name: Fetch issue details +# id: issue +# env: +# GH_TOKEN: ${{ secrets.GH_PAT || github.token }} +# run: | +# ISSUE_JSON=$(gh issue view ${{ matrix.issue }} --json title,body) +# ISSUE_TITLE=$(echo "$ISSUE_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['title'])") +# ISSUE_BODY=$(echo "$ISSUE_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['body'])") +# echo "title=$ISSUE_TITLE" >> "$GITHUB_OUTPUT" +# # Body may be multiline — write to a temp file instead +# echo "$ISSUE_BODY" > /tmp/issue_body.txt +# +# - name: Solve issue with Claude and open PR +# env: +# ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} +# GH_TOKEN: ${{ secrets.GH_PAT || github.token }} +# ISSUE_NUMBER: ${{ matrix.issue }} +# ISSUE_TITLE: ${{ steps.issue.outputs.title }} +# run: | +# BRANCH="autopilot/fix-issue-${ISSUE_NUMBER}" +# ISSUE_BODY=$(cat /tmp/issue_body.txt) +# +# claude --print \ +# --allowedTools "Bash,Write,Edit" \ +# "You are working on the repository at $(pwd). +# +# GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE} +# +# Issue description: +# ${ISSUE_BODY} +# +# Your task: +# 1. Create a new branch: git checkout -b ${BRANCH} +# 2. Analyse the issue and make the minimal necessary code changes to fix it. +# 3. Run 'make test' to verify the fix passes all tests. +# 4. Commit your changes with a descriptive message referencing the issue. +# 5. Push the branch: git push origin ${BRANCH} +# 6. Open a pull request using: gh pr create --title 'fix: ${ISSUE_TITLE}' --body 'Fixes #${ISSUE_NUMBER} +# +# Automated fix generated by the autopilot workflow.' --head ${BRANCH} --base ${{ github.ref_name }} +# +# Keep changes minimal and focused on addressing the issue described." diff --git a/.github/workflows/autopilot_v2.yml b/.github/workflows/autopilot_v2.yml new file mode 100644 index 00000000..4b68b3d2 --- /dev/null +++ b/.github/workflows/autopilot_v2.yml @@ -0,0 +1,149 @@ +name: Autopilot_v2 + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * 1' # Weekly on Monday + +permissions: + contents: write + issues: write + pull-requests: write + +jobs: + + # ── Job 1: Deterministic repository analysis using GitHub Models ── + + analyse: + runs-on: ubuntu-latest + outputs: + has_analysis: ${{ steps.analysis.outputs.has_analysis }} + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + lfs: true + token: ${{ secrets.GH_PAT || github.token }} + + - name: Run repository analysis (GitHub Models) + id: analysis + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT || github.token }} + run: | + python3 << 'PYEOF' + import json, subprocess, datetime, os, urllib.request, sys + + # --- Collect repo snapshot (controlled scope) --- + files = subprocess.check_output( + "git ls-files", shell=True, text=True + ).splitlines() + + files = [f for f in files if f.endswith((".py", ".md", ".toml"))][:200] + + content = "" + for f in files: + try: + with open(f) as fh: + content += f"\n\n# FILE: {f}\n" + fh.read()[:2000] + except: + pass + + prompt = """ + Analyze this repository. + + Return STRICT JSON: + + { + "summary": "...", + "weaknesses": ["..."], + "risks": ["..."], + "opportunities": ["..."] + } + + No text outside JSON. + """ + + payload = json.dumps({ + "model": "gpt-4.1", + "messages": [ + {"role": "user", "content": prompt + content} + ], + "temperature": 0 + }).encode() + + req = urllib.request.Request( + "https://models.inference.ai.azure.com/chat/completions", + data=payload, + headers={ + "Content-Type": "application/json", + "Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}" + } + ) + + try: + with urllib.request.urlopen(req) as resp: + result = json.loads(resp.read()) + except Exception as e: + print("Model call failed:", e) + print("has_analysis=false") + with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: + gho.write('has_analysis=false\n') + sys.exit(0) + + raw = result["choices"][0]["message"]["content"] + + try: + data = json.loads(raw) + except: + print("Invalid JSON from model") + with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: + gho.write('has_analysis=false\n') + sys.exit(0) + + # --- Validate schema --- + for key in ["summary", "weaknesses", "risks", "opportunities"]: + if key not in data: + raise ValueError(f"Missing key: {key}") + + date = datetime.date.today().isoformat() + data["date"] = date + + # --- Save JSON --- + with open("analysis.json", "w") as f: + json.dump(data, f, indent=2) + + # --- Append markdown (derived artifact) --- + md = f"""## {date} + + ### Summary + {data['summary']} + + ### Weaknesses + {chr(10).join('- ' + w for w in data['weaknesses'])} + + ### Risks / Technical Debt + {chr(10).join('- ' + r for r in data['risks'])} + + ### Opportunities + {chr(10).join('- ' + o for o in data['opportunities'])} + """ + + with open("REPOSITORY_ANALYSIS.md", "a") as f: + f.write("\n\n" + md) + + with open(os.environ['GITHUB_OUTPUT'], 'a') as gho: + gho.write('has_analysis=true\n') + PYEOF + + - name: Commit analysis + if: steps.analysis.outputs.has_analysis == 'true' + env: + GH_PAT: ${{ secrets.GH_PAT || github.token }} + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add analysis.json REPOSITORY_ANALYSIS.md + if ! git diff --staged --quiet; then + git commit -m "chore: update analysis [autopilot v2] [skip ci]" + git push origin ${{ github.ref_name }} + fi diff --git a/.rhiza/make.d/agentic.mk b/.rhiza/make.d/agentic.mk index 5ddeea97..6cdfe302 100644 --- a/.rhiza/make.d/agentic.mk +++ b/.rhiza/make.d/agentic.mk @@ -16,11 +16,12 @@ copilot: install-copilot ## open interactive prompt for copilot claude: install-claude ## open interactive prompt for claude code @"$(CLAUDE_BIN)" -analyse-repo: install-claude ## run the analyser agent to update REPOSITORY_ANALYSIS.md - @"$(CLAUDE_BIN)" --print \ - --allowedTools "Write" \ - --agent .github/agents/analyser.md \ - "Analyze the repository and update REPOSITORY_ANALYSIS.md" +analyse-repo: install-copilot ## run the analyser agent to update REPOSITORY_ANALYSIS.md + @"$(COPILOT_BIN)" \ + --allow-all-tools \ + --model "$(DEFAULT_AI_MODEL)" \ + --agent analyser \ + -p "Analyze the repository and append a new dated entry to REPOSITORY_ANALYSIS.md" summarise-changes: install-copilot ## summarise changes since the most recent release/tag @"$(COPILOT_BIN)" -p "Show me the commits since the last release/tag and summarise them" --allow-tool 'shell(git)' --model "$(DEFAULT_AI_MODEL)" --agent summarise