Setting the file. One moment. Sync Squad Labels · {skill Name} · microsoft/waza · Skills Docs11.14
Plugin Marketplace
workflows/sync-squad-labels.yml
workflows/sync-squad-labels.yml
YAML·169 lines·7 KB
14jobs:
15 sync-labels:
16 runs-on: ubuntu-latest
17 steps:
18 - uses: actions/checkout@v4
19
20 - name: Parse roster and sync labels
21 uses: actions/github-script@v7
22 with:
23 script: |
24 const fs = require('fs');
25 let teamFile = '.squad/team.md';
26 if (!fs.existsSync(teamFile)) {
27 teamFile = '.ai-team/team.md';
28 }
29
30 if (!fs.existsSync(teamFile)) {
31 core.info('No .squad/team.md or .ai-team/team.md found — skipping label sync');
32 return;
33 }
34
35 const content = fs.readFileSync(teamFile, 'utf8');
36 const lines = content.split('\n');
37
38 // Parse the Members table for agent names
39 const members = [];
40 let inMembersTable = false;
41 for (const line of lines) {
42 if (line.match(/^##\s+(Members|Team Roster)/i)) {
43 inMembersTable = true;
44 continue;
45 }
46 if (inMembersTable && line.startsWith('## ')) {
47 break;
48 }
49 if (inMembersTable && line.startsWith('|') && !line.includes('---') && !line.includes('Name')) {
50 const cells = line.split('|').map(c => c.trim()).filter(Boolean);
51 if (cells.length >= 2 && cells[0] !== 'Scribe') {
52 members.push({
53 name: cells[0],
54 role: cells[1]
55 });
56 }
57 }
58 }
59
60 core.info(`Found ${members.length} squad members: ${members.map(m => m.name).join(', ')}`);
61
62 // Check if @copilot is on the team
63 const hasCopilot = content.includes('🤖 Coding Agent');
64
65 // Define label color palette for squad labels
66 const SQUAD_COLOR = '9B8FCC';
67 const MEMBER_COLOR = '9B8FCC';
68 const COPILOT_COLOR = '10b981';
69
70 // Define go: and release: labels (static)
71 const GO_LABELS = [
72 { name: 'go:yes', color: '0E8A16', description: 'Ready to implement' },
73 { name: 'go:no', color: 'B60205', description: 'Not pursuing' },
74 { name: 'go:needs-research', color: 'FBCA04', description: 'Needs investigation' }
75 ];
76
77 const RELEASE_LABELS = [
78 { name: 'release:v0.4.0', color: '6B8EB5', description: 'Targeted for v0.4.0' },
79 { name: 'release:v0.5.0', color: '6B8EB5', description: 'Targeted for v0.5.0' },
80 { name: 'release:v0.6.0', color: '8B7DB5', description: 'Targeted for v0.6.0' },
81 { name: 'release:v1.0.0', color: '8B7DB5', description: 'Targeted for v1.0.0' },
82 { name: 'release:backlog', color: 'D4E5F7', description: 'Not yet targeted' }
83 ];
84
85 const TYPE_LABELS = [
86 { name: 'type:feature', color: 'DDD1F2', description: 'New capability' },
87 { name: 'type:bug', color: 'FF0422', description: 'Something broken' },
88 { name: 'type:spike', color: 'F2DDD4', description: 'Research/investigation — produces a plan, not code' },
89 { name: 'type:docs', color: 'D4E5F7', description: 'Documentation work' },
90 { name: 'type:chore', color: 'D4E5F7', description: 'Maintenance, refactoring, cleanup' },
91 { name: 'type:epic', color: 'CC4455', description: 'Parent issue that decomposes into sub-issues' }
92 ];
93
94 // High-signal labels — these MUST visually dominate all others
95 const SIGNAL_LABELS = [
96 { name: 'bug', color: 'FF0422', description: 'Something isn\'t working' },
97 { name: 'feedback', color: '00E5FF', description: 'User feedback — high signal, needs attention' }
98 ];
99
100 const PRIORITY_LABELS = [
101 { name: 'priority:p0', color: 'B60205', description: 'Blocking release' },
102 { name: 'priority:p1', color: 'D93F0B', description: 'This sprint' },
103 { name: 'priority:p2', color: 'FBCA04', description: 'Next sprint' }
104 ];
105
106 // Ensure the base "squad" triage label exists
107 const labels = [
108 { name: 'squad', color: SQUAD_COLOR, description: 'Squad triage inbox — Lead will assign to a member' }
109 ];
110
111 for (const member of members) {
112 labels.push({
113 name: `squad:${member.name.toLowerCase()}`,
114 color: MEMBER_COLOR,
115 description: `Assigned to ${member.name} (${member.role})`
116 });
117 }
118
119 // Add @copilot label if coding agent is on the team
120 if (hasCopilot) {
121 labels.push({
122 name: 'squad:copilot',
123 color: COPILOT_COLOR,
124 description: 'Assigned to @copilot (Coding Agent) for autonomous work'
125 });
126 }
127
128 // Add go:, release:, type:, priority:, and high-signal labels
129 labels.push(...GO_LABELS);
130 labels.push(...RELEASE_LABELS);
131 labels.push(...TYPE_LABELS);
132 labels.push(...PRIORITY_LABELS);
133 labels.push(...SIGNAL_LABELS);
134
135 // Sync labels (create or update)
136 for (const label of labels) {
137 try {
138 await github.rest.issues.getLabel({
139 owner: context.repo.owner,
140 repo: context.repo.repo,
141 name: label.name
142 });
143 // Label exists — update it
144 await github.rest.issues.updateLabel({
145 owner: context.repo.owner,
146 repo: context.repo.repo,
147 name: label.name,
148 color: label.color,
149 description: label.description
150 });
151 core.info(`Updated label: ${label.name}`);
152 } catch (err) {
153 if (err.status === 404) {
154 // Label doesn't exist — create it
155 await github.rest.issues.createLabel({
156 owner: context.repo.owner,
157 repo: context.repo.repo,
158 name: label.name,
159 color: label.color,
160 description: label.description
161 });
162 core.info(`Created label: ${label.name}`);
163 } else {
164 throw err;
165 }
166 }
167 }
168
169 core.info(`Label sync complete: ${labels.length} labels synced`);