relay-cc 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +428 -0
- package/agents/relay-codebase-mapper.md +761 -0
- package/agents/relay-debugger.md +1203 -0
- package/agents/relay-estimator.md +257 -0
- package/agents/relay-executor.md +823 -0
- package/agents/relay-plan-checker.md +812 -0
- package/agents/relay-planner.md +1418 -0
- package/agents/relay-reviewer.md +279 -0
- package/agents/relay-ticket-researcher.md +287 -0
- package/agents/relay-verifier.md +778 -0
- package/bin/install.js +1667 -0
- package/commands/relay/add-todo.md +193 -0
- package/commands/relay/check-todos.md +200 -0
- package/commands/relay/debug.md +169 -0
- package/commands/relay/estimate.md +182 -0
- package/commands/relay/help.md +328 -0
- package/commands/relay/history.md +203 -0
- package/commands/relay/map-codebase.md +71 -0
- package/commands/relay/pause-work.md +128 -0
- package/commands/relay/pr.md +223 -0
- package/commands/relay/quick.md +307 -0
- package/commands/relay/resume-work.md +40 -0
- package/commands/relay/resume.md +181 -0
- package/commands/relay/review.md +322 -0
- package/commands/relay/rollback.md +248 -0
- package/commands/relay/set-profile.md +116 -0
- package/commands/relay/settings.md +165 -0
- package/commands/relay/setup.md +247 -0
- package/commands/relay/status.md +131 -0
- package/commands/relay/tickets.md +106 -0
- package/commands/relay/update.md +200 -0
- package/commands/relay/work.md +398 -0
- package/hooks/dist/relay-check-update.js +61 -0
- package/hooks/dist/relay-statusline.js +91 -0
- package/package.json +47 -0
- package/relay/references/checkpoints.md +1078 -0
- package/relay/references/continuation-format.md +249 -0
- package/relay/references/git-integration.md +209 -0
- package/relay/references/model-profiles.md +57 -0
- package/relay/references/planning-config.md +189 -0
- package/relay/references/questioning.md +141 -0
- package/relay/references/tdd.md +263 -0
- package/relay/references/ui-brand.md +162 -0
- package/relay/references/verification-patterns.md +612 -0
- package/relay/templates/DEBUG.md +159 -0
- package/relay/templates/UAT.md +247 -0
- package/relay/templates/analysis.md +101 -0
- package/relay/templates/codebase/architecture.md +255 -0
- package/relay/templates/codebase/concerns.md +310 -0
- package/relay/templates/codebase/conventions.md +307 -0
- package/relay/templates/codebase/integrations.md +280 -0
- package/relay/templates/codebase/stack.md +186 -0
- package/relay/templates/codebase/structure.md +285 -0
- package/relay/templates/codebase/testing.md +480 -0
- package/relay/templates/config.json +40 -0
- package/relay/templates/context.md +283 -0
- package/relay/templates/continue-here.md +78 -0
- package/relay/templates/debug-subagent-prompt.md +91 -0
- package/relay/templates/estimate.md +108 -0
- package/relay/templates/phase-prompt.md +567 -0
- package/relay/templates/planner-subagent-prompt.md +117 -0
- package/relay/templates/research.md +552 -0
- package/relay/templates/state.md +127 -0
- package/relay/templates/summary.md +246 -0
- package/relay/templates/verification-report.md +322 -0
- package/relay/workflows/analyze-ticket.md +42 -0
- package/relay/workflows/diagnose-issues.md +231 -0
- package/relay/workflows/execute-phase.md +700 -0
- package/relay/workflows/execute-plan.md +1851 -0
- package/relay/workflows/map-codebase.md +357 -0
- package/relay/workflows/resume-project.md +307 -0
- package/relay/workflows/sync-ticket.md +58 -0
- package/relay/workflows/verify-phase.md +628 -0
- package/relay/workflows/verify-ticket.md +596 -0
- package/scripts/build-hooks.js +42 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: relay:review
|
|
3
|
+
description: Review a PR or address review comments on your own PR
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Edit
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- Task
|
|
12
|
+
- AskUserQuestion
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<objective>
|
|
16
|
+
Two modes:
|
|
17
|
+
- **Mode A — Review a PR**: Analyze someone else's PR with a code review agent
|
|
18
|
+
- **Mode B — Address comments**: Fix review comments on your own PR
|
|
19
|
+
|
|
20
|
+
Selected upfront via user choice.
|
|
21
|
+
</objective>
|
|
22
|
+
|
|
23
|
+
<context>
|
|
24
|
+
@.relay/config.json
|
|
25
|
+
@.relay/STATE.md
|
|
26
|
+
</context>
|
|
27
|
+
|
|
28
|
+
<process>
|
|
29
|
+
|
|
30
|
+
## 0. Pre-flight
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
test -f .relay/config.json && echo "config exists" || echo "no config"
|
|
34
|
+
command -v gh >/dev/null 2>&1 && echo "gh available" || echo "gh missing"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If no config: suggest `/relay:setup` and STOP.
|
|
38
|
+
If `gh` CLI not available: report that `gh` is required and STOP.
|
|
39
|
+
|
|
40
|
+
Read model profile:
|
|
41
|
+
```bash
|
|
42
|
+
MODEL_PROFILE=$(cat .relay/config.json 2>/dev/null | grep -o '"model_profile"[[:space:]]*:[[:space:]]*"[^"]*"' | grep -o '"[^"]*"$' | tr -d '"' || echo "balanced")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Model lookup table:**
|
|
46
|
+
|
|
47
|
+
| Agent | quality | balanced | budget |
|
|
48
|
+
|-------|---------|----------|--------|
|
|
49
|
+
| relay-reviewer | opus | sonnet | sonnet |
|
|
50
|
+
|
|
51
|
+
## 1. Choose Mode
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
AskUserQuestion(
|
|
55
|
+
header: "Review",
|
|
56
|
+
question: "What would you like to do?",
|
|
57
|
+
options: [
|
|
58
|
+
{ label: "Review a PR", description: "Analyze someone else's PR and provide code review" },
|
|
59
|
+
{ label: "Address comments", description: "Fix review comments on your own PR" }
|
|
60
|
+
]
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Mode A — Review a PR
|
|
67
|
+
|
|
68
|
+
### A1. List Open PRs
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
gh pr list --state open --limit 20
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If no open PRs: report and STOP.
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
AskUserQuestion(
|
|
78
|
+
header: "PR",
|
|
79
|
+
question: "Which PR would you like to review?",
|
|
80
|
+
options: [
|
|
81
|
+
{ label: "#${PR_1_NUM}", description: "${PR_1_TITLE}" },
|
|
82
|
+
{ label: "#${PR_2_NUM}", description: "${PR_2_TITLE}" },
|
|
83
|
+
{ label: "#${PR_3_NUM}", description: "${PR_3_TITLE}" }
|
|
84
|
+
]
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### A2. Save Current Branch and Checkout PR
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
ORIGINAL_BRANCH=$(git branch --show-current)
|
|
92
|
+
git fetch origin
|
|
93
|
+
gh pr checkout ${PR_NUMBER}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### A3. Get Diff
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
BASE_BRANCH=$(gh pr view ${PR_NUMBER} --json baseRefName --jq '.baseRefName')
|
|
100
|
+
git diff ${BASE_BRANCH}...HEAD --stat
|
|
101
|
+
git diff ${BASE_BRANCH}...HEAD
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### A4. Spawn Reviewer Agent
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
mkdir -p .relay/reviews
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Task(
|
|
112
|
+
prompt="
|
|
113
|
+
<pr>
|
|
114
|
+
Number: ${PR_NUMBER}
|
|
115
|
+
Title: ${PR_TITLE}
|
|
116
|
+
Author: ${PR_AUTHOR}
|
|
117
|
+
Base: ${BASE_BRANCH}
|
|
118
|
+
Description: ${PR_DESCRIPTION}
|
|
119
|
+
|
|
120
|
+
<diff>
|
|
121
|
+
${DIFF_CONTENT}
|
|
122
|
+
</diff>
|
|
123
|
+
|
|
124
|
+
<files_changed>
|
|
125
|
+
${DIFF_STAT}
|
|
126
|
+
</files_changed>
|
|
127
|
+
</pr>
|
|
128
|
+
|
|
129
|
+
<codebase_context>
|
|
130
|
+
@.relay/codebase/ARCHITECTURE.md (if exists)
|
|
131
|
+
@.relay/codebase/CONVENTIONS.md (if exists)
|
|
132
|
+
@.relay/codebase/TESTING.md (if exists)
|
|
133
|
+
</codebase_context>
|
|
134
|
+
|
|
135
|
+
<output>
|
|
136
|
+
Write review to: .relay/reviews/PR-${PR_NUMBER}-review.md
|
|
137
|
+
</output>
|
|
138
|
+
",
|
|
139
|
+
subagent_type="relay-reviewer",
|
|
140
|
+
model="{reviewer_model}",
|
|
141
|
+
description="Review PR #${PR_NUMBER}"
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### A5. Display Review and Offer Actions
|
|
146
|
+
|
|
147
|
+
Read `.relay/reviews/PR-${PR_NUMBER}-review.md` and display summary.
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
151
|
+
Relay ► REVIEW COMPLETE — PR #${PR_NUMBER}
|
|
152
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
153
|
+
|
|
154
|
+
Recommendation: ${APPROVE | COMMENT | REQUEST_CHANGES}
|
|
155
|
+
Critical: ${COUNT}
|
|
156
|
+
Suggestions: ${COUNT}
|
|
157
|
+
|
|
158
|
+
Full review: .relay/reviews/PR-${PR_NUMBER}-review.md
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
AskUserQuestion(
|
|
163
|
+
header: "Action",
|
|
164
|
+
question: "What would you like to do with this review?",
|
|
165
|
+
options: [
|
|
166
|
+
{ label: "Post as PR comment", description: "Submit review via gh pr review" },
|
|
167
|
+
{ label: "View full review", description: "Display the complete review document" },
|
|
168
|
+
{ label: "Done", description: "Return to original branch" }
|
|
169
|
+
]
|
|
170
|
+
)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**If "Post as PR comment":**
|
|
174
|
+
```bash
|
|
175
|
+
gh pr review ${PR_NUMBER} --body "$(cat .relay/reviews/PR-${PR_NUMBER}-review.md)" --comment
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### A6. Restore Original Branch
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git checkout "${ORIGINAL_BRANCH}"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Always restore the original branch, regardless of action taken.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Mode B — Address PR Comments
|
|
189
|
+
|
|
190
|
+
### B1. List Your Open PRs
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
gh pr list --state open --author @me --limit 20
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
If no open PRs: report and STOP.
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
AskUserQuestion(
|
|
200
|
+
header: "PR",
|
|
201
|
+
question: "Which PR has comments to address?",
|
|
202
|
+
options: [
|
|
203
|
+
{ label: "#${PR_1_NUM}", description: "${PR_1_TITLE}" },
|
|
204
|
+
{ label: "#${PR_2_NUM}", description: "${PR_2_TITLE}" },
|
|
205
|
+
{ label: "#${PR_3_NUM}", description: "${PR_3_TITLE}" }
|
|
206
|
+
]
|
|
207
|
+
)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### B2. Fetch Review Comments
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
|
|
214
|
+
gh api repos/${REPO}/pulls/${PR_NUMBER}/comments --jq '.[] | {path: .path, line: .line, body: .body, user: .user.login}'
|
|
215
|
+
gh api repos/${REPO}/pulls/${PR_NUMBER}/reviews --jq '.[] | select(.state != "APPROVED") | {body: .body, user: .user.login, state: .state}'
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### B3. Display Comments Grouped by File
|
|
219
|
+
|
|
220
|
+
Group comments by file path and display:
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
## Review Comments for PR #${PR_NUMBER}
|
|
224
|
+
|
|
225
|
+
### ${FILE_1}
|
|
226
|
+
- Line ${LINE}: ${COMMENT_BODY} (by ${USER})
|
|
227
|
+
|
|
228
|
+
### ${FILE_2}
|
|
229
|
+
- Line ${LINE}: ${COMMENT_BODY} (by ${USER})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### B4. Choose What to Address
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
AskUserQuestion(
|
|
236
|
+
header: "Comments",
|
|
237
|
+
question: "Which comments would you like to address?",
|
|
238
|
+
options: [
|
|
239
|
+
{ label: "All comments", description: "Address every review comment" },
|
|
240
|
+
{ label: "Select specific", description: "Choose which comments to fix" },
|
|
241
|
+
{ label: "View only", description: "Just review the comments, don't change code" }
|
|
242
|
+
]
|
|
243
|
+
)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
If "View only": display and STOP.
|
|
247
|
+
|
|
248
|
+
If "Select specific": let user pick which comments to address.
|
|
249
|
+
|
|
250
|
+
### B5. Checkout PR Branch and Fix
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
gh pr checkout ${PR_NUMBER}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
For each comment to address:
|
|
257
|
+
1. Read the file at the mentioned line
|
|
258
|
+
2. Understand the feedback
|
|
259
|
+
3. Make the code change using Edit
|
|
260
|
+
4. Verify the fix
|
|
261
|
+
|
|
262
|
+
### B6. Commit Fixes
|
|
263
|
+
|
|
264
|
+
For each file changed, commit with descriptive message:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
# Detect ticket ID from branch name or PR title
|
|
268
|
+
TICKET_ID=$(git branch --show-current | grep -oE '[A-Z]+-[0-9]+' | head -1)
|
|
269
|
+
TICKET_ID=${TICKET_ID:-review}
|
|
270
|
+
|
|
271
|
+
git add ${CHANGED_FILE}
|
|
272
|
+
git commit -m "fix(${TICKET_ID}): address review — ${DESCRIPTION}"
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### B7. Offer to Push
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
AskUserQuestion(
|
|
279
|
+
header: "Push",
|
|
280
|
+
question: "Push fixes to update the PR?",
|
|
281
|
+
options: [
|
|
282
|
+
{ label: "Push", description: "Push commits to update PR #${PR_NUMBER}" },
|
|
283
|
+
{ label: "Skip", description: "Keep changes local for now" }
|
|
284
|
+
]
|
|
285
|
+
)
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
If "Push":
|
|
289
|
+
```bash
|
|
290
|
+
git push
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
295
|
+
Relay ► COMMENTS ADDRESSED — PR #${PR_NUMBER}
|
|
296
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
297
|
+
|
|
298
|
+
Comments addressed: ${COUNT}
|
|
299
|
+
Commits: ${COMMIT_COUNT}
|
|
300
|
+
Pushed: ${YES/NO}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
</process>
|
|
304
|
+
|
|
305
|
+
<success_criteria>
|
|
306
|
+
**Mode A:**
|
|
307
|
+
- [ ] PR selected from open PRs
|
|
308
|
+
- [ ] Original branch saved
|
|
309
|
+
- [ ] PR branch checked out
|
|
310
|
+
- [ ] Diff captured
|
|
311
|
+
- [ ] Reviewer agent produced structured review
|
|
312
|
+
- [ ] Review displayed with recommendation
|
|
313
|
+
- [ ] Action taken (post, view, or skip)
|
|
314
|
+
- [ ] Original branch restored
|
|
315
|
+
|
|
316
|
+
**Mode B:**
|
|
317
|
+
- [ ] User's PR selected
|
|
318
|
+
- [ ] Review comments fetched and displayed
|
|
319
|
+
- [ ] Selected comments addressed with code changes
|
|
320
|
+
- [ ] Each fix committed with descriptive message
|
|
321
|
+
- [ ] Pushed if requested
|
|
322
|
+
</success_criteria>
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: relay:rollback
|
|
3
|
+
description: Safely revert work done on a specific ticket
|
|
4
|
+
argument-hint: <ticket-id>
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- AskUserQuestion
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<objective>
|
|
15
|
+
Safely revert ticket work using `git revert` (creates new commits — no history rewriting).
|
|
16
|
+
|
|
17
|
+
Destructive action — requires explicit user confirmation before executing.
|
|
18
|
+
</objective>
|
|
19
|
+
|
|
20
|
+
<context>
|
|
21
|
+
@.relay/STATE.md
|
|
22
|
+
Ticket ID: $ARGUMENTS
|
|
23
|
+
</context>
|
|
24
|
+
|
|
25
|
+
<process>
|
|
26
|
+
|
|
27
|
+
## 0. Pre-flight
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
test -f .relay/config.json && echo "config exists" || echo "no config"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If no config: suggest `/relay:setup` and STOP.
|
|
34
|
+
|
|
35
|
+
If no $ARGUMENTS:
|
|
36
|
+
```
|
|
37
|
+
AskUserQuestion(
|
|
38
|
+
header: "Ticket",
|
|
39
|
+
question: "Which ticket's work would you like to rollback?",
|
|
40
|
+
options: [
|
|
41
|
+
{ label: "Enter ID", description: "Type a ticket ID (e.g., PROJ-123)" },
|
|
42
|
+
{ label: "Cancel", description: "Don't rollback anything" }
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 1. Find Ticket Commits
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git log --oneline --all --grep="${TICKET_ID}"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If no commits found:
|
|
54
|
+
```
|
|
55
|
+
No commits found for ${TICKET_ID}.
|
|
56
|
+
```
|
|
57
|
+
STOP.
|
|
58
|
+
|
|
59
|
+
## 2. Display Commits and Files
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
63
|
+
Relay ► ROLLBACK — ${TICKET_ID}
|
|
64
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Show commits:
|
|
68
|
+
```bash
|
|
69
|
+
git log --oneline --all --grep="${TICKET_ID}" --format="%h %s (%ai)"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Show files affected:
|
|
73
|
+
```bash
|
|
74
|
+
git log --all --grep="${TICKET_ID}" --name-only --format="" | sort -u
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Count total:
|
|
78
|
+
```bash
|
|
79
|
+
COMMIT_COUNT=$(git log --oneline --all --grep="${TICKET_ID}" | wc -l | tr -d ' ')
|
|
80
|
+
FILE_COUNT=$(git log --all --grep="${TICKET_ID}" --name-only --format="" | sort -u | wc -l | tr -d ' ')
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Found ${COMMIT_COUNT} commits affecting ${FILE_COUNT} files.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 3. Check for Interleaved Commits
|
|
88
|
+
|
|
89
|
+
Check if other work is interleaved with ticket commits:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Get the range of ticket commits
|
|
93
|
+
FIRST_COMMIT=$(git log --oneline --all --grep="${TICKET_ID}" --format="%H" | tail -1)
|
|
94
|
+
LAST_COMMIT=$(git log --oneline --all --grep="${TICKET_ID}" --format="%H" | head -1)
|
|
95
|
+
|
|
96
|
+
# Check for non-ticket commits in that range
|
|
97
|
+
git log --oneline ${FIRST_COMMIT}..${LAST_COMMIT} | grep -v "${TICKET_ID}"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If interleaved commits exist, warn:
|
|
101
|
+
```
|
|
102
|
+
WARNING: Other commits exist between ${TICKET_ID} commits.
|
|
103
|
+
Reverting may cause conflicts. Consider selective revert.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## 4. Choose Rollback Mode
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
AskUserQuestion(
|
|
110
|
+
header: "Mode",
|
|
111
|
+
question: "How would you like to rollback ${TICKET_ID}? (${COMMIT_COUNT} commits, ${FILE_COUNT} files)",
|
|
112
|
+
options: [
|
|
113
|
+
{ label: "Full revert", description: "Revert all ${COMMIT_COUNT} commits for ${TICKET_ID}" },
|
|
114
|
+
{ label: "Selective revert", description: "Choose which commits to revert" },
|
|
115
|
+
{ label: "Soft rollback", description: "Just switch to main branch (no revert commits)" },
|
|
116
|
+
{ label: "Cancel", description: "Don't rollback" }
|
|
117
|
+
]
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
If "Cancel": STOP.
|
|
122
|
+
|
|
123
|
+
### Soft Rollback
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
BASE_BRANCH=$(git remote show origin 2>/dev/null | grep 'HEAD branch' | sed 's/.*: //')
|
|
127
|
+
BASE_BRANCH=${BASE_BRANCH:-main}
|
|
128
|
+
git checkout "${BASE_BRANCH}"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Skip to step 6.
|
|
132
|
+
|
|
133
|
+
### Selective Revert
|
|
134
|
+
|
|
135
|
+
Display commits numbered for selection:
|
|
136
|
+
```bash
|
|
137
|
+
git log --oneline --all --grep="${TICKET_ID}" --format="%h %s"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Ask user which commits to revert (by hash or number).
|
|
141
|
+
|
|
142
|
+
### Full Revert / Selective Revert
|
|
143
|
+
|
|
144
|
+
Continue to step 5.
|
|
145
|
+
|
|
146
|
+
## 5. Confirm and Execute
|
|
147
|
+
|
|
148
|
+
**Explicit confirmation required:**
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
AskUserQuestion(
|
|
152
|
+
header: "Confirm",
|
|
153
|
+
question: "This will create revert commits for ${REVERT_COUNT} commits. This cannot be easily undone. Proceed?",
|
|
154
|
+
options: [
|
|
155
|
+
{ label: "Revert", description: "Execute git revert for selected commits" },
|
|
156
|
+
{ label: "Cancel", description: "Abort rollback" }
|
|
157
|
+
]
|
|
158
|
+
)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
If "Cancel": STOP.
|
|
162
|
+
|
|
163
|
+
**Execute reverts (newest first):**
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Get commits in reverse chronological order (newest first)
|
|
167
|
+
COMMITS=$(git log --oneline --all --grep="${TICKET_ID}" --format="%H")
|
|
168
|
+
|
|
169
|
+
for COMMIT in ${COMMITS}; do
|
|
170
|
+
git revert --no-edit ${COMMIT} || {
|
|
171
|
+
echo "Conflict during revert of ${COMMIT}"
|
|
172
|
+
echo "Resolve conflicts and run: git revert --continue"
|
|
173
|
+
break
|
|
174
|
+
}
|
|
175
|
+
done
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
If conflicts occur, display:
|
|
179
|
+
```
|
|
180
|
+
Conflict encountered while reverting ${COMMIT_HASH}.
|
|
181
|
+
|
|
182
|
+
Conflicting files:
|
|
183
|
+
$(git diff --name-only --diff-filter=U)
|
|
184
|
+
|
|
185
|
+
Options:
|
|
186
|
+
1. Resolve conflicts manually, then run: git revert --continue
|
|
187
|
+
2. Abort the rollback: git revert --abort
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## 6. Handle Artifacts
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
AskUserQuestion(
|
|
194
|
+
header: "Artifacts",
|
|
195
|
+
question: "What should happen to the ticket artifacts in .relay/tickets/${TICKET_ID}/?",
|
|
196
|
+
options: [
|
|
197
|
+
{ label: "Archive", description: "Move to .relay/tickets/${TICKET_ID}/.archived/" },
|
|
198
|
+
{ label: "Delete", description: "Remove all ticket artifacts" },
|
|
199
|
+
{ label: "Keep", description: "Leave artifacts as-is" }
|
|
200
|
+
]
|
|
201
|
+
)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Archive:**
|
|
205
|
+
```bash
|
|
206
|
+
mkdir -p .relay/tickets/${TICKET_ID}/.archived
|
|
207
|
+
mv .relay/tickets/${TICKET_ID}/*.md .relay/tickets/${TICKET_ID}/.archived/ 2>/dev/null
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Delete:**
|
|
211
|
+
```bash
|
|
212
|
+
rm -rf .relay/tickets/${TICKET_ID}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Keep:** No action.
|
|
216
|
+
|
|
217
|
+
## 7. Update State
|
|
218
|
+
|
|
219
|
+
Update STATE.md:
|
|
220
|
+
- Clear active ticket if it was the rolled-back ticket
|
|
221
|
+
- Add note to recent tickets: "reverted"
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
225
|
+
Relay ► ROLLBACK COMPLETE — ${TICKET_ID}
|
|
226
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
227
|
+
|
|
228
|
+
Reverted: ${REVERT_COUNT} commits
|
|
229
|
+
Artifacts: ${archived/deleted/kept}
|
|
230
|
+
|
|
231
|
+
## Next Steps
|
|
232
|
+
|
|
233
|
+
- `/relay:tickets` — browse available tickets
|
|
234
|
+
- `/relay:status` — check current state
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
</process>
|
|
238
|
+
|
|
239
|
+
<success_criteria>
|
|
240
|
+
- [ ] Ticket commits found and displayed
|
|
241
|
+
- [ ] Interleaved commits warned about
|
|
242
|
+
- [ ] User chose rollback mode
|
|
243
|
+
- [ ] Explicit confirmation obtained before revert
|
|
244
|
+
- [ ] `git revert --no-edit` executed for selected commits (newest first)
|
|
245
|
+
- [ ] Conflicts handled gracefully if they occur
|
|
246
|
+
- [ ] Artifacts archived, deleted, or kept per user choice
|
|
247
|
+
- [ ] STATE.md updated (active ticket cleared, marked as reverted)
|
|
248
|
+
</success_criteria>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: set-profile
|
|
3
|
+
description: Switch model profile for Relay agents (quality/balanced/budget)
|
|
4
|
+
arguments:
|
|
5
|
+
- name: profile
|
|
6
|
+
description: "Profile name: quality, balanced, or budget"
|
|
7
|
+
required: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<objective>
|
|
11
|
+
Switch the model profile used by Relay agents. This controls which Claude model each agent uses, balancing quality vs token spend.
|
|
12
|
+
</objective>
|
|
13
|
+
|
|
14
|
+
<profiles>
|
|
15
|
+
| Profile | Description |
|
|
16
|
+
|---------|-------------|
|
|
17
|
+
| **quality** | Opus everywhere except read-only verification |
|
|
18
|
+
| **balanced** | Opus for planning, Sonnet for execution/verification (default) |
|
|
19
|
+
| **budget** | Sonnet for writing, Haiku for research/verification |
|
|
20
|
+
</profiles>
|
|
21
|
+
|
|
22
|
+
<process>
|
|
23
|
+
|
|
24
|
+
## 1. Validate argument
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
if $ARGUMENTS.profile not in ["quality", "balanced", "budget"]:
|
|
28
|
+
Error: Invalid profile "$ARGUMENTS.profile"
|
|
29
|
+
Valid profiles: quality, balanced, budget
|
|
30
|
+
STOP
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 2. Ensure config exists
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
ls .relay/config.json 2>/dev/null
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
If `.relay/config.json` missing, create it with defaults:
|
|
40
|
+
```bash
|
|
41
|
+
mkdir -p .relay
|
|
42
|
+
```
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"model_profile": "balanced",
|
|
46
|
+
"workflow": {
|
|
47
|
+
"research": true,
|
|
48
|
+
"plan_check": true,
|
|
49
|
+
"verifier": true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
Write this to `.relay/config.json`, then continue.
|
|
54
|
+
|
|
55
|
+
## 3. Update config.json
|
|
56
|
+
|
|
57
|
+
Read current config:
|
|
58
|
+
```bash
|
|
59
|
+
cat .relay/config.json
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Update `model_profile` field:
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"model_profile": "$ARGUMENTS.profile"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Write updated config back to `.relay/config.json`.
|
|
70
|
+
|
|
71
|
+
## 4. Confirm
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
✓ Model profile set to: $ARGUMENTS.profile
|
|
75
|
+
|
|
76
|
+
Agents will now use:
|
|
77
|
+
[Show table from model-profiles.md for selected profile]
|
|
78
|
+
|
|
79
|
+
Next spawned agents will use the new profile.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
</process>
|
|
83
|
+
|
|
84
|
+
<examples>
|
|
85
|
+
|
|
86
|
+
**Switch to budget mode:**
|
|
87
|
+
```
|
|
88
|
+
/relay:set-profile budget
|
|
89
|
+
|
|
90
|
+
✓ Model profile set to: budget
|
|
91
|
+
|
|
92
|
+
Agents will now use:
|
|
93
|
+
| Agent | Model |
|
|
94
|
+
|-------|-------|
|
|
95
|
+
| relay-planner | sonnet |
|
|
96
|
+
| relay-executor | sonnet |
|
|
97
|
+
| relay-verifier | haiku |
|
|
98
|
+
| ... | ... |
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Switch to quality mode:**
|
|
102
|
+
```
|
|
103
|
+
/relay:set-profile quality
|
|
104
|
+
|
|
105
|
+
✓ Model profile set to: quality
|
|
106
|
+
|
|
107
|
+
Agents will now use:
|
|
108
|
+
| Agent | Model |
|
|
109
|
+
|-------|-------|
|
|
110
|
+
| relay-planner | opus |
|
|
111
|
+
| relay-executor | opus |
|
|
112
|
+
| relay-verifier | sonnet |
|
|
113
|
+
| ... | ... |
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
</examples>
|