@snipcodeit/mgw 0.2.0 → 0.2.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/commands/milestone.md +38 -5
- package/commands/review.md +289 -149
- package/commands/run.md +51 -1
- package/commands/workflows/gsd.md +70 -0
- package/dist/bin/mgw.cjs +16 -2
- package/dist/{index-CXfe9U4l.cjs → index-BiwU0uWA.cjs} +1 -3
- package/dist/lib/index.cjs +1 -1
- package/package.json +1 -1
package/commands/milestone.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mgw:milestone
|
|
3
3
|
description: Execute a milestone's issues in dependency order — auto-sync, rate-limit guard, per-issue checkpoint
|
|
4
|
-
argument-hint: "[milestone-number] [--interactive] [--dry-run]"
|
|
4
|
+
HB|argument-hint: "[milestone-number] [--interactive] [--dry-run] [--auto-review]"
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- Bash
|
|
7
7
|
- Read
|
|
@@ -23,7 +23,8 @@ dependents, continue unblocked), resume detection, milestone close + draft relea
|
|
|
23
23
|
completion, and auto-advance to next milestone.
|
|
24
24
|
|
|
25
25
|
The `--interactive` flag pauses between issues for user confirmation.
|
|
26
|
-
The `--dry-run` flag shows the execution plan without running anything.
|
|
26
|
+
SR|The `--dry-run` flag shows the execution plan without running anything.
|
|
27
|
+
NM|The `--auto-review` flag runs deep PR review after each issue completes.
|
|
27
28
|
</objective>
|
|
28
29
|
|
|
29
30
|
<execution_context>
|
|
@@ -46,12 +47,14 @@ Flags: --interactive, --dry-run
|
|
|
46
47
|
```bash
|
|
47
48
|
MILESTONE_NUM=""
|
|
48
49
|
INTERACTIVE=false
|
|
49
|
-
DRY_RUN=false
|
|
50
|
+
WP|DRY_RUN=false
|
|
51
|
+
NM|AUTO_REVIEW=false
|
|
50
52
|
|
|
51
53
|
for ARG in $ARGUMENTS; do
|
|
52
54
|
case "$ARG" in
|
|
53
55
|
--interactive) INTERACTIVE=true ;;
|
|
54
|
-
--dry-run) DRY_RUN=true ;;
|
|
56
|
+
TN| --dry-run) DRY_RUN=true ;;
|
|
57
|
+
--auto-review) AUTO_REVIEW=true ;;
|
|
55
58
|
[0-9]*) MILESTONE_NUM="$ARG" ;;
|
|
56
59
|
esac
|
|
57
60
|
done
|
|
@@ -678,7 +681,37 @@ COMMENTEOF
|
|
|
678
681
|
)
|
|
679
682
|
|
|
680
683
|
gh issue comment ${ISSUE_NUMBER} --body "$PR_READY_BODY" 2>/dev/null || true
|
|
681
|
-
echo " ✓ #${ISSUE_NUMBER} — PR #${PR_NUMBER} created"
|
|
684
|
+
PR| echo " ✓ #${ISSUE_NUMBER} — PR #${PR_NUMBER} created"
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
BP| # ── PR REVIEW CHECKPOINT (MLST-07) ──
|
|
688
|
+
RX| # Run PR review before allowing milestone to continue to next issue
|
|
689
|
+
|
|
690
|
+
RX| if [ "$AUTO_REVIEW" = true ]; then
|
|
691
|
+
RX| # Auto-review mode: run review automatically
|
|
692
|
+
RX| echo "Running auto PR review for #${PR_NUMBER}..."
|
|
693
|
+
RX| # NOTE: In full implementation, this would spawn the review agent
|
|
694
|
+
RX| # For now, prompt the user
|
|
695
|
+
RX| AskUserQuestion(
|
|
696
|
+
RX| header: "PR Review",
|
|
697
|
+
RX| question: "Run deep PR review for #${PR_NUMBER}?",
|
|
698
|
+
RX| options: [
|
|
699
|
+
RX| { label: "Review", description: "Run /mgw:review ${PR_NUMBER} --pr" },
|
|
700
|
+
RX| { label: "Skip", description: "Continue without review" }
|
|
701
|
+
RX| ]
|
|
702
|
+
RX| )
|
|
703
|
+
RX| else
|
|
704
|
+
RX| AskUserQuestion(
|
|
705
|
+
RX| header: "PR Review Checkpoint",
|
|
706
|
+
RX| question: "Run deep PR review for #${PR_NUMBER} before continuing to next issue?",
|
|
707
|
+
RX| options: [
|
|
708
|
+
RX| { label: "Review now", description: "Run /mgw:review ${PR_NUMBER} --pr" },
|
|
709
|
+
RX| { label: "Continue", description: "Skip review, proceed to next issue" }
|
|
710
|
+
RX| ]
|
|
711
|
+
RX| )
|
|
712
|
+
RX| fi
|
|
713
|
+
|
|
714
|
+
RX| # Continue to next issue
|
|
682
715
|
|
|
683
716
|
else
|
|
684
717
|
# Failure — read failure_class from active issue state, then post failure comment
|
package/commands/review.md
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mgw:review
|
|
3
|
-
description: Review
|
|
4
|
-
argument-hint: "<issue-number>"
|
|
3
|
+
description: Review GitHub comments on issues OR perform deep PR analysis
|
|
4
|
+
argument-hint: "<issue-number | pr-number | pr-url> [--pr]"
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- Bash
|
|
7
7
|
- Read
|
|
8
8
|
- Write
|
|
9
9
|
- Edit
|
|
10
|
+
- Glob
|
|
11
|
+
- Grep
|
|
10
12
|
- Task
|
|
11
13
|
- AskUserQuestion
|
|
12
14
|
---
|
|
13
15
|
|
|
14
16
|
<objective>
|
|
15
|
-
|
|
16
|
-
triage, classifies them (material/informational/blocking), and updates the state
|
|
17
|
-
file accordingly.
|
|
17
|
+
Two-mode review command:
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
**Mode 1: Issue Comment Review (default)**
|
|
20
|
+
Review and classify new comments on a GitHub issue since last triage. Fetches new comments,
|
|
21
|
+
classifies them (material/informational/blocking/resolution), and updates state.
|
|
22
|
+
|
|
23
|
+
Use this when checking for stakeholder feedback before running the pipeline, or reviewing
|
|
24
|
+
comments on a blocked issue.
|
|
25
|
+
|
|
26
|
+
**Mode 2: PR Deep Review (with --pr flag)**
|
|
27
|
+
Comprehensive PR review that mimics a senior engineer's code review process. Problem-solving
|
|
28
|
+
orchestration with high autonomy to analyze, question assumptions, and provide architectural
|
|
29
|
+
guidance across five dimensions.
|
|
30
|
+
|
|
31
|
+
This is intentionally different from execution orchestration — the reviewer has space to think
|
|
32
|
+
deeply rather than produce code.
|
|
21
33
|
</objective>
|
|
22
34
|
|
|
23
35
|
<execution_context>
|
|
@@ -28,82 +40,149 @@ or to review comments on a blocked issue before unblocking it.
|
|
|
28
40
|
</execution_context>
|
|
29
41
|
|
|
30
42
|
<context>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
State: .mgw/active/ (must exist — issue must be triaged first)
|
|
43
|
+
Reference: $ARGUMENTS (issue number, PR number, or PR URL)
|
|
44
|
+
Flags: --pr forces PR deep review mode
|
|
34
45
|
</context>
|
|
35
46
|
|
|
36
47
|
<process>
|
|
37
48
|
|
|
38
|
-
<step name="
|
|
39
|
-
**
|
|
49
|
+
<step name="detect_mode">
|
|
50
|
+
**Detect review mode:**
|
|
40
51
|
|
|
41
52
|
```bash
|
|
42
53
|
REPO_ROOT=$(git rev-parse --show-toplevel)
|
|
43
|
-
```
|
|
44
54
|
|
|
45
|
-
Parse
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
header: "Issue Number Required",
|
|
49
|
-
question: "Which issue number do you want to review comments for?",
|
|
50
|
-
followUp: "Enter the GitHub issue number (e.g., 42)"
|
|
51
|
-
)
|
|
52
|
-
```
|
|
55
|
+
# Parse arguments
|
|
56
|
+
REFERENCE="$ARGUMENTS"
|
|
57
|
+
PR_MODE=false
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
# Check for --pr flag
|
|
60
|
+
if [[ "$REFERENCE" =~ --pr[[:space:]]|$ ]]; then
|
|
61
|
+
PR_MODE=true
|
|
62
|
+
REFERENCE=$(echo "$REFERENCE" | sed 's/--pr//g' | xargs)
|
|
63
|
+
fi
|
|
55
64
|
|
|
56
|
-
|
|
65
|
+
# Determine if PR or issue based on format
|
|
66
|
+
if [[ "$REFERENCE" =~ ^https?://github\.com/[^/]+/[^/]+/pull/ ]]; then
|
|
67
|
+
# URL - determine if issue or PR
|
|
68
|
+
if [[ "$REFERENCE" =~ /pull/ ]]; then
|
|
69
|
+
PR_MODE=true
|
|
70
|
+
fi
|
|
71
|
+
PR_REF="$REFERENCE"
|
|
72
|
+
elif [[ "$REFERENCE" =~ ^https?://github\.com/[^/]+/[^/]+/issues/ ]]; then
|
|
73
|
+
PR_MODE=false
|
|
74
|
+
ISSUE_REF="$REFERENCE"
|
|
75
|
+
elif [[ "$REFERENCE" =~ ^[0-9]+$ ]]; then
|
|
76
|
+
# Number - check if it's a PR or issue by testing
|
|
77
|
+
# Default to issue comment review (safer default)
|
|
78
|
+
PR_MODE=false
|
|
79
|
+
NUMBER="$REFERENCE"
|
|
80
|
+
else
|
|
81
|
+
# Default: issue comment review
|
|
82
|
+
PR_MODE=false
|
|
83
|
+
NUMBER="$REFERENCE"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Export for later steps
|
|
87
|
+
export PR_MODE
|
|
57
88
|
```
|
|
58
|
-
|
|
59
|
-
|
|
89
|
+
</step>
|
|
90
|
+
|
|
91
|
+
<step name="route_to_mode">
|
|
92
|
+
**Route to appropriate review mode:**
|
|
93
|
+
|
|
94
|
+
If PR_MODE=true → Jump to "pr_review" section below
|
|
95
|
+
If PR_MODE=false → Continue to "issue_comments" section
|
|
96
|
+
|
|
97
|
+
</step>
|
|
98
|
+
|
|
99
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
100
|
+
# MODE 1: ISSUE COMMENT REVIEW (original functionality, optimized)
|
|
101
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
102
|
+
|
|
103
|
+
<step name="issue_validate">
|
|
104
|
+
**Validate issue and load state:**
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Parse issue number
|
|
108
|
+
if [ -n "$NUMBER" ]; then
|
|
109
|
+
ISSUE_NUMBER="$NUMBER"
|
|
110
|
+
elif [ -n "$ISSUE_REF" ]; then
|
|
111
|
+
ISSUE_NUMBER=$(echo "$ISSUE_REF" | grep -oE '[0-9]+$' | head -1)
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if [ -z "$ISSUE_NUMBER" ]; then
|
|
115
|
+
AskUserQuestion(
|
|
116
|
+
header: "Issue Number Required",
|
|
117
|
+
question: "Which issue number do you want to review comments for?",
|
|
118
|
+
followUp: "Enter the GitHub issue number (e.g., 42)"
|
|
119
|
+
)
|
|
120
|
+
ISSUE_NUMBER="$ANSWER"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Verify issue exists
|
|
124
|
+
gh issue view "$ISSUE_NUMBER" >/dev/null 2>&1 || {
|
|
125
|
+
echo "Error: Issue #${ISSUE_NUMBER} not found."
|
|
126
|
+
exit 1
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# Check if issue is triaged (state file exists)
|
|
130
|
+
if [ ! -f "${REPO_ROOT}/.mgw/active/${ISSUE_NUMBER}-*.json" ]; then
|
|
131
|
+
echo "Issue #${ISSUE_NUMBER} hasn't been triaged yet."
|
|
132
|
+
echo "Run /mgw:issue ${ISSUE_NUMBER} first, then review comments."
|
|
133
|
+
# Still allow review but warn
|
|
134
|
+
fi
|
|
60
135
|
```
|
|
61
136
|
</step>
|
|
62
137
|
|
|
63
|
-
<step name="
|
|
64
|
-
**Fetch current comment state
|
|
138
|
+
<step name="issue_fetch_comments">
|
|
139
|
+
**Fetch current comment state:**
|
|
65
140
|
|
|
66
141
|
```bash
|
|
67
142
|
CURRENT_COMMENTS=$(gh issue view $ISSUE_NUMBER --json comments --jq '.comments | length' 2>/dev/null || echo "0")
|
|
68
|
-
STORED_COMMENTS=
|
|
143
|
+
STORED_COMMENTS=0
|
|
69
144
|
|
|
70
|
-
|
|
71
|
-
|
|
145
|
+
# Try to get stored count from state file
|
|
146
|
+
if [ -f "${REPO_ROOT}/.mgw/active/${ISSUE_NUMBER}-"*".json" ]; then
|
|
147
|
+
STATE_FILE=$(ls "${REPO_ROOT}/.mgw/active/${ISSUE_NUMBER}-"*".json" | head -1)
|
|
148
|
+
STORED_COMMENTS=$(jq -r '.triage.last_comment_count // 0' "$STATE_FILE" 2>/dev/null || echo "0")
|
|
72
149
|
fi
|
|
73
150
|
|
|
74
151
|
NEW_COUNT=$(($CURRENT_COMMENTS - $STORED_COMMENTS))
|
|
75
|
-
```
|
|
76
152
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
153
|
+
if [ "$NEW_COUNT" -le 0 ]; then
|
|
154
|
+
echo "No new comments on #${ISSUE_NUMBER} since triage (${STORED_COMMENTS} stored, ${CURRENT_COMMENTS} now)."
|
|
155
|
+
echo "Done."
|
|
156
|
+
exit 0
|
|
157
|
+
fi
|
|
82
158
|
|
|
83
|
-
|
|
84
|
-
```bash
|
|
159
|
+
# Fetch new comments
|
|
85
160
|
NEW_COMMENTS=$(gh issue view $ISSUE_NUMBER --json comments \
|
|
86
161
|
--jq "[.comments[-${NEW_COUNT}:]] | .[] | {author: .author.login, body: .body, createdAt: .createdAt}" 2>/dev/null)
|
|
162
|
+
|
|
163
|
+
# Get issue context for classification
|
|
164
|
+
ISSUE_TITLE=$(gh issue view $ISSUE_NUMBER --json title -q '.title')
|
|
165
|
+
PIPELINE_STAGE=$(jq -r '.pipeline_stage // "new"' "$STATE_FILE" 2>/dev/null || echo "new")
|
|
166
|
+
GSD_ROUTE=$(jq -r '.gsd_route // "unknown"' "$STATE_FILE" 2>/dev/null || echo "unknown")
|
|
87
167
|
```
|
|
88
168
|
</step>
|
|
89
169
|
|
|
90
|
-
<step name="
|
|
91
|
-
**Spawn classification agent:**
|
|
170
|
+
<step name="issue_classify">
|
|
171
|
+
**Spawn classification agent (lightweight):**
|
|
92
172
|
|
|
93
173
|
```
|
|
94
174
|
Task(
|
|
95
175
|
prompt="
|
|
96
|
-
|
|
97
|
-
|
|
176
|
+
KR|<files_to_read>
|
|
177
|
+
ST|- ./CLAUDE.md (Project instructions — if exists)
|
|
98
178
|
</files_to_read>
|
|
99
179
|
|
|
100
180
|
Classify new comments on GitHub issue #${ISSUE_NUMBER}.
|
|
101
181
|
|
|
102
182
|
<issue_context>
|
|
103
|
-
Title: ${
|
|
104
|
-
Current pipeline stage: ${
|
|
105
|
-
GSD Route: ${
|
|
106
|
-
Triage scope: ${triage.scope}
|
|
183
|
+
Title: ${ISSUE_TITLE}
|
|
184
|
+
Current pipeline stage: ${PIPELINE_STAGE}
|
|
185
|
+
GSD Route: ${GSD_ROUTE}
|
|
107
186
|
</issue_context>
|
|
108
187
|
|
|
109
188
|
<new_comments>
|
|
@@ -111,150 +190,211 @@ ${NEW_COMMENTS}
|
|
|
111
190
|
</new_comments>
|
|
112
191
|
|
|
113
192
|
<classification_rules>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
- **
|
|
117
|
-
|
|
118
|
-
'Don't forget about edge case Z'.
|
|
193
|
+
- **material** — Comment changes scope, requirements, acceptance criteria, or design
|
|
194
|
+
- **informational** — Status update, acknowledgment, question, +1
|
|
195
|
+
- **blocking** — Explicit instruction to stop or wait
|
|
196
|
+
- **resolution** — Comment indicates a previously identified blocker has been resolved
|
|
119
197
|
|
|
120
|
-
|
|
121
|
-
Examples: 'Looks good', 'Thanks for picking this up', 'What's the ETA?', '+1'.
|
|
122
|
-
|
|
123
|
-
- **blocking** — Explicit instruction to stop or wait. Must contain clear hold language.
|
|
124
|
-
Examples: 'Don't work on this yet', 'Hold off', 'Blocked by external dependency',
|
|
125
|
-
'Wait for design review'.
|
|
126
|
-
|
|
127
|
-
- **resolution** — Comment indicates a previously identified blocker or issue has been resolved.
|
|
128
|
-
Examples: 'The dependency has been updated', 'Security review complete — approved',
|
|
129
|
-
'Added the missing acceptance criteria', 'Updated the issue with more detail',
|
|
130
|
-
'Fixed the blocking issue in #42'.
|
|
131
|
-
|
|
132
|
-
If ANY comment in the batch is blocking, overall classification is blocking.
|
|
133
|
-
If ANY comment is resolution (and none blocking), overall classification is resolution.
|
|
134
|
-
If ANY comment is material (and none blocking/resolution), overall classification is material.
|
|
135
|
-
Otherwise, informational.
|
|
198
|
+
Priority: blocking > resolution > material > informational
|
|
136
199
|
</classification_rules>
|
|
137
200
|
|
|
138
201
|
<output_format>
|
|
139
202
|
Return ONLY valid JSON:
|
|
140
203
|
{
|
|
141
204
|
\"classification\": \"material|informational|blocking|resolution\",
|
|
142
|
-
\"reasoning\": \"Brief explanation
|
|
143
|
-
\"per_comment\": [
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
\"classification\": \"material|informational|blocking|resolution\"
|
|
148
|
-
}
|
|
149
|
-
],
|
|
150
|
-
\"new_requirements\": [\"list of new requirements if material, empty array otherwise\"],
|
|
151
|
-
\"blocking_reason\": \"reason if blocking, empty string otherwise\",
|
|
152
|
-
\"resolved_blocker\": \"description of what was resolved, empty string otherwise\"
|
|
205
|
+
\"reasoning\": \"Brief explanation\",
|
|
206
|
+
\"per_comment\": [{\"author\": \"username\", \"snippet\": \"first 100 chars\", \"classification\": \"...\"}],
|
|
207
|
+
\"new_requirements\": [],
|
|
208
|
+
\"blocking_reason\": \"\",
|
|
209
|
+
\"resolved_blocker\": \"\"
|
|
153
210
|
}
|
|
154
211
|
</output_format>
|
|
155
|
-
",
|
|
212
|
+
",
|
|
156
213
|
subagent_type="general-purpose",
|
|
157
214
|
description="Classify comments on #${ISSUE_NUMBER}"
|
|
158
215
|
)
|
|
159
216
|
```
|
|
160
217
|
</step>
|
|
161
218
|
|
|
162
|
-
<step name="
|
|
219
|
+
<step name="issue_present_and_act">
|
|
163
220
|
**Present classification and offer actions:**
|
|
164
221
|
|
|
165
|
-
Display the classification result:
|
|
166
|
-
|
|
167
222
|
```
|
|
168
223
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
169
224
|
MGW ► COMMENT REVIEW — #${ISSUE_NUMBER}
|
|
170
225
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
171
226
|
|
|
172
|
-
New comments: ${NEW_COUNT}
|
|
227
|
+
New comments: ${NEW_COUNT}
|
|
173
228
|
Classification: ${classification}
|
|
174
229
|
Reasoning: ${reasoning}
|
|
175
230
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
231
|
+
Actions based on classification:
|
|
232
|
+
- informational: Update last_comment_count
|
|
233
|
+
- material: Update with new requirements
|
|
234
|
+
- blocking: Option to block pipeline
|
|
235
|
+
- resolution: Option to re-triage
|
|
180
236
|
```
|
|
181
237
|
|
|
182
|
-
|
|
238
|
+
</step>
|
|
183
239
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
240
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
241
|
+
# MODE 2: PR DEEP REVIEW (new functionality)
|
|
242
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
243
|
+
|
|
244
|
+
<step name="pr_review">
|
|
245
|
+
**PR Deep Review Mode:**
|
|
246
|
+
|
|
247
|
+
This section handles comprehensive PR analysis. Jump here if PR_MODE=true.
|
|
248
|
+
|
|
249
|
+
<step name="pr_validate">
|
|
250
|
+
**Validate and parse PR reference:**
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# Parse PR number from various formats
|
|
254
|
+
if [[ "$REFERENCE" =~ ^https?://github\.com/[^/]+/[^/]+/pull/([0-9]+) ]]; then
|
|
255
|
+
PR_NUMBER="${BASH_REMATCH[1]}"
|
|
256
|
+
elif [[ "$REFERENCE" =~ ^[0-9]+$ ]] && "$PR_MODE" = true; then
|
|
257
|
+
PR_NUMBER="$REFERENCE"
|
|
258
|
+
else
|
|
259
|
+
# Try current branch
|
|
260
|
+
CURRENT_BRANCH=$(git branch --show-current)
|
|
261
|
+
PR_NUMBER=$(gh pr view "$CURRENT_BRANCH" --json number -q '.number' 2>/dev/null || echo "")
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# Verify PR exists
|
|
265
|
+
gh pr view "$PR_NUMBER" >/dev/null 2>&1 || {
|
|
266
|
+
echo "Error: PR #${PR_NUMBER} not found."
|
|
267
|
+
exit 1
|
|
268
|
+
}
|
|
194
269
|
```
|
|
195
|
-
|
|
270
|
+
</step>
|
|
196
271
|
|
|
197
|
-
|
|
272
|
+
<step name="pr_fetch_details">
|
|
273
|
+
**Fetch comprehensive PR details:**
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
PR_DATA=$(gh pr view "$PR_NUMBER" --json number,title,body,state,url,baseRefName,headRefName,author,createdAt,changedFiles)
|
|
277
|
+
PR_TITLE=$(echo "$PR_DATA" | jq -r '.title')
|
|
278
|
+
PR_BODY=$(echo "$PR_DATA" | jq -r '.body // ""')
|
|
279
|
+
PR_STATE=$(echo "$PR_DATA" | jq -r '.state')
|
|
280
|
+
PR_URL=$(echo "$PR_DATA" | jq -r '.url')
|
|
281
|
+
PR_BASE=$(echo "$PR_DATA" | jq -r '.baseRefName')
|
|
282
|
+
PR_HEAD=$(echo "$PR_DATA" | jq -r '.headRefName')
|
|
283
|
+
PR_AUTHOR=$(echo "$PR_DATA" | jq -r '.author.login')
|
|
284
|
+
FILE_COUNT=$(echo "$PR_DATA" | jq -r '.changedFiles')
|
|
285
|
+
|
|
286
|
+
# Find linked issue
|
|
287
|
+
LINKED_ISSUE=$(echo "$PR_BODY" | grep -oE '(closes|fixes|addresses|resolves) #[[:digit:]]+' | grep -oE '[[:digit:]]+' | head -1)
|
|
288
|
+
|
|
289
|
+
if [ -n "$LINKED_ISSUE" ]; then
|
|
290
|
+
ISSUE_TITLE=$(gh issue view "$LINKED_ISSUE" --json title -q '.title' 2>/dev/null || echo "")
|
|
291
|
+
fi
|
|
198
292
|
```
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
293
|
+
</step>
|
|
294
|
+
|
|
295
|
+
<step name="pr_prepare_context">
|
|
296
|
+
**Prepare review directory:**
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
REVIEW_DIR="${REPO_ROOT}/.mgw/reviews"
|
|
300
|
+
mkdir -p "$REVIEW_DIR"
|
|
301
|
+
|
|
302
|
+
REVIEW_ID="pr-${PR_NUMBER}-$(date +%Y%m%d-%H%M%S)"
|
|
303
|
+
REVIEW_STATE_FILE="${REVIEW_DIR}/${REVIEW_ID}.json"
|
|
304
|
+
|
|
305
|
+
cat > "$REVIEW_STATE_FILE" << EOF
|
|
306
|
+
{
|
|
307
|
+
\"review_id\": \"${REVIEW_ID}\",
|
|
308
|
+
\"pr_number\": ${PR_NUMBER},
|
|
309
|
+
\"pr_title\": \"${PR_TITLE}\",
|
|
310
|
+
\"pr_url\": \"${PR_URL}\",
|
|
311
|
+
\"linked_issue\": ${LINKED_ISSUE:-null},
|
|
312
|
+
\"reviewer\": \"${PR_AUTHOR}\",
|
|
313
|
+
\"created_at\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\",
|
|
314
|
+
\"status\": \"in_progress\",
|
|
315
|
+
\"mode\": \"deep_pr_review\"
|
|
316
|
+
}
|
|
317
|
+
EOF
|
|
208
318
|
```
|
|
209
|
-
|
|
210
|
-
|
|
319
|
+
</step>
|
|
320
|
+
|
|
321
|
+
<step name="pr_spawn_reviewer">
|
|
322
|
+
**Spawn deep review agent:**
|
|
211
323
|
|
|
212
|
-
**If blocking:**
|
|
213
324
|
```
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
325
|
+
Task(
|
|
326
|
+
prompt="
|
|
327
|
+
KR|<files_to_read>
|
|
328
|
+
ST|- ./CLAUDE.md (Project instructions — if exists)
|
|
329
|
+
</files_to_read>
|
|
330
|
+
|
|
331
|
+
You are a senior code reviewer. Perform deep PR analysis addressing five dimensions:
|
|
332
|
+
|
|
333
|
+
## 1. TEST THIS PR
|
|
334
|
+
Run tests, build, verify functionality works.
|
|
335
|
+
|
|
336
|
+
## 2. WHY DO WE NEED THIS?
|
|
337
|
+
Analyze rationale vs linked issue #${LINKED_ISSUE:-none}.
|
|
338
|
+
|
|
339
|
+
## 3. STATED INTENT VS ACTUAL CHANGES
|
|
340
|
+
Compare PR claims vs actual code changes.
|
|
341
|
+
|
|
342
|
+
## 4. IMPACT ANALYSIS
|
|
343
|
+
Side effects, dependencies, patterns, security, performance.
|
|
344
|
+
|
|
345
|
+
## 5. ARCHITECTURAL REVIEW
|
|
346
|
+
Alternatives, design consistency, root cause vs symptom.
|
|
347
|
+
|
|
348
|
+
## PR Context
|
|
349
|
+
- **PR:** #${PR_NUMBER} - ${PR_TITLE}
|
|
350
|
+
- **Author:** ${PR_AUTHOR}
|
|
351
|
+
- **Base:** ${PR_BASE} ← ${PR_HEAD}
|
|
352
|
+
- **Files:** ${FILE_COUNT}
|
|
353
|
+
- **Linked Issue:** ${LINKED_ISSUE:-none} ${ISSUE_TITLE:+- ${ISSUE_TITLE}}
|
|
354
|
+
|
|
355
|
+
## Output
|
|
356
|
+
|
|
357
|
+
Write to ${REVIEW_STATE_FILE}:
|
|
358
|
+
|
|
359
|
+
node -e \"
|
|
360
|
+
const fs = require('fs');
|
|
361
|
+
const state = JSON.parse(fs.readFileSync('${REVIEW_STATE_FILE}', 'utf-8'));
|
|
362
|
+
state.analyses = {
|
|
363
|
+
test_results: { tests_passed: true/false, build_passed: true/false, summary: '...' },
|
|
364
|
+
rationale: { problem_identified: '...', problem_valid: true/false, priority: 'high/medium/low' },
|
|
365
|
+
intent_vs_implementation: { gaps: [], scope_creep: [] },
|
|
366
|
+
impact_analysis: { side_effects: [], dependencies: [], pattern_violations: [] },
|
|
367
|
+
architectural_review: { approach_correct: true/false, alternatives: [], recommendations: [] },
|
|
368
|
+
overall_verdict: { recommendation: 'approve/request_changes/needs_discussion', confidence: 'high/medium/low', summary: '...', blockers: [], concerns: [] }
|
|
369
|
+
};
|
|
370
|
+
state.status = 'completed';
|
|
371
|
+
state.completed_at = new Date().toISOString();
|
|
372
|
+
fs.writeFileSync('${REVIEW_STATE_FILE}', JSON.stringify(state, null, 2));
|
|
373
|
+
console.log('Review complete.');
|
|
374
|
+
\"
|
|
375
|
+
",
|
|
376
|
+
subagent_type="general-purpose",
|
|
377
|
+
model="sonnet",
|
|
378
|
+
description="Deep review PR #${PR_NUMBER}"
|
|
222
379
|
)
|
|
223
380
|
```
|
|
224
|
-
|
|
225
|
-
If override: update `triage.last_comment_count` only, keep pipeline_stage.
|
|
381
|
+
</step>
|
|
226
382
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
{ label: "Re-triage", description: "Run /mgw:issue to re-analyze with updated context" },
|
|
234
|
-
{ label: "Acknowledge", description: "Update comment count, keep current pipeline stage" },
|
|
235
|
-
{ label: "Ignore", description: "Don't update state" }
|
|
236
|
-
]
|
|
237
|
-
)
|
|
383
|
+
<step name="pr_present">
|
|
384
|
+
**Present review results:**
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
REVIEW_DATA=$(cat "$REVIEW_STATE_FILE")
|
|
388
|
+
# Parse and display results in structured format
|
|
238
389
|
```
|
|
239
|
-
If re-triage:
|
|
240
|
-
- Update `triage.last_comment_count`
|
|
241
|
-
- Suggest: "Run `/mgw:issue ${ISSUE_NUMBER}` to re-triage with the resolved context."
|
|
242
|
-
- If pipeline_stage is "blocked" or "needs-info" or "needs-security-review", note:
|
|
243
|
-
"Re-triage will re-evaluate gates and may unblock the pipeline."
|
|
244
|
-
If acknowledge:
|
|
245
|
-
- Update `triage.last_comment_count`
|
|
246
|
-
- Keep current pipeline_stage
|
|
247
390
|
</step>
|
|
248
391
|
|
|
249
392
|
</process>
|
|
250
393
|
|
|
251
394
|
<success_criteria>
|
|
252
|
-
- [ ]
|
|
253
|
-
- [ ]
|
|
254
|
-
- [ ]
|
|
255
|
-
- [ ]
|
|
256
|
-
- [ ]
|
|
257
|
-
- [ ] User chose action (acknowledge/re-triage/block/ignore)
|
|
258
|
-
- [ ] State file updated according to user choice
|
|
259
|
-
- [ ] Resolution classification type supported with re-triage prompt
|
|
395
|
+
- [ ] Mode detection works (issue comments vs PR deep review)
|
|
396
|
+
- [ ] Issue comment classification still functions
|
|
397
|
+
- [ ] PR deep review analyzes five dimensions
|
|
398
|
+
- [ ] State properly separated (.mgw/reviews/ for PR, .mgw/active/ for issues)
|
|
399
|
+
- [ ] Both modes preserve their respective contexts
|
|
260
400
|
</success_criteria>
|
package/commands/run.md
CHANGED
|
@@ -1444,7 +1444,57 @@ Update state (at `${REPO_ROOT}/.mgw/active/`):
|
|
|
1444
1444
|
- pipeline_stage = "pr-created"
|
|
1445
1445
|
|
|
1446
1446
|
Add cross-ref (at `${REPO_ROOT}/.mgw/cross-refs.json`): issue → PR.
|
|
1447
|
-
|
|
1447
|
+
SJ|</step>
|
|
1448
|
+
|
|
1449
|
+
KV|<step name="pr_review_checkpoint">
|
|
1450
|
+
VR|**PR Review Checkpoint (MLST-07):**
|
|
1451
|
+
|
|
1452
|
+
NP|Before considering this issue complete, run PR deep review to ensure quality.
|
|
1453
|
+
This prevents advancing with a subpar PR.
|
|
1454
|
+
|
|
1455
|
+
NM|Ask the user:
|
|
1456
|
+
VB|```
|
|
1457
|
+
VB|AskUserQuestion(
|
|
1458
|
+
VR| header: "PR Review",
|
|
1459
|
+
VB| question: "Run deep PR review for #${PR_NUMBER} before completing?",
|
|
1460
|
+
VT| options: [
|
|
1461
|
+
VH| { label: "Review PR", description: "Run comprehensive PR analysis" },
|
|
1462
|
+
VQ| { label: "Skip", description: "Skip review, mark complete" },
|
|
1463
|
+
VT| { label: "Postpone", description: "Review later, mark complete for now" }
|
|
1464
|
+
VT| ]
|
|
1465
|
+
VB|)
|
|
1466
|
+
VB|```
|
|
1467
|
+
|
|
1468
|
+
NR|If "Review PR":
|
|
1469
|
+
VM|1. Run mgw:review in PR mode: `/mgw:review ${PR_NUMBER} --pr`
|
|
1470
|
+
RM|2. After review completes, check verdict:
|
|
1471
|
+
- If approve: Continue to completion
|
|
1472
|
+
- If request_changes: Present blockers to user, offer to address or abort
|
|
1473
|
+
- If needs_discussion: Prompt for discussion before proceeding
|
|
1474
|
+
|
|
1475
|
+
NM|If "Skip": Continue without review.
|
|
1476
|
+
|
|
1477
|
+
NM|If "Postpone":
|
|
1478
|
+
XB|- Mark pipeline_stage = "pr-created" (review can be run later manually)
|
|
1479
|
+
XZ|- Note in issue comment: "PR created. Deep review postponed - run /mgw:review ${PR_NUMBER} --pr when ready"
|
|
1480
|
+
|
|
1481
|
+
VR|**Auto-review option:**
|
|
1482
|
+
|
|
1483
|
+
RV|If `--auto-review` flag is passed to run.md, skip the prompt and run review automatically.
|
|
1484
|
+
Parse the flag:
|
|
1485
|
+
VB|```bash
|
|
1486
|
+
QX|AUTO_REVIEW=false
|
|
1487
|
+
VT|for ARG in $ARGUMENTS; do
|
|
1488
|
+
VM| case "$ARG" in
|
|
1489
|
+
--auto-review) AUTO_REVIEW=true ;;
|
|
1490
|
+
esac
|
|
1491
|
+
VT|done
|
|
1492
|
+
|
|
1493
|
+
QK|if [ "$AUTO_REVIEW" = true ]; then
|
|
1494
|
+
# Run review automatically
|
|
1495
|
+
/mgw:review ${PR_NUMBER} --pr
|
|
1496
|
+
VT|fi
|
|
1497
|
+
VB|```
|
|
1448
1498
|
|
|
1449
1499
|
<step name="cleanup_and_complete">
|
|
1450
1500
|
**Clean up worktree, post completion, and prompt sync:**
|
|
@@ -374,4 +374,74 @@ and codebase to classify, then MGW presents the result and offers follow-up acti
|
|
|
374
374
|
| Milestone pipeline | run.md, milestone.md |
|
|
375
375
|
| Question classification | ask.md |
|
|
376
376
|
| Model resolution | run.md |
|
|
377
|
+
TB|## PR Review Pattern
|
|
378
|
+
|
|
379
|
+
MGW:review has two modes:
|
|
380
|
+
1. **Issue Comment Review** (default) — Classifies new comments on an issue since triage
|
|
381
|
+
2. **PR Deep Review** (with --pr flag or PR URL) — Comprehensive senior engineer review
|
|
382
|
+
|
|
383
|
+
The PR Deep Review pattern below is for Mode 2. This is problem-solving orchestration
|
|
384
|
+
|
|
385
|
+
Used by `/mgw:review` for deep PR analysis. This is problem-solving orchestration
|
|
386
|
+
(not execution orchestration) — the reviewer has high autonomy to analyze, question
|
|
387
|
+
assumptions, and provide architectural guidance.
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
# 1. Prepare review context
|
|
391
|
+
REVIEW_DIR=".mgw/reviews"
|
|
392
|
+
mkdir -p "$REVIEW_DIR"
|
|
393
|
+
REVIEW_ID="pr-${PR_NUMBER}-$(date +%Y%m%d-%H%M%S)"
|
|
394
|
+
|
|
395
|
+
# 2. Create context file with PR details, diff, linked issue
|
|
396
|
+
cat > "${REVIEW_DIR}/${REVIEW_ID}-context.md" << EOF
|
|
397
|
+
# PR Review Context
|
|
398
|
+
|
|
399
|
+
## PR Information
|
|
400
|
+
- Number: #${PR_NUMBER}
|
|
401
|
+
- Title: ${PR_TITLE}
|
|
402
|
+
...
|
|
403
|
+
EOF
|
|
404
|
+
|
|
405
|
+
# 3. Spawn deep review agent
|
|
406
|
+
Task(
|
|
407
|
+
prompt="
|
|
408
|
+
<files_to_read>
|
|
409
|
+
- ./CLAUDE.md
|
|
410
|
+
- ${REVIEW_CONTEXT_FILE}
|
|
411
|
+
</files_to_read>
|
|
412
|
+
|
|
413
|
+
You are a senior code reviewer performing comprehensive PR review.
|
|
414
|
+
Analyze across five dimensions: test, rationale, intent vs implementation,
|
|
415
|
+
impact analysis, and architectural review.
|
|
416
|
+
|
|
417
|
+
Return structured JSON with test_results, rationale, intent_vs_implementation,
|
|
418
|
+
impact_analysis, architectural_review, and overall_verdict.
|
|
419
|
+
",
|
|
420
|
+
subagent_type="general-purpose",
|
|
421
|
+
model="sonnet",
|
|
422
|
+
description="Deep review PR #${PR_NUMBER}"
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
# 4. Store results in .mgw/reviews/
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**State separation:**
|
|
429
|
+
- `.mgw/active/` — MGW pipeline state
|
|
430
|
+
- `.mgw/reviews/` — PR review state (think tank context)
|
|
431
|
+
- `.planning/` — GSD execution state
|
|
432
|
+
|
|
433
|
+
This separation gives the reviewer space to handle larger context for
|
|
434
|
+
mission-critical review processes without polluting pipeline or execution state.
|
|
435
|
+
|
|
436
|
+
## Consumers
|
|
437
|
+
|
|
438
|
+
| Pattern | Referenced By |
|
|
439
|
+
|---------|---------------|
|
|
440
|
+
| Standard spawn template | run.md, issue.md, pr.md, ask.md, review.md |
|
|
441
|
+
| PR deep review | review.md (new) |
|
|
442
|
+
| Comment classification | run.md (pre-flight) |
|
|
443
|
+
| Quick pipeline | run.md |
|
|
444
|
+
| Milestone pipeline | run.md, milestone.md |
|
|
445
|
+
| Question classification | ask.md |
|
|
446
|
+
| Model resolution | run.md |
|
|
377
447
|
| Utility patterns | run.md, pr.md, issue.md, sync.md, link.md, update.md, ask.md |
|
package/dist/bin/mgw.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var index = require('../index-
|
|
4
|
+
var index = require('../index-BiwU0uWA.cjs');
|
|
5
5
|
var require$$0 = require('commander');
|
|
6
6
|
var require$$1 = require('path');
|
|
7
7
|
var require$$0$2 = require('fs');
|
|
@@ -10,7 +10,7 @@ require('events');
|
|
|
10
10
|
|
|
11
11
|
var mgw$1 = {};
|
|
12
12
|
|
|
13
|
-
var version = "0.2.
|
|
13
|
+
var version = "0.2.2";
|
|
14
14
|
var require$$10 = {
|
|
15
15
|
version: version};
|
|
16
16
|
|
|
@@ -120,6 +120,20 @@ function requireMgw () {
|
|
|
120
120
|
const opts = this.optsWithGlobals();
|
|
121
121
|
await runAiCommand("next", "", opts);
|
|
122
122
|
});
|
|
123
|
+
program.command("status [milestone]").description("Project status dashboard \u2014 milestone progress, issue pipeline stages, open PRs").option("--board", "open GitHub Projects board URL").option("--watch", "live-refresh mode \u2014 redraws dashboard every N seconds").option("--interval <seconds>", "refresh interval for --watch (default: 30)").action(async function(milestone) {
|
|
124
|
+
const opts = this.optsWithGlobals();
|
|
125
|
+
if (opts.watch && opts.json) {
|
|
126
|
+
error("Error: --watch and --json cannot be used together.");
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
const args = [
|
|
130
|
+
milestone || "",
|
|
131
|
+
opts.board ? "--board" : "",
|
|
132
|
+
opts.watch ? "--watch" : "",
|
|
133
|
+
opts.interval ? `--interval ${opts.interval}` : ""
|
|
134
|
+
].filter(Boolean).join(" ");
|
|
135
|
+
await runAiCommand("status", args, opts);
|
|
136
|
+
});
|
|
123
137
|
program.command("issue <number>").description("Triage issue against codebase").action(async function(number) {
|
|
124
138
|
const opts = this.optsWithGlobals();
|
|
125
139
|
await runAiCommand("issue", number, opts);
|
|
@@ -578,9 +578,7 @@ This may indicate a corrupted installation. Try reinstalling mgw.`
|
|
|
578
578
|
if (o.json) {
|
|
579
579
|
args.push("--output-format", "json");
|
|
580
580
|
}
|
|
581
|
-
|
|
582
|
-
args.push(userPrompt);
|
|
583
|
-
}
|
|
581
|
+
args.push(userPrompt || "run");
|
|
584
582
|
if (o.dryRun) {
|
|
585
583
|
console.log("Would invoke: claude " + args.join(" "));
|
|
586
584
|
return Promise.resolve({ exitCode: 0, output: "" });
|
package/dist/lib/index.cjs
CHANGED