@snipcodeit/mgw 0.1.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,243 @@
1
+ ---
2
+ name: mgw:sync
3
+ description: Reconcile local .mgw/ state with GitHub — archive completed, flag drift
4
+ argument-hint: ""
5
+ allowed-tools:
6
+ - Bash
7
+ - Read
8
+ - Write
9
+ - Edit
10
+ - AskUserQuestion
11
+ ---
12
+
13
+ <objective>
14
+ Catch drift between GitHub and local .mgw/ state. For each active issue, checks
15
+ if the GitHub issue is still open, if linked PRs were merged/closed, and if tracked
16
+ branches still exist. Moves completed items to .mgw/completed/, cleans up branches
17
+ and lingering worktrees, flags inconsistencies.
18
+
19
+ Run periodically or when starting a new session to get a clean view.
20
+ </objective>
21
+
22
+ <execution_context>
23
+ @~/.claude/commands/mgw/workflows/state.md
24
+ @~/.claude/commands/mgw/workflows/github.md
25
+ @~/.claude/commands/mgw/workflows/gsd.md
26
+ @~/.claude/commands/mgw/workflows/validation.md
27
+ </execution_context>
28
+
29
+ <process>
30
+
31
+ <step name="scan_active">
32
+ **Scan all active issue states:**
33
+
34
+ ```bash
35
+ ls .mgw/active/*.json 2>/dev/null
36
+ ```
37
+
38
+ If no active issues → "No active MGW issues. Nothing to sync."
39
+
40
+ For each file, load the JSON state.
41
+ </step>
42
+
43
+ <step name="check_each">
44
+ **For each active issue, check GitHub state:**
45
+
46
+ ```bash
47
+ # Issue state
48
+ gh issue view ${NUMBER} --json state,closed -q '{state: .state, closed: .closed}'
49
+
50
+ # PR state (if linked_pr exists)
51
+ gh pr view ${PR_NUMBER} --json state,mergedAt -q '{state: .state, mergedAt: .mergedAt}' 2>/dev/null
52
+
53
+ # Branch existence
54
+ git branch --list ${BRANCH_NAME} | grep -q . && echo "local" || echo "no-local"
55
+ git ls-remote --heads origin ${BRANCH_NAME} | grep -q . && echo "remote" || echo "no-remote"
56
+
57
+ # Worktree existence
58
+ git worktree list | grep -q "${BRANCH_NAME}" && echo "worktree" || echo "no-worktree"
59
+
60
+ # Comment delta (detect unreviewed comments since triage)
61
+ CURRENT_COMMENTS=$(gh issue view ${NUMBER} --json comments --jq '.comments | length' 2>/dev/null || echo "0")
62
+ STORED_COMMENTS="${triage.last_comment_count}" # From state file, may be null/missing
63
+ if [ -n "$STORED_COMMENTS" ] && [ "$STORED_COMMENTS" != "null" ]; then
64
+ COMMENT_DELTA=$(($CURRENT_COMMENTS - $STORED_COMMENTS))
65
+ else
66
+ COMMENT_DELTA=0 # No baseline — skip comment drift
67
+ fi
68
+ ```
69
+
70
+ **GSD milestone consistency check (maps-to links):**
71
+
72
+ Read all maps-to links from .mgw/cross-refs.json:
73
+
74
+ ```bash
75
+ MAPS_TO_LINKS=$(python3 -c "
76
+ import json
77
+ with open('.mgw/cross-refs.json') as f:
78
+ data = json.load(f)
79
+ links = data.get('links', [])
80
+ maps_to = [l for l in links if l.get('type') == 'maps-to']
81
+ print(json.dumps(maps_to))
82
+ ")
83
+ ```
84
+
85
+ For each maps-to link (format: { "a": "milestone:N", "b": "gsd-milestone:id", "type": "maps-to" }):
86
+ 1. Extract the GitHub milestone number from "a" (parse "milestone:N")
87
+ 2. Extract the GSD milestone ID from "b" (parse "gsd-milestone:id")
88
+ 3. Check if this GSD milestone ID appears in either:
89
+ - .planning/ROADMAP.md header (active milestone)
90
+ - .planning/MILESTONES.md (archived milestones)
91
+ 4. If found in neither: flag as inconsistent
92
+
93
+ ```bash
94
+ # Check each maps-to link
95
+ echo "$MAPS_TO_LINKS" | python3 -c "
96
+ import json, sys, os
97
+
98
+ links = json.load(sys.stdin)
99
+ inconsistent = []
100
+
101
+ for link in links:
102
+ a = link.get('a', '')
103
+ b = link.get('b', '')
104
+
105
+ if not a.startswith('milestone:') or not b.startswith('gsd-milestone:'):
106
+ continue
107
+
108
+ github_num = a.split(':')[1]
109
+ gsd_id = b.split(':', 1)[1]
110
+
111
+ found = False
112
+
113
+ # Check ROADMAP.md
114
+ if os.path.exists('.planning/ROADMAP.md'):
115
+ with open('.planning/ROADMAP.md') as f:
116
+ content = f.read()
117
+ if gsd_id in content:
118
+ found = True
119
+
120
+ # Check MILESTONES.md
121
+ if not found and os.path.exists('.planning/MILESTONES.md'):
122
+ with open('.planning/MILESTONES.md') as f:
123
+ content = f.read()
124
+ if gsd_id in content:
125
+ found = True
126
+
127
+ if not found:
128
+ inconsistent.append({'github_milestone': github_num, 'gsd_id': gsd_id})
129
+
130
+ for i in inconsistent:
131
+ print(f\"WARN: GitHub milestone #{i['github_milestone']} maps to GSD milestone '{i['gsd_id']}' which was not found in .planning/\")
132
+
133
+ if not inconsistent:
134
+ print('GSD milestone links: all consistent')
135
+ "
136
+ ```
137
+
138
+ Classify each issue into:
139
+ - **Completed:** Issue closed AND (PR merged OR no PR expected)
140
+ - **Stale:** PR merged but issue still open (auto-close missed)
141
+ - **Orphaned:** Branch deleted but work incomplete
142
+ - **Active:** Still in progress, everything consistent
143
+ - **Drift:** State file says one thing, GitHub says another
144
+ - **Unreviewed comments:** COMMENT_DELTA > 0 — new comments posted since triage that haven't been classified
145
+ </step>
146
+
147
+ <step name="health_check">
148
+ **GSD health check (if .planning/ exists):**
149
+
150
+ For repos with GSD initialized, run a health check and include in the sync report:
151
+ ```bash
152
+ if [ -d ".planning" ]; then
153
+ HEALTH=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs validate health 2>/dev/null || echo '{"status":"unknown"}')
154
+ fi
155
+ ```
156
+ This is read-only and additive — health status is included in the sync summary but does not block any reconciliation actions.
157
+ </step>
158
+
159
+ <step name="reconcile">
160
+ **Take action per classification:**
161
+
162
+ | Classification | Action |
163
+ |---------------|--------|
164
+ | Completed | Move state file to .mgw/completed/, clean up branch + worktree |
165
+ | Stale | Report: "Issue #N still open but PR #M merged — close issue?" |
166
+ | Orphaned | Report: "Branch deleted for #N but issue still open" |
167
+ | Active | No action, include in summary |
168
+ | Drift | Report specific mismatch, offer to update state |
169
+
170
+ **Branch cleanup for completed items:**
171
+
172
+ For each completed issue with linked branches:
173
+ ```bash
174
+ # Remove any lingering worktree first
175
+ WORKTREE_DIR=".worktrees/${BRANCH_NAME}"
176
+ if [ -d "${WORKTREE_DIR}" ]; then
177
+ git worktree remove "${WORKTREE_DIR}" 2>/dev/null
178
+ fi
179
+
180
+ # Clean up empty worktree parent dirs
181
+ rmdir .worktrees/issue 2>/dev/null
182
+ rmdir .worktrees 2>/dev/null
183
+ ```
184
+
185
+ Ask user before deleting branches:
186
+ ```
187
+ AskUserQuestion(
188
+ header: "Branch Cleanup",
189
+ question: "Delete merged branches for completed issues?",
190
+ options: [
191
+ { label: "Delete all", description: "Remove local + remote branches for all completed issues" },
192
+ { label: "Local only", description: "Remove local branches, keep remote" },
193
+ { label: "Skip", description: "Keep all branches" }
194
+ ]
195
+ )
196
+ ```
197
+
198
+ If user approves:
199
+ ```bash
200
+ # Delete local branch
201
+ git branch -d ${BRANCH_NAME} 2>/dev/null
202
+
203
+ # Delete remote branch (if user chose "Delete all")
204
+ git push origin --delete ${BRANCH_NAME} 2>/dev/null
205
+ ```
206
+ </step>
207
+
208
+ <step name="report">
209
+ **Present sync summary:**
210
+
211
+ ```
212
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
213
+ MGW ► SYNC
214
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
215
+
216
+ Active: ${active_count} issues in progress
217
+ Completed: ${completed_count} archived
218
+ Stale: ${stale_count} need attention
219
+ Orphaned: ${orphaned_count} need attention
220
+ Comments: ${comment_drift_count} issues with unreviewed comments
221
+ Branches: ${deleted_count} cleaned up
222
+ ${HEALTH ? 'GSD Health: ' + HEALTH.status : ''}
223
+
224
+ ${details_for_each_non_active_item}
225
+ ${comment_drift_details ? 'Unreviewed comments:\n' + comment_drift_details : ''}
226
+ ${gsd_milestone_consistency ? 'GSD Milestone Links:\n' + gsd_milestone_consistency : ''}
227
+
228
+ ```
229
+ </step>
230
+
231
+ </process>
232
+
233
+ <success_criteria>
234
+ - [ ] All .mgw/active/ files scanned
235
+ - [ ] GitHub state checked for each issue, PR, branch
236
+ - [ ] Comment delta checked for each active issue
237
+ - [ ] GSD milestone consistency checked for all maps-to links
238
+ - [ ] Completed items moved to .mgw/completed/
239
+ - [ ] Lingering worktrees cleaned up for completed items
240
+ - [ ] Branch deletion offered for completed items
241
+ - [ ] Stale/orphaned/drift items flagged (including comment drift and milestone inconsistencies)
242
+ - [ ] Summary presented
243
+ </success_criteria>
@@ -0,0 +1,282 @@
1
+ ---
2
+ name: mgw:update
3
+ description: Post a structured status comment on a GitHub issue
4
+ argument-hint: "<issue-number> [message]"
5
+ allowed-tools:
6
+ - Bash
7
+ - Read
8
+ - Write
9
+ - Edit
10
+ ---
11
+
12
+ <objective>
13
+ Post professional, structured status comments on GitHub issues. These comments serve
14
+ as a machine-readable audit trail — MGW reads them back for resume detection, sync,
15
+ and progress tracking.
16
+
17
+ Called automatically by mgw:run at every pipeline checkpoint, or manually with a custom
18
+ message. Each comment follows a consistent format with metadata headers and collapsible
19
+ detail sections.
20
+
21
+ When called without a message, auto-detects update type from .mgw/ pipeline_stage.
22
+ When called with a message, posts that as a custom update.
23
+
24
+ Appends cross-references from .mgw/cross-refs.json if related work exists.
25
+ Logs comment ID in state file to prevent duplicates.
26
+ </objective>
27
+
28
+ <execution_context>
29
+ @~/.claude/commands/mgw/workflows/state.md
30
+ @~/.claude/commands/mgw/workflows/github.md
31
+ </execution_context>
32
+
33
+ <context>
34
+ $ARGUMENTS — expects: <issue-number> [optional message]
35
+ </context>
36
+
37
+ <process>
38
+
39
+ <step name="parse_args">
40
+ **Parse issue number and optional message:**
41
+
42
+ First token: issue number (required).
43
+ Remaining tokens: custom message (optional).
44
+
45
+ If no issue number, check .mgw/active/ for exactly one active issue. If exactly one, use it. If zero or multiple, prompt:
46
+ ```
47
+ AskUserQuestion(
48
+ header: "Which Issue?",
49
+ question: "Which issue number do you want to update?",
50
+ followUp: null
51
+ )
52
+ ```
53
+ </step>
54
+
55
+ <step name="read_state">
56
+ **Read issue state:**
57
+
58
+ Find state file: `.mgw/active/${ISSUE_NUMBER}-*.json`
59
+
60
+ If not found → error: "No active MGW state for issue #${ISSUE_NUMBER}. Run /mgw:issue ${ISSUE_NUMBER} first."
61
+
62
+ Load state as $STATE.
63
+
64
+ Also load project.json if it exists (for milestone/phase context):
65
+ ```bash
66
+ REPO_ROOT=$(git rev-parse --show-toplevel)
67
+ MGW_DIR="${REPO_ROOT}/.mgw"
68
+ PROJECT_JSON=""
69
+ if [ -f "${MGW_DIR}/project.json" ]; then
70
+ PROJECT_JSON=$(cat "${MGW_DIR}/project.json")
71
+ fi
72
+ ```
73
+
74
+ Extract milestone and phase context:
75
+ ```bash
76
+ if [ -n "$PROJECT_JSON" ]; then
77
+ MILESTONE_CONTEXT=$(echo "$PROJECT_JSON" | python3 -c "
78
+ import json, sys
79
+ p = json.load(sys.stdin)
80
+ for m in p['milestones']:
81
+ for i in m.get('issues', []):
82
+ if i.get('github_number') == ${ISSUE_NUMBER}:
83
+ print(f\"Milestone: {m['name']} | Phase {i['phase_number']}: {i['phase_name']}\")
84
+ break
85
+ " 2>/dev/null || echo "")
86
+ fi
87
+ ```
88
+ </step>
89
+
90
+ <step name="build_comment">
91
+ **Build comment body:**
92
+
93
+ If custom message provided → use it wrapped in the standard format:
94
+ ```markdown
95
+ > **MGW** · `status-update` · ${timestamp}
96
+ > ${MILESTONE_CONTEXT}
97
+
98
+ ${custom_message}
99
+ ```
100
+
101
+ If no custom message → auto-detect from pipeline_stage and build structured comment:
102
+
103
+ **All comments follow this format:**
104
+ ```markdown
105
+ > **MGW** · `${stage_label}` · ${timestamp}
106
+ > ${MILESTONE_CONTEXT}
107
+
108
+ ### ${Stage Title}
109
+
110
+ ${Stage-specific body with structured data}
111
+
112
+ <details>
113
+ <summary>Pipeline State</summary>
114
+
115
+ | Field | Value |
116
+ |-------|-------|
117
+ | Stage | `${pipeline_stage}` |
118
+ | Route | `${gsd_route}` |
119
+ | Branch | `${branch_name}` |
120
+ | Duration | ${elapsed} |
121
+
122
+ </details>
123
+ ```
124
+
125
+ **Stage-specific templates:**
126
+
127
+ ---
128
+
129
+ **`triaged`** — Posted after triage analysis completes:
130
+ ```markdown
131
+ > **MGW** · `triage-complete` · ${timestamp}
132
+ > ${MILESTONE_CONTEXT}
133
+
134
+ ### Triage Complete
135
+
136
+ | | |
137
+ |---|---|
138
+ | **Scope** | ${scope_size} — ${file_count} files across ${system_list} |
139
+ | **Validity** | ${validity_status} |
140
+ | **Security** | ${security_risk} |
141
+ | **Route** | \`${gsd_route}\` — ${route_reasoning} |
142
+ | **Conflicts** | ${conflicts_or_none} |
143
+
144
+ Work begins on branch \`${branch_name}\`.
145
+
146
+ <details>
147
+ <summary>Affected Files</summary>
148
+
149
+ ${file_list_as_bullet_points}
150
+
151
+ </details>
152
+ ```
153
+
154
+ ---
155
+
156
+ **`planning`** — Posted after GSD planner completes:
157
+ ```markdown
158
+ > **MGW** · `planning-complete` · ${timestamp}
159
+ > ${MILESTONE_CONTEXT}
160
+
161
+ ### Planning Complete
162
+
163
+ Plan created via \`${gsd_route}\` with ${task_count} task(s).
164
+
165
+ | Task | Files | Action |
166
+ |------|-------|--------|
167
+ ${task_table_from_plan}
168
+
169
+ Execution starting.
170
+ ```
171
+
172
+ ---
173
+
174
+ **`executing`** — Posted during/after GSD executor:
175
+ ```markdown
176
+ > **MGW** · `execution-complete` · ${timestamp}
177
+ > ${MILESTONE_CONTEXT}
178
+
179
+ ### Execution Complete
180
+
181
+ ${commit_count} atomic commit(s) on branch \`${branch_name}\`.
182
+
183
+ **Changes:**
184
+ ${file_changes_grouped_by_module}
185
+
186
+ **Tests:** ${test_status}
187
+
188
+ Preparing pull request.
189
+ ```
190
+
191
+ ---
192
+
193
+ **`verifying`** — Posted after GSD verifier (--full mode only):
194
+ ```markdown
195
+ > **MGW** · `verification` · ${timestamp}
196
+ > ${MILESTONE_CONTEXT}
197
+
198
+ ### Verification
199
+
200
+ ${must_have_count}/${must_have_total} must-haves passed.
201
+
202
+ | Check | Status |
203
+ |-------|--------|
204
+ ${verification_table}
205
+ ```
206
+
207
+ ---
208
+
209
+ **`pr-created`** — Posted after PR is created:
210
+ ```markdown
211
+ > **MGW** · `pr-ready` · ${timestamp}
212
+ > ${MILESTONE_CONTEXT}
213
+
214
+ ### PR Ready
215
+
216
+ **PR #${pr_number}** — [${pr_title}](${pr_url})
217
+
218
+ Testing procedures posted on the PR.
219
+ This issue will auto-close when the PR is merged.
220
+
221
+ <details>
222
+ <summary>Pipeline Summary</summary>
223
+
224
+ | Stage | Duration | Status |
225
+ |-------|----------|--------|
226
+ | Triage | ${triage_duration} | ✓ |
227
+ | Planning | ${planning_duration} | ✓ |
228
+ | Execution | ${execution_duration} | ✓ |
229
+ ${verification_row}
230
+ | PR Creation | ${pr_duration} | ✓ |
231
+ | **Total** | **${total_duration}** | |
232
+
233
+ </details>
234
+ ```
235
+
236
+ ---
237
+
238
+ **Append cross-references** if .mgw/cross-refs.json has links for this issue:
239
+ ```markdown
240
+
241
+ ---
242
+ <sub>Related: ${cross_ref_list} · Managed by [MGW](https://github.com/snipcodeit/mgw)</sub>
243
+ ```
244
+ </step>
245
+
246
+ <step name="post_comment">
247
+ **Post comment and log:**
248
+
249
+ ```bash
250
+ gh issue comment $ISSUE_NUMBER --body "$COMMENT_BODY"
251
+ ```
252
+
253
+ Capture comment URL from output.
254
+
255
+ Update state file: append to comments_posted array:
256
+ ```json
257
+ { "type": "${update_type}", "timestamp": "$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs current-timestamp --raw)", "url": "${comment_url}" }
258
+ ```
259
+
260
+ Write updated state back to `.mgw/active/${filename}.json`.
261
+ </step>
262
+
263
+ <step name="report">
264
+ **Report to user:**
265
+
266
+ ```
267
+ Posted ${update_type} comment on #${ISSUE_NUMBER}: ${comment_url}
268
+ ```
269
+ </step>
270
+
271
+ </process>
272
+
273
+ <success_criteria>
274
+ - [ ] Issue number parsed from args or auto-detected from single active issue
275
+ - [ ] State file read from .mgw/active/
276
+ - [ ] Milestone/phase context loaded from project.json if available
277
+ - [ ] Comment body built (auto-detected type or custom message)
278
+ - [ ] Comment follows structured format with metadata header
279
+ - [ ] Cross-references appended if present
280
+ - [ ] Comment posted via gh issue comment
281
+ - [ ] Comment ID logged in state file (no duplicates)
282
+ </success_criteria>