@snipcodeit/mgw 0.2.2 → 0.4.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.
@@ -0,0 +1,324 @@
1
+ ---
2
+ name: mgw:run/pr-create
3
+ description: Create PR from GSD artifacts and clean up worktree
4
+ ---
5
+
6
+ <step name="create_pr">
7
+ **Create PR (task agent):**
8
+
9
+ After GSD execution completes (any route):
10
+
11
+ Push branch and gather artifacts:
12
+ ```bash
13
+ git push -u origin ${BRANCH_NAME}
14
+
15
+ # Structured summary data via gsd-tools (returns JSON with one_liner, key_files, tech_added, patterns, decisions)
16
+ SUMMARY_DATA=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs summary-extract "${gsd_artifacts_path}/*SUMMARY*" 2>/dev/null || echo '{}')
17
+ # Also keep raw summary for full context
18
+ SUMMARY=$(cat ${gsd_artifacts_path}/*SUMMARY* 2>/dev/null)
19
+ VERIFICATION=$(cat ${gsd_artifacts_path}/*VERIFICATION* 2>/dev/null)
20
+ COMMITS=$(git log ${DEFAULT_BRANCH}..HEAD --oneline)
21
+ CROSS_REFS=$(cat ${REPO_ROOT}/.mgw/cross-refs.json 2>/dev/null)
22
+ # Progress table for PR details section
23
+ PROGRESS_TABLE=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs progress table --raw 2>/dev/null || echo "")
24
+
25
+ **Verify execution evidence exists before creating PR:**
26
+ ```bash
27
+ SUMMARY_COUNT=$(ls ${gsd_artifacts_path}/*SUMMARY* 2>/dev/null | wc -l)
28
+ if [ "$SUMMARY_COUNT" -eq 0 ]; then
29
+ echo "MGW ERROR: No SUMMARY files found at ${gsd_artifacts_path}. Cannot create PR without execution evidence."
30
+ echo "This usually means the executor agent failed silently. Check the execution logs."
31
+ # Update pipeline_stage to "failed"
32
+ node -e "
33
+ const fs = require('fs'), path = require('path');
34
+ const activeDir = path.join(process.cwd(), '.mgw', 'active');
35
+ const files = fs.readdirSync(activeDir);
36
+ const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.json'));
37
+ if (file) {
38
+ const filePath = path.join(activeDir, file);
39
+ const state = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
40
+ state.pipeline_stage = 'failed';
41
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2));
42
+ }
43
+ " 2>/dev/null || true
44
+ exit 1
45
+ fi
46
+ ```
47
+
48
+ # Milestone/phase context for PR body
49
+ MILESTONE_TITLE=""
50
+ PHASE_INFO=""
51
+ DEPENDENCY_CHAIN=""
52
+ PROJECT_BOARD_URL=""
53
+ if [ -f "${REPO_ROOT}/.mgw/project.json" ]; then
54
+ MILESTONE_TITLE=$(python3 -c "
55
+ import json
56
+ p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
57
+ for m in p['milestones']:
58
+ for i in m.get('issues', []):
59
+ if i.get('github_number') == ${ISSUE_NUMBER}:
60
+ print(m['name'])
61
+ break
62
+ " 2>/dev/null || echo "")
63
+
64
+ PHASE_INFO=$(python3 -c "
65
+ import json
66
+ p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
67
+ total_phases = sum(len(m.get('issues', [])) for m in p['milestones'])
68
+ for m in p['milestones']:
69
+ for i in m.get('issues', []):
70
+ if i.get('github_number') == ${ISSUE_NUMBER}:
71
+ total_in_milestone = len(m.get('issues', []))
72
+ idx = [x['github_number'] for x in m['issues']].index(${ISSUE_NUMBER}) + 1
73
+ print(f\"Phase {i['phase_number']}: {i['phase_name']} (issue {idx}/{total_in_milestone} in milestone)\")
74
+ break
75
+ " 2>/dev/null || echo "")
76
+
77
+ DEPENDENCY_CHAIN=$(python3 -c "
78
+ import json
79
+ p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
80
+ refs = json.load(open('${REPO_ROOT}/.mgw/cross-refs.json'))
81
+ blockers = [l['b'].split(':')[1] for l in refs.get('links', [])
82
+ if l.get('type') == 'blocked-by' and l['a'] == 'issue:${ISSUE_NUMBER}']
83
+ blocks = [l['a'].split(':')[1] for l in refs.get('links', [])
84
+ if l.get('type') == 'blocked-by' and l['b'] == 'issue:${ISSUE_NUMBER}']
85
+ parts = []
86
+ if blockers: parts.append('Blocked by: ' + ', '.join(f'#{b}' for b in blockers))
87
+ if blocks: parts.append('Unblocks: ' + ', '.join(f'#{b}' for b in blocks))
88
+ print(' | '.join(parts) if parts else 'No dependencies')
89
+ " 2>/dev/null || echo "")
90
+
91
+ PROJECT_BOARD_URL=$(python3 -c "
92
+ import json
93
+ p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
94
+ print(p.get('project', {}).get('project_board', {}).get('url', ''))
95
+ " 2>/dev/null || echo "")
96
+ fi
97
+
98
+ # Phase Context from GitHub issue comments (multi-developer context sharing)
99
+ PHASE_CONTEXT=$(node -e "
100
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
101
+ ic.assembleIssueContext(${ISSUE_NUMBER})
102
+ .then(ctx => process.stdout.write(ctx));
103
+ " 2>/dev/null || echo "")
104
+ ```
105
+
106
+ Read issue state for context.
107
+
108
+ ```
109
+ Task(
110
+ prompt="
111
+ <files_to_read>
112
+ - ./CLAUDE.md (Project instructions — if exists, follow all guidelines)
113
+ - .agents/skills/ (Project skills — if dir exists, list skills, read SKILL.md for each, follow relevant rules)
114
+ </files_to_read>
115
+
116
+ Create a GitHub PR for issue #${ISSUE_NUMBER}.
117
+
118
+ <issue>
119
+ Title: ${issue_title}
120
+ Body: ${issue_body}
121
+ </issue>
122
+
123
+ <milestone_context>
124
+ Milestone: ${MILESTONE_TITLE}
125
+ Phase: ${PHASE_INFO}
126
+ Dependencies: ${DEPENDENCY_CHAIN}
127
+ Board: ${PROJECT_BOARD_URL}
128
+ </milestone_context>
129
+
130
+ <summary_structured>
131
+ ${SUMMARY_DATA}
132
+ </summary_structured>
133
+
134
+ <summary_raw>
135
+ ${SUMMARY}
136
+ </summary_raw>
137
+
138
+ <verification>
139
+ ${VERIFICATION}
140
+ </verification>
141
+
142
+ <artifact_warnings>
143
+ ${ARTIFACT_CHECK}
144
+ ${KEYLINK_CHECK}
145
+ </artifact_warnings>
146
+
147
+ <commits>
148
+ ${COMMITS}
149
+ </commits>
150
+
151
+ <cross_refs>
152
+ ${CROSS_REFS}
153
+ </cross_refs>
154
+
155
+ <phase_context>
156
+ ${PHASE_CONTEXT}
157
+ </phase_context>
158
+
159
+ <instructions>
160
+ 1. Build PR title: short, prefixed with fix:/feat:/refactor: based on issue labels. Under 70 characters.
161
+
162
+ 2. Build PR body using this EXACT structure (fill in from data above):
163
+
164
+ ## Summary
165
+ - 2-4 bullets of what was built and why (use one_liner from summary_structured if available)
166
+
167
+ Closes #${ISSUE_NUMBER}
168
+
169
+ ## Milestone Context
170
+ - **Milestone:** ${MILESTONE_TITLE}
171
+ - **Phase:** ${PHASE_INFO}
172
+ - **Dependencies:** ${DEPENDENCY_CHAIN}
173
+ (Skip this section entirely if MILESTONE_TITLE is empty)
174
+
175
+ ## Changes
176
+ - File-level changes grouped by module (use key_files from summary_structured)
177
+
178
+ ## Phase Context
179
+ <details>
180
+ <summary>Planning & execution context from GitHub issue comments</summary>
181
+
182
+ ${PHASE_CONTEXT}
183
+ </details>
184
+ (Skip if PHASE_CONTEXT is empty)
185
+
186
+ ## Test Plan
187
+ - Verification checklist from VERIFICATION artifact
188
+
189
+ ## Cross-References
190
+ - ${CROSS_REFS entries as bullet points}
191
+ (Skip if no cross-refs)
192
+
193
+ <details>
194
+ <summary>GSD Progress</summary>
195
+
196
+ ${PROGRESS_TABLE}
197
+ </details>
198
+ (Skip if PROGRESS_TABLE is empty)
199
+
200
+ 3. Create PR: gh pr create --title '<title>' --base '${DEFAULT_BRANCH}' --head '${BRANCH_NAME}' --body '<body>'
201
+ 4. Post testing procedures as separate PR comment: gh pr comment <pr_number> --body '<testing>'
202
+ 5. Return: PR number, PR URL
203
+ </instructions>
204
+ ",
205
+ subagent_type="general-purpose",
206
+ description="Create PR for #${ISSUE_NUMBER}"
207
+ )
208
+ ```
209
+
210
+ Parse PR number and URL from agent response.
211
+
212
+ Update state (at `${REPO_ROOT}/.mgw/active/`):
213
+ - linked_pr = PR number
214
+ - pipeline_stage = "pr-created"
215
+
216
+ Add cross-ref (at `${REPO_ROOT}/.mgw/cross-refs.json`): issue → PR.
217
+ </step>
218
+
219
+ <step name="cleanup_and_complete">
220
+ **Clean up worktree, post completion, and prompt sync:**
221
+
222
+ Return to main repo and remove worktree (branch persists for PR):
223
+ ```bash
224
+ cd "${REPO_ROOT}"
225
+ git worktree remove "${WORKTREE_DIR}" 2>/dev/null
226
+ rmdir "${REPO_ROOT}/.worktrees/issue" 2>/dev/null
227
+ rmdir "${REPO_ROOT}/.worktrees" 2>/dev/null
228
+ ```
229
+
230
+ Clear MGW labels at completion:
231
+ ```bash
232
+ # Pass empty string — removes all mgw: labels without applying a new one
233
+ remove_mgw_labels_and_apply ${ISSUE_NUMBER} ""
234
+ ```
235
+
236
+ Post-completion label reconciliation:
237
+ ```bash
238
+ # Post-completion label reconciliation — verify no stray MGW labels remain
239
+ LIVE_LABELS=$(gh issue view ${ISSUE_NUMBER} --json labels --jq '[.labels[].name]' 2>/dev/null || echo "[]")
240
+ STRAY_MGW=$(echo "$LIVE_LABELS" | python3 -c "
241
+ import json, sys
242
+ labels = json.load(sys.stdin)
243
+ stray = [l for l in labels if l.startswith('mgw:')]
244
+ print('\n'.join(stray))
245
+ " 2>/dev/null || echo "")
246
+
247
+ if [ -n "$STRAY_MGW" ]; then
248
+ echo "MGW WARNING: unexpected MGW labels still on issue after completion: $STRAY_MGW" >&2
249
+ fi
250
+
251
+ # Sync live labels back to .mgw/active state file
252
+ LIVE_LABELS_LIST=$(gh issue view ${ISSUE_NUMBER} --json labels --jq '[.labels[].name]' 2>/dev/null || echo "[]")
253
+ # Update labels field in ${REPO_ROOT}/.mgw/active/${STATE_FILE} using python3 json patch:
254
+ python3 -c "
255
+ import json, sys
256
+ path = sys.argv[1]
257
+ live = json.loads(sys.argv[2])
258
+ with open(path) as f: state = json.load(f)
259
+ state['labels'] = live
260
+ with open(path, 'w') as f: json.dump(state, f, indent=2)
261
+ " "${REPO_ROOT}/.mgw/active/${STATE_FILE}" "$LIVE_LABELS_LIST" 2>/dev/null || true
262
+ ```
263
+
264
+ Extract one-liner summary for concise comment:
265
+ ```bash
266
+ ONE_LINER=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs summary-extract "${gsd_artifacts_path}/*SUMMARY*" --fields one_liner --raw 2>/dev/null || echo "")
267
+ ```
268
+
269
+ Post structured PR-ready comment directly (no sub-agent — guarantees it happens):
270
+
271
+ ```bash
272
+ DONE_TIMESTAMP=$(node -e "try{process.stdout.write(require('./lib/gsd-adapter.cjs').getTimestamp())}catch(e){process.stdout.write(new Date().toISOString().replace(/\\.\\d{3}Z$/,'Z'))}")
273
+
274
+ PR_READY_BODY=$(cat <<COMMENTEOF
275
+ > **MGW** · \`pr-ready\` · ${DONE_TIMESTAMP}
276
+ > ${MILESTONE_CONTEXT}
277
+
278
+ ### PR Ready
279
+
280
+ **PR #${PR_NUMBER}** — ${PR_URL}
281
+
282
+ ${ONE_LINER}
283
+
284
+ Testing procedures posted on the PR.
285
+ This issue will auto-close when the PR is merged.
286
+
287
+ <details>
288
+ <summary>Pipeline Summary</summary>
289
+
290
+ | Stage | Status |
291
+ |-------|--------|
292
+ | Triage | ✓ |
293
+ | Planning | ✓ |
294
+ | Execution | ✓ |
295
+ | PR Creation | ✓ |
296
+
297
+ </details>
298
+ COMMENTEOF
299
+ )
300
+
301
+ gh issue comment ${ISSUE_NUMBER} --body "$PR_READY_BODY" 2>/dev/null || true
302
+ ```
303
+
304
+ Update pipeline_stage to "done" (at `${REPO_ROOT}/.mgw/active/`).
305
+
306
+ Report to user:
307
+ ```
308
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
309
+ MGW ► PIPELINE COMPLETE
310
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
311
+
312
+ Issue: #${ISSUE_NUMBER} — ${issue_title}
313
+ Route: ${gsd_route}
314
+ PR: #${PR_NUMBER} — ${PR_URL}
315
+ Branch: ${BRANCH_NAME} (worktree cleaned up)
316
+
317
+ Status comments posted. PR includes testing procedures.
318
+ Issue will auto-close on merge.
319
+
320
+ Next:
321
+ → Review the PR, then merge
322
+ → After merge: /mgw:sync to archive state and clean up branches
323
+ ```
324
+ </step>