awesome-slash 2.4.2
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/.claude-plugin/marketplace.json +54 -0
- package/.claude-plugin/plugin.json +11 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +261 -0
- package/LICENSE +21 -0
- package/README.md +363 -0
- package/SECURITY.md +101 -0
- package/adapters/README.md +256 -0
- package/adapters/codex/README.md +272 -0
- package/adapters/codex/install.sh +179 -0
- package/adapters/opencode/README.md +301 -0
- package/adapters/opencode/install.sh +223 -0
- package/lib/patterns/review-patterns.js +511 -0
- package/lib/patterns/slop-patterns.js +647 -0
- package/lib/platform/detect-platform.js +535 -0
- package/lib/platform/verify-tools.js +235 -0
- package/lib/state/workflow-state.js +635 -0
- package/lib/state/workflow-state.schema.json +282 -0
- package/lib/utils/context-optimizer.js +227 -0
- package/mcp-server/index.js +303 -0
- package/mcp-server/package.json +23 -0
- package/package.json +63 -0
- package/plugins/deslop-around/.claude-plugin/plugin.json +20 -0
- package/plugins/deslop-around/commands/deslop-around.md +220 -0
- package/plugins/deslop-around/lib/patterns/review-patterns.js +511 -0
- package/plugins/deslop-around/lib/patterns/slop-patterns.js +641 -0
- package/plugins/deslop-around/lib/platform/detect-platform.js +514 -0
- package/plugins/deslop-around/lib/platform/verify-tools.js +235 -0
- package/plugins/deslop-around/lib/state/workflow-state.js +635 -0
- package/plugins/deslop-around/lib/state/workflow-state.schema.json +282 -0
- package/plugins/deslop-around/lib/utils/context-optimizer.js +222 -0
- package/plugins/next-task/.claude-plugin/plugin.json +24 -0
- package/plugins/next-task/agents/ci-fixer.md +236 -0
- package/plugins/next-task/agents/ci-monitor.md +291 -0
- package/plugins/next-task/agents/delivery-validator.md +451 -0
- package/plugins/next-task/agents/deslop-work.md +272 -0
- package/plugins/next-task/agents/docs-updater.md +506 -0
- package/plugins/next-task/agents/exploration-agent.md +277 -0
- package/plugins/next-task/agents/implementation-agent.md +427 -0
- package/plugins/next-task/agents/planning-agent.md +236 -0
- package/plugins/next-task/agents/policy-selector.md +248 -0
- package/plugins/next-task/agents/review-orchestrator.md +521 -0
- package/plugins/next-task/agents/simple-fixer.md +136 -0
- package/plugins/next-task/agents/task-discoverer.md +357 -0
- package/plugins/next-task/agents/test-coverage-checker.md +447 -0
- package/plugins/next-task/agents/worktree-manager.md +419 -0
- package/plugins/next-task/commands/delivery-approval.md +331 -0
- package/plugins/next-task/commands/next-task.md +627 -0
- package/plugins/next-task/commands/update-docs-around.md +418 -0
- package/plugins/next-task/hooks/hooks.json +14 -0
- package/plugins/next-task/lib/patterns/review-patterns.js +511 -0
- package/plugins/next-task/lib/patterns/slop-patterns.js +641 -0
- package/plugins/next-task/lib/platform/detect-platform.js +514 -0
- package/plugins/next-task/lib/platform/verify-tools.js +235 -0
- package/plugins/next-task/lib/state/tasks-registry.schema.json +85 -0
- package/plugins/next-task/lib/state/workflow-state.js +635 -0
- package/plugins/next-task/lib/state/workflow-state.schema.json +282 -0
- package/plugins/next-task/lib/state/worktree-status.schema.json +219 -0
- package/plugins/next-task/lib/utils/context-optimizer.js +222 -0
- package/plugins/project-review/.claude-plugin/plugin.json +20 -0
- package/plugins/project-review/commands/project-review-agents.md +286 -0
- package/plugins/project-review/commands/project-review-github.md +142 -0
- package/plugins/project-review/commands/project-review.md +273 -0
- package/plugins/project-review/lib/patterns/review-patterns.js +511 -0
- package/plugins/project-review/lib/patterns/slop-patterns.js +641 -0
- package/plugins/project-review/lib/platform/detect-platform.js +514 -0
- package/plugins/project-review/lib/platform/verify-tools.js +235 -0
- package/plugins/project-review/lib/state/workflow-state.js +635 -0
- package/plugins/project-review/lib/state/workflow-state.schema.json +282 -0
- package/plugins/project-review/lib/utils/context-optimizer.js +222 -0
- package/plugins/reality-check/.claude-plugin/plugin.json +23 -0
- package/plugins/reality-check/README.md +156 -0
- package/plugins/reality-check/agents/code-explorer.md +353 -0
- package/plugins/reality-check/agents/doc-analyzer.md +337 -0
- package/plugins/reality-check/agents/issue-scanner.md +231 -0
- package/plugins/reality-check/agents/plan-synthesizer.md +479 -0
- package/plugins/reality-check/commands/scan.md +242 -0
- package/plugins/reality-check/commands/set.md +203 -0
- package/plugins/reality-check/lib/state/reality-check-state.js +509 -0
- package/plugins/reality-check/skills/reality-analysis/SKILL.md +317 -0
- package/plugins/ship/.claude-plugin/plugin.json +21 -0
- package/plugins/ship/commands/ship-ci-review-loop.md +443 -0
- package/plugins/ship/commands/ship-deployment.md +330 -0
- package/plugins/ship/commands/ship-error-handling.md +254 -0
- package/plugins/ship/commands/ship.md +370 -0
- package/plugins/ship/lib/patterns/review-patterns.js +511 -0
- package/plugins/ship/lib/patterns/slop-patterns.js +641 -0
- package/plugins/ship/lib/platform/detect-platform.js +514 -0
- package/plugins/ship/lib/platform/verify-tools.js +235 -0
- package/plugins/ship/lib/state/workflow-state.js +635 -0
- package/plugins/ship/lib/state/workflow-state.schema.json +282 -0
- package/plugins/ship/lib/utils/context-optimizer.js +222 -0
- package/scripts/install/claude.sh +50 -0
- package/scripts/install/codex.sh +181 -0
- package/scripts/install/opencode.sh +211 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# Phase 4: CI & Review Monitor Loop - Reference
|
|
2
|
+
|
|
3
|
+
This file contains detailed implementation for the CI & Review Monitor Loop phase of `/ship`.
|
|
4
|
+
|
|
5
|
+
**Parent document**: `ship.md`
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The monitor loop waits for:
|
|
10
|
+
1. CI to pass
|
|
11
|
+
2. ALL comments resolved (addressed or replied to)
|
|
12
|
+
3. No "changes requested" reviews remain
|
|
13
|
+
|
|
14
|
+
## Why ALL Comments Matter
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
╔══════════════════════════════════════════════════════════════════════════╗
|
|
18
|
+
║ EVERY COMMENT MUST BE ADDRESSED ║
|
|
19
|
+
╠══════════════════════════════════════════════════════════════════════════╣
|
|
20
|
+
║ ║
|
|
21
|
+
║ • Critical/High issues → Fix immediately ║
|
|
22
|
+
║ • Medium issues → Fix (don't defer) ║
|
|
23
|
+
║ • Minor/Nit issues → Fix (shows attention to quality) ║
|
|
24
|
+
║ • Style suggestions → Fix (maintains codebase consistency) ║
|
|
25
|
+
║ • Questions → Answer with explanation ║
|
|
26
|
+
║ • False positives → Reply explaining why, then resolve ║
|
|
27
|
+
║ • Not relevant → Reply explaining why, then resolve ║
|
|
28
|
+
║ ║
|
|
29
|
+
║ NEVER ignore a comment. NEVER leave comments unresolved. ║
|
|
30
|
+
║ A clean PR has ZERO unresolved conversations. ║
|
|
31
|
+
║ ║
|
|
32
|
+
╚══════════════════════════════════════════════════════════════════════════╝
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## The Monitor Loop Algorithm
|
|
36
|
+
|
|
37
|
+
> **Note:** The JavaScript below is **conceptual pseudocode** showing the algorithm flow.
|
|
38
|
+
> Implement using bash functions defined in this file.
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
const MAX_ITERATIONS = 10; // Safety limit
|
|
42
|
+
const INITIAL_WAIT_MS = 180000; // 3 minutes - wait for auto-reviews
|
|
43
|
+
const ITERATION_WAIT_MS = 30000; // 30 seconds between iterations
|
|
44
|
+
let iteration = 0;
|
|
45
|
+
|
|
46
|
+
while (iteration < MAX_ITERATIONS) {
|
|
47
|
+
iteration++;
|
|
48
|
+
console.log(`\n## CI & Review Monitor - Iteration ${iteration}`);
|
|
49
|
+
|
|
50
|
+
// Step 1: Wait for CI to complete
|
|
51
|
+
const ciStatus = await waitForCI();
|
|
52
|
+
if (ciStatus === 'failed') {
|
|
53
|
+
await fixCIFailures();
|
|
54
|
+
continue; // Push fix, re-run CI
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Step 1.5: First iteration only - wait for auto-reviews
|
|
58
|
+
if (iteration === 1) {
|
|
59
|
+
console.log("Waiting 3 minutes for auto-reviews...");
|
|
60
|
+
await sleep(INITIAL_WAIT_MS);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Step 2: Check for PR comments and reviews
|
|
64
|
+
const feedback = await checkPRFeedback();
|
|
65
|
+
|
|
66
|
+
if (feedback.unresolvedCount === 0 && !feedback.changesRequested) {
|
|
67
|
+
console.log("✓ CI passed, all comments resolved");
|
|
68
|
+
break; // Ready to merge!
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Step 3: Address ALL feedback
|
|
72
|
+
await addressAllFeedback(PR_NUMBER);
|
|
73
|
+
|
|
74
|
+
// Step 4: Push fixes
|
|
75
|
+
if (feedback.hasCodeChanges) {
|
|
76
|
+
await commitAndPush(`fix: address review feedback (iteration ${iteration})`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Step 5: Sleep before next check
|
|
80
|
+
await sleep(ITERATION_WAIT_MS);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Step 1: Wait for CI
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
wait_for_ci() {
|
|
88
|
+
echo "Waiting for CI checks..."
|
|
89
|
+
|
|
90
|
+
while true; do
|
|
91
|
+
CHECKS=$(gh pr checks $PR_NUMBER --json name,state,conclusion 2>/dev/null || echo "[]")
|
|
92
|
+
|
|
93
|
+
PENDING=$(echo "$CHECKS" | jq '[.[] | select(.state | IN("pending", "queued", "in_progress"))] | length')
|
|
94
|
+
FAILED=$(echo "$CHECKS" | jq '[.[] | select(.conclusion | IN("failure", "cancelled"))] | length')
|
|
95
|
+
PASSED=$(echo "$CHECKS" | jq '[.[] | select(.conclusion=="success")] | length')
|
|
96
|
+
|
|
97
|
+
if [ "$FAILED" -gt 0 ]; then
|
|
98
|
+
echo "✗ CI failed ($FAILED checks)"
|
|
99
|
+
gh pr checks $PR_NUMBER
|
|
100
|
+
return 1
|
|
101
|
+
elif [ "$PENDING" -eq 0 ] && [ "$PASSED" -gt 0 ]; then
|
|
102
|
+
echo "✓ CI passed ($PASSED checks)"
|
|
103
|
+
return 0
|
|
104
|
+
elif [ "$PENDING" -eq 0 ] && [ "$PASSED" -eq 0 ]; then
|
|
105
|
+
echo "⚠ No CI checks found, proceeding..."
|
|
106
|
+
return 0
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
echo " Waiting... ($PENDING pending, $PASSED passed)"
|
|
110
|
+
sleep 15
|
|
111
|
+
done
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Step 2: Check PR Feedback
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
check_pr_feedback() {
|
|
119
|
+
local pr_number=$1
|
|
120
|
+
|
|
121
|
+
echo "Checking PR feedback..."
|
|
122
|
+
|
|
123
|
+
# Extract owner and repo from git remote
|
|
124
|
+
REPO_INFO=$(gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"')
|
|
125
|
+
OWNER=$(echo "$REPO_INFO" | cut -d'/' -f1)
|
|
126
|
+
REPO=$(echo "$REPO_INFO" | cut -d'/' -f2)
|
|
127
|
+
|
|
128
|
+
# Get review state
|
|
129
|
+
REVIEWS=$(gh pr view $pr_number --json reviews --jq '.reviews')
|
|
130
|
+
CHANGES_REQUESTED=$(echo "$REVIEWS" | jq '[.[] | select(.state=="CHANGES_REQUESTED")] | length')
|
|
131
|
+
|
|
132
|
+
# Get unresolved review threads
|
|
133
|
+
# NOTE: Fetches first 100 threads. For PRs with >100 threads, implement pagination.
|
|
134
|
+
UNRESOLVED_THREADS=$(gh api graphql -f query='
|
|
135
|
+
query($owner: String!, $repo: String!, $pr: Int!) {
|
|
136
|
+
repository(owner: $owner, name: $repo) {
|
|
137
|
+
pullRequest(number: $pr) {
|
|
138
|
+
reviewThreads(first: 100) {
|
|
139
|
+
nodes {
|
|
140
|
+
isResolved
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
' -f owner="$OWNER" -f repo="$REPO" -F pr=$pr_number \
|
|
147
|
+
--jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length')
|
|
148
|
+
|
|
149
|
+
echo " Unresolved threads: $UNRESOLVED_THREADS"
|
|
150
|
+
echo " Changes requested: $CHANGES_REQUESTED"
|
|
151
|
+
|
|
152
|
+
echo "{\"unresolvedThreads\": $UNRESOLVED_THREADS, \"changesRequested\": $CHANGES_REQUESTED}"
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Get Full Thread Details
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
get_unresolved_threads() {
|
|
160
|
+
local pr_number=$1
|
|
161
|
+
|
|
162
|
+
REPO_INFO=$(gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"')
|
|
163
|
+
OWNER=$(echo "$REPO_INFO" | cut -d'/' -f1)
|
|
164
|
+
REPO=$(echo "$REPO_INFO" | cut -d'/' -f2)
|
|
165
|
+
|
|
166
|
+
# NOTE: Fetches first 100 threads. For PRs with >100, implement pagination.
|
|
167
|
+
gh api graphql -f query='
|
|
168
|
+
query($owner: String!, $repo: String!, $pr: Int!) {
|
|
169
|
+
repository(owner: $owner, name: $repo) {
|
|
170
|
+
pullRequest(number: $pr) {
|
|
171
|
+
reviewThreads(first: 100) {
|
|
172
|
+
nodes {
|
|
173
|
+
id
|
|
174
|
+
isResolved
|
|
175
|
+
path
|
|
176
|
+
line
|
|
177
|
+
diffHunk
|
|
178
|
+
comments(first: 1) {
|
|
179
|
+
nodes {
|
|
180
|
+
id
|
|
181
|
+
body
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
' -f owner="$OWNER" -f repo="$REPO" -F pr=$pr_number \
|
|
190
|
+
--jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)'
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Step 3: Address ALL Feedback
|
|
195
|
+
|
|
196
|
+
> **Note:** This is **conceptual pseudocode** showing the algorithm flow.
|
|
197
|
+
> Implement using: gh api, Read, Edit, Task (ci-fixer), etc.
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
async function addressAllFeedback(prNumber) {
|
|
201
|
+
const threads = await getUnresolvedThreads(prNumber);
|
|
202
|
+
|
|
203
|
+
console.log(`\nAddressing ${threads.length} unresolved threads...`);
|
|
204
|
+
|
|
205
|
+
for (const thread of threads) {
|
|
206
|
+
console.log(`\n--- Thread: ${thread.path}:${thread.line} ---`);
|
|
207
|
+
const analysis = analyzeComment(thread);
|
|
208
|
+
|
|
209
|
+
switch (analysis.type) {
|
|
210
|
+
case 'code_fix_required':
|
|
211
|
+
console.log(`Action: Fixing code issue`);
|
|
212
|
+
await implementFix(thread); // Use Task(ci-fixer) or Edit tool
|
|
213
|
+
break;
|
|
214
|
+
|
|
215
|
+
case 'style_suggestion':
|
|
216
|
+
console.log(`Action: Applying style fix`);
|
|
217
|
+
await implementFix(thread);
|
|
218
|
+
break;
|
|
219
|
+
|
|
220
|
+
case 'question':
|
|
221
|
+
console.log(`Action: Answering question`);
|
|
222
|
+
await replyToComment(prNumber, thread.commentId, generateAnswer(thread));
|
|
223
|
+
await resolveThread(thread.id);
|
|
224
|
+
break;
|
|
225
|
+
|
|
226
|
+
case 'false_positive':
|
|
227
|
+
console.log(`Action: Explaining false positive`);
|
|
228
|
+
await replyToComment(prNumber, thread.commentId,
|
|
229
|
+
`This is a false positive because: ${analysis.reason}\n\n` +
|
|
230
|
+
`Resolving. Please reopen if you disagree.`
|
|
231
|
+
);
|
|
232
|
+
await resolveThread(thread.id);
|
|
233
|
+
break;
|
|
234
|
+
|
|
235
|
+
case 'not_relevant':
|
|
236
|
+
console.log(`Action: Explaining out of scope`);
|
|
237
|
+
await replyToComment(prNumber, thread.commentId,
|
|
238
|
+
`Outside scope of this PR: ${analysis.reason}\n\n` +
|
|
239
|
+
`Resolving. Please reopen if needed.`
|
|
240
|
+
);
|
|
241
|
+
await resolveThread(thread.id);
|
|
242
|
+
break;
|
|
243
|
+
|
|
244
|
+
case 'already_addressed':
|
|
245
|
+
console.log(`Action: Confirming addressed`);
|
|
246
|
+
await replyToComment(prNumber, thread.commentId,
|
|
247
|
+
`Addressed in commit ${gitRevParseHead}.`
|
|
248
|
+
);
|
|
249
|
+
await resolveThread(thread.id);
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Request re-review from those who requested changes
|
|
255
|
+
const changesRequestedReviews = await getChangesRequestedReviews(prNumber);
|
|
256
|
+
for (const review of changesRequestedReviews) {
|
|
257
|
+
await requestReReview(prNumber, review.author);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Comment Analysis Heuristics
|
|
263
|
+
|
|
264
|
+
> **Note:** Classification heuristics for comment handling.
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
function analyzeComment(thread) {
|
|
268
|
+
const body = thread.body.toLowerCase();
|
|
269
|
+
|
|
270
|
+
// Question patterns
|
|
271
|
+
if (body.includes('?') || body.startsWith('why') || body.startsWith('how') ||
|
|
272
|
+
body.startsWith('what') || body.startsWith('could you explain')) {
|
|
273
|
+
return { type: 'question', reason: 'Comment is a question' };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Style/nit patterns
|
|
277
|
+
if (body.includes('nit:') || body.includes('nitpick') || body.includes('minor:') ||
|
|
278
|
+
body.includes('style:') || body.includes('consider') || body.includes('optional')) {
|
|
279
|
+
return { type: 'style_suggestion', reason: 'Style or minor suggestion' };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Out of scope patterns
|
|
283
|
+
if (!thread.diffHunk || commentRefersToUnchangedCode(thread)) {
|
|
284
|
+
return { type: 'not_relevant', reason: 'Comment refers to unchanged code' };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Default: treat as code fix required
|
|
288
|
+
return { type: 'code_fix_required', reason: 'Valid code feedback' };
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Implementing Fixes
|
|
293
|
+
|
|
294
|
+
Use the ci-fixer agent for code changes:
|
|
295
|
+
|
|
296
|
+
```javascript
|
|
297
|
+
Task({
|
|
298
|
+
subagent_type: "next-task:ci-fixer",
|
|
299
|
+
prompt: `Fix the following review comment:
|
|
300
|
+
|
|
301
|
+
**File**: ${thread.path}
|
|
302
|
+
**Line**: ${thread.line}
|
|
303
|
+
**Comment**: ${thread.body}
|
|
304
|
+
**Code Context**:
|
|
305
|
+
\`\`\`
|
|
306
|
+
${thread.diffHunk}
|
|
307
|
+
\`\`\`
|
|
308
|
+
|
|
309
|
+
Requirements:
|
|
310
|
+
1. Make the minimal change to address the feedback
|
|
311
|
+
2. Do NOT over-engineer or add unrelated changes
|
|
312
|
+
3. Ensure tests still pass after the fix`
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Resolving Threads
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
resolve_thread() {
|
|
320
|
+
local thread_id=$1
|
|
321
|
+
|
|
322
|
+
gh api graphql -f query='
|
|
323
|
+
mutation($threadId: ID!) {
|
|
324
|
+
resolveReviewThread(input: {threadId: $threadId}) {
|
|
325
|
+
thread {
|
|
326
|
+
isResolved
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
' -f threadId="$thread_id"
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
reply_to_comment() {
|
|
334
|
+
local pr_number=$1
|
|
335
|
+
local comment_id=$2
|
|
336
|
+
local body=$3
|
|
337
|
+
|
|
338
|
+
REPO_INFO=$(gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"')
|
|
339
|
+
OWNER=$(echo "$REPO_INFO" | cut -d'/' -f1)
|
|
340
|
+
REPO=$(echo "$REPO_INFO" | cut -d'/' -f2)
|
|
341
|
+
|
|
342
|
+
gh api -X POST "repos/$OWNER/$REPO/pulls/$pr_number/comments" \
|
|
343
|
+
-f body="$body" \
|
|
344
|
+
-F in_reply_to="$comment_id"
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Step 4: Commit and Push
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
commit_and_push_fixes() {
|
|
352
|
+
local message=$1
|
|
353
|
+
local branch=${2:-$(git branch --show-current)}
|
|
354
|
+
|
|
355
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
356
|
+
git add -A
|
|
357
|
+
git commit -m "$message"
|
|
358
|
+
git push origin "$branch"
|
|
359
|
+
echo "✓ Pushed fixes"
|
|
360
|
+
return 0
|
|
361
|
+
else
|
|
362
|
+
echo "No code changes to commit (only comment replies)"
|
|
363
|
+
return 1
|
|
364
|
+
fi
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Complete Loop Script
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
#!/bin/bash
|
|
372
|
+
# Phase 4: CI & Review Monitor Loop
|
|
373
|
+
|
|
374
|
+
MAX_ITERATIONS=10
|
|
375
|
+
INITIAL_WAIT=${SHIP_INITIAL_WAIT:-180} # Configurable via env var
|
|
376
|
+
ITERATION_WAIT=30
|
|
377
|
+
iteration=0
|
|
378
|
+
|
|
379
|
+
while [ $iteration -lt $MAX_ITERATIONS ]; do
|
|
380
|
+
iteration=$((iteration + 1))
|
|
381
|
+
echo ""
|
|
382
|
+
echo "========================================"
|
|
383
|
+
echo "CI & Review Monitor - Iteration $iteration"
|
|
384
|
+
echo "========================================"
|
|
385
|
+
|
|
386
|
+
# Step 1: Wait for CI
|
|
387
|
+
if ! wait_for_ci; then
|
|
388
|
+
echo "CI failed - launching ci-fixer agent..."
|
|
389
|
+
continue
|
|
390
|
+
fi
|
|
391
|
+
|
|
392
|
+
# Step 1.5: First iteration - wait for auto-reviews
|
|
393
|
+
if [ $iteration -eq 1 ] && [ "$INITIAL_WAIT" -gt 0 ]; then
|
|
394
|
+
echo "First iteration - waiting ${INITIAL_WAIT}s for auto-reviews..."
|
|
395
|
+
sleep $INITIAL_WAIT
|
|
396
|
+
fi
|
|
397
|
+
|
|
398
|
+
# Step 2: Check feedback
|
|
399
|
+
FEEDBACK=$(check_pr_feedback $PR_NUMBER)
|
|
400
|
+
UNRESOLVED=$(echo "$FEEDBACK" | jq -r '.unresolvedThreads')
|
|
401
|
+
CHANGES_REQ=$(echo "$FEEDBACK" | jq -r '.changesRequested')
|
|
402
|
+
|
|
403
|
+
if [ "$UNRESOLVED" -eq 0 ] && [ "$CHANGES_REQ" -eq 0 ]; then
|
|
404
|
+
echo ""
|
|
405
|
+
echo "╔══════════════════════════════════════╗"
|
|
406
|
+
echo "║ ✓ ALL CHECKS PASSED ║"
|
|
407
|
+
echo "║ ✓ ALL COMMENTS RESOLVED ║"
|
|
408
|
+
echo "║ Ready to merge! ║"
|
|
409
|
+
echo "╚══════════════════════════════════════╝"
|
|
410
|
+
break
|
|
411
|
+
fi
|
|
412
|
+
|
|
413
|
+
# Step 3: Address all feedback
|
|
414
|
+
echo "Addressing $UNRESOLVED unresolved threads..."
|
|
415
|
+
|
|
416
|
+
# Step 4: Commit and push
|
|
417
|
+
commit_and_push_fixes "fix: address review feedback (iteration $iteration)"
|
|
418
|
+
|
|
419
|
+
# Step 5: Wait before next iteration
|
|
420
|
+
echo "Waiting ${ITERATION_WAIT}s..."
|
|
421
|
+
sleep $ITERATION_WAIT
|
|
422
|
+
done
|
|
423
|
+
|
|
424
|
+
if [ $iteration -ge $MAX_ITERATIONS ]; then
|
|
425
|
+
echo "✗ Max iterations reached - manual intervention required"
|
|
426
|
+
exit 1
|
|
427
|
+
fi
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Iteration Summary Output
|
|
431
|
+
|
|
432
|
+
```markdown
|
|
433
|
+
## Iteration ${iteration} Summary
|
|
434
|
+
|
|
435
|
+
**CI Status**: ✓ Passed
|
|
436
|
+
**Comments Addressed**: ${addressedCount}
|
|
437
|
+
- Code fixes: ${codeFixCount}
|
|
438
|
+
- Answered questions: ${questionCount}
|
|
439
|
+
- Resolved as not applicable: ${notApplicableCount}
|
|
440
|
+
**Remaining Unresolved**: ${remainingCount}
|
|
441
|
+
|
|
442
|
+
${remainingCount > 0 ? 'Continuing...' : 'Ready to merge!'}
|
|
443
|
+
```
|