diff --git a/.squad-templates/workflows/squad-heartbeat.yml b/.squad-templates/workflows/squad-heartbeat.yml index 1b75fda3e..3ab647c89 100644 --- a/.squad-templates/workflows/squad-heartbeat.yml +++ b/.squad-templates/workflows/squad-heartbeat.yml @@ -1,167 +1,164 @@ -name: Squad Heartbeat (Ralph) -# ⚠️ SYNC: This workflow is maintained in 4 locations. Changes must be applied to all: -# - templates/workflows/squad-heartbeat.yml (source template) -# - packages/squad-cli/templates/workflows/squad-heartbeat.yml (CLI package) -# - .squad/templates/workflows/squad-heartbeat.yml (installed template) -# - .github/workflows/squad-heartbeat.yml (active workflow) -# Run 'squad upgrade' to sync installed copies from source templates. - -on: - # React to completed work or new squad work - issues: - types: [closed, labeled] - pull_request: - types: [closed] - - # Manual trigger - workflow_dispatch: - -permissions: - issues: write - contents: read - pull-requests: read - -jobs: - heartbeat: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Check triage script - id: check-script - run: | - if [ -f ".squad/templates/ralph-triage.js" ]; then - echo "has_script=true" >> $GITHUB_OUTPUT - else - echo "has_script=false" >> $GITHUB_OUTPUT - echo "⚠️ ralph-triage.js not found — run 'squad upgrade' to install" - fi - - - name: Ralph — Smart triage - if: steps.check-script.outputs.has_script == 'true' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - node .squad/templates/ralph-triage.js \ - --squad-dir .squad \ - --output triage-results.json - - - name: Ralph — Apply triage decisions - if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != '' - uses: actions/github-script@v7 - with: - script: | - const fs = require('fs'); - const path = 'triage-results.json'; - if (!fs.existsSync(path)) { - core.info('No triage results — board is clear'); - return; - } - - const results = JSON.parse(fs.readFileSync(path, 'utf8')); - if (results.length === 0) { - core.info('📋 Board is clear — Ralph found no untriaged issues'); - return; - } - - for (const decision of results) { - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: decision.issueNumber, - labels: [decision.label] - }); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: decision.issueNumber, - body: [ - '### 🔄 Ralph — Auto-Triage', - '', - `**Assigned to:** ${decision.assignTo}`, - `**Reason:** ${decision.reason}`, - `**Source:** ${decision.source}`, - '', - '> Ralph auto-triaged this issue using routing rules.', - '> To reassign, swap the `squad:*` label.' - ].join('\n') - }); - - core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`); - } catch (e) { - core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`); - } - } - - core.info(`🔄 Ralph triaged ${results.length} issue(s)`); - - # Copilot auto-assign step (uses PAT if available) - - name: Ralph — Assign @copilot issues - if: success() - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); - - let teamFile = '.squad/team.md'; - if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) return; - - const content = fs.readFileSync(teamFile, 'utf8'); - - // Check if @copilot is on the team with auto-assign - const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot'); - const autoAssign = content.includes(''); - if (!hasCopilot || !autoAssign) return; - - // Find issues labeled squad:copilot with no assignee - try { - const { data: copilotIssues } = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - labels: 'squad:copilot', - state: 'open', - per_page: 5 - }); - - const unassigned = copilotIssues.filter(i => - !i.assignees || i.assignees.length === 0 - ); - - if (unassigned.length === 0) { - core.info('No unassigned squad:copilot issues'); - return; - } - - // Get repo default branch - const { data: repoData } = await github.rest.repos.get({ - owner: context.repo.owner, - repo: context.repo.repo - }); - - for (const issue of unassigned) { - try { - await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - assignees: ['copilot-swe-agent[bot]'], - agent_assignment: { - target_repo: `${context.repo.owner}/${context.repo.repo}`, - base_branch: repoData.default_branch, - custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` - } - }); - core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); - } catch (e) { - core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`); - } - } - } catch (e) { - core.info(`No squad:copilot label found or error: ${e.message}`); - } +name: Squad Heartbeat (Ralph) +# ⚠️ SYNC: This workflow is maintained in 4 locations. Changes must be applied to all: +# - templates/workflows/squad-heartbeat.yml (source template) +# - packages/squad-cli/templates/workflows/squad-heartbeat.yml (CLI package) +# - .squad/templates/workflows/squad-heartbeat.yml (installed template) +# - .github/workflows/squad-heartbeat.yml (active workflow) +# Run 'squad upgrade' to sync installed copies from source templates. + +on: + # React to completed work or new squad work + issues: + types: [closed, labeled] + pull_request: + types: [closed] + + # Manual trigger + workflow_dispatch: + +permissions: + issues: write + contents: read + pull-requests: read + +jobs: + heartbeat: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check triage script + id: check-script + run: | + if [ -f ".squad/templates/ralph-triage.js" ]; then + echo "has_script=true" >> $GITHUB_OUTPUT + else + echo "has_script=false" >> $GITHUB_OUTPUT + echo "⚠️ ralph-triage.js not found — run 'squad upgrade' to install" + fi + + - name: Ralph — Smart triage + if: steps.check-script.outputs.has_script == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + node .squad/templates/ralph-triage.js \ + --squad-dir .squad \ + --output triage-results.json + + - name: Ralph — Apply triage decisions + if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != '' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = 'triage-results.json'; + if (!fs.existsSync(path)) { + core.info('No triage results — board is clear'); + return; + } + + const results = JSON.parse(fs.readFileSync(path, 'utf8')); + if (results.length === 0) { + core.info('📋 Board is clear — Ralph found no untriaged issues'); + return; + } + + for (const decision of results) { + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: decision.issueNumber, + labels: [decision.label] + }); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: decision.issueNumber, + body: [ + '### 🔄 Ralph — Auto-Triage', + '', + `**Assigned to:** ${decision.assignTo}`, + `**Reason:** ${decision.reason}`, + `**Source:** ${decision.source}`, + '', + '> Ralph auto-triaged this issue using routing rules.', + '> To reassign, swap the `squad:*` label.' + ].join('\n') + }); + + core.info(`Triaged #${decision.issueNumber} → ${decision.assignTo} (${decision.source})`); + } catch (e) { + core.warning(`Failed to triage #${decision.issueNumber}: ${e.message}`); + } + } + + core.info(`🔄 Ralph triaged ${results.length} issue(s)`); + + # Copilot auto-assign step (uses PAT if available) + - name: Ralph — Assign @copilot issues + if: success() + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + + const teamFile = '.squad/team.md'; + if (!fs.existsSync(teamFile)) return; + + const content = fs.readFileSync(teamFile, 'utf8'); + + // Check if @copilot is on the team with auto-assign + const hasCopilot = content.includes('🤖 Coding Agent') || content.includes('@copilot'); + const autoAssign = content.includes(''); + if (!hasCopilot || !autoAssign) return; + + // Find issues labeled squad:copilot with no assignee + try { + const { data: copilotIssues } = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + labels: 'squad:copilot', + state: 'open', + per_page: 5 + }); + + const unassigned = copilotIssues.filter(i => + !i.assignees || i.assignees.length === 0 + ); + + if (unassigned.length === 0) { + core.info('No unassigned squad:copilot issues'); + return; + } + + // Get repo default branch + const { data: repoData } = await github.rest.repos.get({ + owner: context.repo.owner, + repo: context.repo.repo + }); + + for (const issue of unassigned) { + try { + await github.request('POST /repos/{owner}/{repo}/issues/{issue_number}/assignees', { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + assignees: ['copilot-swe-agent[bot]'], + agent_assignment: { + target_repo: `${context.repo.owner}/${context.repo.repo}`, + base_branch: repoData.default_branch, + custom_instructions: `Read .squad/team.md for team context and .squad/routing.md for routing rules.` + } + }); + core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); + } catch (e) { + core.warning(`Failed to assign @copilot to #${issue.number}: ${e.message}`); + } + } + } catch (e) { + core.info(`No squad:copilot label found or error: ${e.message}`); + } diff --git a/.squad-templates/workflows/squad-issue-assign.yml b/.squad-templates/workflows/squad-issue-assign.yml index ad140f42d..f6b664bd8 100644 --- a/.squad-templates/workflows/squad-issue-assign.yml +++ b/.squad-templates/workflows/squad-issue-assign.yml @@ -27,13 +27,9 @@ jobs: // Extract member name from label (e.g., "squad:ripley" → "ripley") const memberName = label.replace('squad:', '').toLowerCase(); - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot assign work'); + core.warning('No .squad/team.md found — cannot assign work'); return; } @@ -72,7 +68,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, - body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` (or \`.ai-team/team.md\`) for valid member names.` + body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` for valid member names.` }); return; } diff --git a/.squad-templates/workflows/squad-triage.yml b/.squad-templates/workflows/squad-triage.yml index d118a2813..8eaf51f65 100644 --- a/.squad-templates/workflows/squad-triage.yml +++ b/.squad-templates/workflows/squad-triage.yml @@ -22,13 +22,9 @@ jobs: const fs = require('fs'); const issue = context.payload.issue; - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot triage'); + core.warning('No .squad/team.md found — cannot triage'); return; } @@ -88,11 +84,7 @@ jobs: } } - // Read routing rules — check .squad/ first, fall back to .ai-team/ - let routingFile = '.squad/routing.md'; - if (!fs.existsSync(routingFile)) { - routingFile = '.ai-team/routing.md'; - } + const routingFile = '.squad/routing.md'; let routingContent = ''; if (fs.existsSync(routingFile)) { routingContent = fs.readFileSync(routingFile, 'utf8'); diff --git a/.squad-templates/workflows/sync-squad-labels.yml b/.squad-templates/workflows/sync-squad-labels.yml index 699fc680f..f3799e793 100644 --- a/.squad-templates/workflows/sync-squad-labels.yml +++ b/.squad-templates/workflows/sync-squad-labels.yml @@ -4,7 +4,6 @@ on: push: paths: - '.squad/team.md' - - '.ai-team/team.md' workflow_dispatch: permissions: @@ -22,13 +21,9 @@ jobs: with: script: | const fs = require('fs'); - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - - if (!fs.existsSync(teamFile)) { - core.info('No .squad/team.md or .ai-team/team.md found — skipping label sync'); + core.info('No .squad/team.md found — skipping label sync'); return; } diff --git a/packages/squad-cli/templates/workflows/squad-heartbeat.yml b/packages/squad-cli/templates/workflows/squad-heartbeat.yml index 5494296fd..3ab647c89 100644 --- a/packages/squad-cli/templates/workflows/squad-heartbeat.yml +++ b/packages/squad-cli/templates/workflows/squad-heartbeat.yml @@ -106,10 +106,7 @@ jobs: script: | const fs = require('fs'); - let teamFile = '.squad/team.md'; - if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) return; const content = fs.readFileSync(teamFile, 'utf8'); @@ -154,7 +151,7 @@ jobs: agent_assignment: { target_repo: `${context.repo.owner}/${context.repo.repo}`, base_branch: repoData.default_branch, - custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` + custom_instructions: `Read .squad/team.md for team context and .squad/routing.md for routing rules.` } }); core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); diff --git a/packages/squad-cli/templates/workflows/squad-issue-assign.yml b/packages/squad-cli/templates/workflows/squad-issue-assign.yml index ad140f42d..f6b664bd8 100644 --- a/packages/squad-cli/templates/workflows/squad-issue-assign.yml +++ b/packages/squad-cli/templates/workflows/squad-issue-assign.yml @@ -27,13 +27,9 @@ jobs: // Extract member name from label (e.g., "squad:ripley" → "ripley") const memberName = label.replace('squad:', '').toLowerCase(); - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot assign work'); + core.warning('No .squad/team.md found — cannot assign work'); return; } @@ -72,7 +68,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, - body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` (or \`.ai-team/team.md\`) for valid member names.` + body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` for valid member names.` }); return; } diff --git a/packages/squad-cli/templates/workflows/squad-triage.yml b/packages/squad-cli/templates/workflows/squad-triage.yml index d118a2813..8eaf51f65 100644 --- a/packages/squad-cli/templates/workflows/squad-triage.yml +++ b/packages/squad-cli/templates/workflows/squad-triage.yml @@ -22,13 +22,9 @@ jobs: const fs = require('fs'); const issue = context.payload.issue; - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot triage'); + core.warning('No .squad/team.md found — cannot triage'); return; } @@ -88,11 +84,7 @@ jobs: } } - // Read routing rules — check .squad/ first, fall back to .ai-team/ - let routingFile = '.squad/routing.md'; - if (!fs.existsSync(routingFile)) { - routingFile = '.ai-team/routing.md'; - } + const routingFile = '.squad/routing.md'; let routingContent = ''; if (fs.existsSync(routingFile)) { routingContent = fs.readFileSync(routingFile, 'utf8'); diff --git a/packages/squad-cli/templates/workflows/sync-squad-labels.yml b/packages/squad-cli/templates/workflows/sync-squad-labels.yml index 699fc680f..f3799e793 100644 --- a/packages/squad-cli/templates/workflows/sync-squad-labels.yml +++ b/packages/squad-cli/templates/workflows/sync-squad-labels.yml @@ -4,7 +4,6 @@ on: push: paths: - '.squad/team.md' - - '.ai-team/team.md' workflow_dispatch: permissions: @@ -22,13 +21,9 @@ jobs: with: script: | const fs = require('fs'); - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - - if (!fs.existsSync(teamFile)) { - core.info('No .squad/team.md or .ai-team/team.md found — skipping label sync'); + core.info('No .squad/team.md found — skipping label sync'); return; } diff --git a/packages/squad-sdk/templates/workflows/squad-heartbeat.yml b/packages/squad-sdk/templates/workflows/squad-heartbeat.yml index 5494296fd..3ab647c89 100644 --- a/packages/squad-sdk/templates/workflows/squad-heartbeat.yml +++ b/packages/squad-sdk/templates/workflows/squad-heartbeat.yml @@ -106,10 +106,7 @@ jobs: script: | const fs = require('fs'); - let teamFile = '.squad/team.md'; - if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) return; const content = fs.readFileSync(teamFile, 'utf8'); @@ -154,7 +151,7 @@ jobs: agent_assignment: { target_repo: `${context.repo.owner}/${context.repo.repo}`, base_branch: repoData.default_branch, - custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` + custom_instructions: `Read .squad/team.md for team context and .squad/routing.md for routing rules.` } }); core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); diff --git a/packages/squad-sdk/templates/workflows/squad-issue-assign.yml b/packages/squad-sdk/templates/workflows/squad-issue-assign.yml index ad140f42d..f6b664bd8 100644 --- a/packages/squad-sdk/templates/workflows/squad-issue-assign.yml +++ b/packages/squad-sdk/templates/workflows/squad-issue-assign.yml @@ -27,13 +27,9 @@ jobs: // Extract member name from label (e.g., "squad:ripley" → "ripley") const memberName = label.replace('squad:', '').toLowerCase(); - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot assign work'); + core.warning('No .squad/team.md found — cannot assign work'); return; } @@ -72,7 +68,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, - body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` (or \`.ai-team/team.md\`) for valid member names.` + body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` for valid member names.` }); return; } diff --git a/packages/squad-sdk/templates/workflows/squad-triage.yml b/packages/squad-sdk/templates/workflows/squad-triage.yml index d118a2813..8eaf51f65 100644 --- a/packages/squad-sdk/templates/workflows/squad-triage.yml +++ b/packages/squad-sdk/templates/workflows/squad-triage.yml @@ -22,13 +22,9 @@ jobs: const fs = require('fs'); const issue = context.payload.issue; - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot triage'); + core.warning('No .squad/team.md found — cannot triage'); return; } @@ -88,11 +84,7 @@ jobs: } } - // Read routing rules — check .squad/ first, fall back to .ai-team/ - let routingFile = '.squad/routing.md'; - if (!fs.existsSync(routingFile)) { - routingFile = '.ai-team/routing.md'; - } + const routingFile = '.squad/routing.md'; let routingContent = ''; if (fs.existsSync(routingFile)) { routingContent = fs.readFileSync(routingFile, 'utf8'); diff --git a/packages/squad-sdk/templates/workflows/sync-squad-labels.yml b/packages/squad-sdk/templates/workflows/sync-squad-labels.yml index 699fc680f..f3799e793 100644 --- a/packages/squad-sdk/templates/workflows/sync-squad-labels.yml +++ b/packages/squad-sdk/templates/workflows/sync-squad-labels.yml @@ -4,7 +4,6 @@ on: push: paths: - '.squad/team.md' - - '.ai-team/team.md' workflow_dispatch: permissions: @@ -22,13 +21,9 @@ jobs: with: script: | const fs = require('fs'); - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - - if (!fs.existsSync(teamFile)) { - core.info('No .squad/team.md or .ai-team/team.md found — skipping label sync'); + core.info('No .squad/team.md found — skipping label sync'); return; } diff --git a/templates/workflows/squad-heartbeat.yml b/templates/workflows/squad-heartbeat.yml index 5494296fd..3ab647c89 100644 --- a/templates/workflows/squad-heartbeat.yml +++ b/templates/workflows/squad-heartbeat.yml @@ -106,10 +106,7 @@ jobs: script: | const fs = require('fs'); - let teamFile = '.squad/team.md'; - if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) return; const content = fs.readFileSync(teamFile, 'utf8'); @@ -154,7 +151,7 @@ jobs: agent_assignment: { target_repo: `${context.repo.owner}/${context.repo.repo}`, base_branch: repoData.default_branch, - custom_instructions: `Read .squad/team.md (or .ai-team/team.md) for team context and .squad/routing.md (or .ai-team/routing.md) for routing rules.` + custom_instructions: `Read .squad/team.md for team context and .squad/routing.md for routing rules.` } }); core.info(`Assigned copilot-swe-agent[bot] to #${issue.number}`); diff --git a/templates/workflows/squad-issue-assign.yml b/templates/workflows/squad-issue-assign.yml index ad140f42d..f6b664bd8 100644 --- a/templates/workflows/squad-issue-assign.yml +++ b/templates/workflows/squad-issue-assign.yml @@ -27,13 +27,9 @@ jobs: // Extract member name from label (e.g., "squad:ripley" → "ripley") const memberName = label.replace('squad:', '').toLowerCase(); - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot assign work'); + core.warning('No .squad/team.md found — cannot assign work'); return; } @@ -72,7 +68,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, - body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` (or \`.ai-team/team.md\`) for valid member names.` + body: `⚠️ No squad member found matching label \`${label}\`. Check \`.squad/team.md\` for valid member names.` }); return; } diff --git a/templates/workflows/squad-triage.yml b/templates/workflows/squad-triage.yml index d118a2813..8eaf51f65 100644 --- a/templates/workflows/squad-triage.yml +++ b/templates/workflows/squad-triage.yml @@ -22,13 +22,9 @@ jobs: const fs = require('fs'); const issue = context.payload.issue; - // Read team roster — check .squad/ first, fall back to .ai-team/ - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - if (!fs.existsSync(teamFile)) { - core.warning('No .squad/team.md or .ai-team/team.md found — cannot triage'); + core.warning('No .squad/team.md found — cannot triage'); return; } @@ -88,11 +84,7 @@ jobs: } } - // Read routing rules — check .squad/ first, fall back to .ai-team/ - let routingFile = '.squad/routing.md'; - if (!fs.existsSync(routingFile)) { - routingFile = '.ai-team/routing.md'; - } + const routingFile = '.squad/routing.md'; let routingContent = ''; if (fs.existsSync(routingFile)) { routingContent = fs.readFileSync(routingFile, 'utf8'); diff --git a/templates/workflows/sync-squad-labels.yml b/templates/workflows/sync-squad-labels.yml index 699fc680f..f3799e793 100644 --- a/templates/workflows/sync-squad-labels.yml +++ b/templates/workflows/sync-squad-labels.yml @@ -4,7 +4,6 @@ on: push: paths: - '.squad/team.md' - - '.ai-team/team.md' workflow_dispatch: permissions: @@ -22,13 +21,9 @@ jobs: with: script: | const fs = require('fs'); - let teamFile = '.squad/team.md'; + const teamFile = '.squad/team.md'; if (!fs.existsSync(teamFile)) { - teamFile = '.ai-team/team.md'; - } - - if (!fs.existsSync(teamFile)) { - core.info('No .squad/team.md or .ai-team/team.md found — skipping label sync'); + core.info('No .squad/team.md found — skipping label sync'); return; }