@snipcodeit/mgw 0.4.0 → 0.6.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/README.md +1 -0
- package/commands/run/execute.md +456 -24
- package/commands/run/pr-create.md +46 -0
- package/commands/run/triage.md +199 -2
- package/commands/workflows/gsd.md +71 -0
- package/commands/workflows/state.md +340 -1
- package/dist/bin/mgw.cjs +2 -2
- package/dist/{index-B-_JvYpz.cjs → index-CHrVAIMY.cjs} +197 -1
- package/dist/lib/index.cjs +524 -2
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@snipcodeit/mgw)
|
|
4
4
|
[](https://github.com/snipcodeit/mgw/actions/workflows/ci.yml)
|
|
5
|
+
[](./coverage/lcov-report/index.html)
|
|
5
6
|
[](https://www.npmjs.com/package/@snipcodeit/mgw)
|
|
6
7
|
[](https://opensource.org/licenses/MIT)
|
|
7
8
|
[](https://nodejs.org)
|
package/commands/run/execute.md
CHANGED
|
@@ -4,9 +4,16 @@ description: Execute GSD pipeline (quick or milestone route) and post execution
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
<step name="execute_gsd_quick">
|
|
7
|
-
**Execute GSD pipeline (quick / quick --full route):**
|
|
7
|
+
**Execute GSD pipeline (quick / quick --full / plan-phase route):**
|
|
8
8
|
|
|
9
|
-
Only run this step if gsd_route
|
|
9
|
+
Only run this step if gsd_route matches any of these (prefixed or unprefixed):
|
|
10
|
+
- `quick` or `gsd:quick`
|
|
11
|
+
- `quick --full` or `gsd:quick --full`
|
|
12
|
+
- `plan-phase` or `gsd:plan-phase`
|
|
13
|
+
|
|
14
|
+
`plan-phase` follows the same lifecycle as `quick --full` (init -> plan -> check -> execute -> verify -> publish) so it is handled here with FULL_MODE forced on.
|
|
15
|
+
|
|
16
|
+
`plan-phase` follows the same lifecycle as `quick --full` (init → plan → check → execute → verify → publish) so it is handled here with FULL_MODE forced on.
|
|
10
17
|
|
|
11
18
|
**Retry loop initialization:**
|
|
12
19
|
```bash
|
|
@@ -60,7 +67,7 @@ QUICK_DIR=".planning/quick/${next_num}-${slug}"
|
|
|
60
67
|
mkdir -p "$QUICK_DIR"
|
|
61
68
|
```
|
|
62
69
|
|
|
63
|
-
3. **Assemble MGW context and spawn planner (task agent):**
|
|
70
|
+
3. **Assemble MGW context and spawn planner (task agent, with diagnostic capture):**
|
|
64
71
|
|
|
65
72
|
Assemble multi-machine context from GitHub issue comments before spawning:
|
|
66
73
|
```bash
|
|
@@ -77,6 +84,23 @@ ic.buildGSDPromptContext({
|
|
|
77
84
|
" 2>/dev/null || echo "")
|
|
78
85
|
```
|
|
79
86
|
|
|
87
|
+
<!-- mgw:criticality=critical spawn_point=planner -->
|
|
88
|
+
<!-- Critical: plan creation is required for pipeline to proceed.
|
|
89
|
+
On failure: retry via existing retry loop, then dead-letter. -->
|
|
90
|
+
|
|
91
|
+
**Pre-spawn diagnostic hook (planner):**
|
|
92
|
+
```bash
|
|
93
|
+
DIAG_PLANNER=$(node -e "
|
|
94
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
95
|
+
const id = dh.beforeAgentSpawn({
|
|
96
|
+
agentType: 'gsd-planner',
|
|
97
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
98
|
+
prompt: 'Plan: ${issue_title}',
|
|
99
|
+
repoRoot: '${REPO_ROOT}'
|
|
100
|
+
});
|
|
101
|
+
process.stdout.write(id);
|
|
102
|
+
" 2>/dev/null || echo "")
|
|
103
|
+
```
|
|
80
104
|
```
|
|
81
105
|
Task(
|
|
82
106
|
prompt="
|
|
@@ -127,6 +151,53 @@ Return: ## PLANNING COMPLETE with plan path
|
|
|
127
151
|
)
|
|
128
152
|
```
|
|
129
153
|
|
|
154
|
+
4. **Update checkpoint after planner completes:**
|
|
155
|
+
```bash
|
|
156
|
+
# Checkpoint: record plan completion and set resume to plan-check or execution
|
|
157
|
+
node -e "
|
|
158
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
159
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
160
|
+
pipeline_step: 'plan',
|
|
161
|
+
step_progress: { plan_path: '${QUICK_DIR}/${next_num}-PLAN.md', plan_checked: false, revision_count: 0 },
|
|
162
|
+
last_agent_output: '${QUICK_DIR}/${next_num}-PLAN.md',
|
|
163
|
+
artifacts: [{ path: '${QUICK_DIR}/${next_num}-PLAN.md', type: 'plan', created_at: new Date().toISOString() }],
|
|
164
|
+
step_history: [{ step: 'plan', completed_at: new Date().toISOString(), agent_type: 'gsd-planner', output_path: '${QUICK_DIR}/${next_num}-PLAN.md' }],
|
|
165
|
+
resume: { action: '${FULL_MODE ? \"run-plan-checker\" : \"spawn-executor\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
|
|
166
|
+
|
|
167
|
+
**Post-spawn diagnostic hook (planner):**
|
|
168
|
+
```bash
|
|
169
|
+
PLANNER_EXIT=$( [ -f "${QUICK_DIR}/${next_num}-PLAN.md" ] && echo "success" || echo "error" )
|
|
170
|
+
node -e "
|
|
171
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
172
|
+
dh.afterAgentSpawn({
|
|
173
|
+
diagId: '${DIAG_PLANNER}',
|
|
174
|
+
exitReason: '${PLANNER_EXIT}',
|
|
175
|
+
repoRoot: '${REPO_ROOT}'
|
|
176
|
+
});
|
|
177
|
+
" 2>/dev/null || true
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
4. **Checkpoint: record plan completion (atomic write):**
|
|
181
|
+
```bash
|
|
182
|
+
# Checkpoint: record plan completion and set resume to plan-check or execution.
|
|
183
|
+
# All checkpoint writes use atomicWriteJson() — write to .tmp then rename.
|
|
184
|
+
node -e "
|
|
185
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
186
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
187
|
+
pipeline_step: 'plan',
|
|
188
|
+
step_progress: { plan_path: '${QUICK_DIR}/${next_num}-PLAN.md', plan_checked: false, revision_count: 0 },
|
|
189
|
+
last_agent_output: '${QUICK_DIR}/${next_num}-PLAN.md',
|
|
190
|
+
artifacts: [{ path: '${QUICK_DIR}/${next_num}-PLAN.md', type: 'plan', created_at: new Date().toISOString() }],
|
|
191
|
+
step_history: [{ step: 'plan', completed_at: new Date().toISOString(), agent_type: 'gsd-planner', output_path: '${QUICK_DIR}/${next_num}-PLAN.md' }],
|
|
192
|
+
resume: { action: '${FULL_MODE ? \"run-plan-checker\" : \"spawn-executor\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
|
|
193
|
+
});
|
|
194
|
+
" 2>/dev/null || true
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
4b. **Publish plan comment (non-blocking):**
|
|
198
|
+
|
|
199
|
+
4b. **Publish plan comment (non-blocking):**
|
|
200
|
+
|
|
130
201
|
4. **Publish plan comment (non-blocking):**
|
|
131
202
|
```bash
|
|
132
203
|
PLAN_FILE="${QUICK_DIR}/${next_num}-PLAN.md"
|
|
@@ -150,6 +221,37 @@ PLAN_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify plan-structur
|
|
|
150
221
|
Parse the JSON result. If structural issues found, include them in the plan-checker prompt below so it has concrete problems to evaluate rather than searching from scratch.
|
|
151
222
|
|
|
152
223
|
6. **(If --full) Spawn plan-checker, handle revision loop (max 2 iterations):**
|
|
224
|
+
|
|
225
|
+
<!-- mgw:criticality=advisory spawn_point=plan-checker -->
|
|
226
|
+
<!-- Advisory: plan checking is a quality gate, not a pipeline blocker.
|
|
227
|
+
If this agent fails, log a warning and proceed with the unchecked plan.
|
|
228
|
+
The plan was already verified structurally by gsd-tools verify plan-structure.
|
|
229
|
+
|
|
230
|
+
Graceful degradation pattern:
|
|
231
|
+
```
|
|
232
|
+
PLAN_CHECK_RESULT=$(wrapAdvisoryAgent(Task(...), 'plan-checker', {
|
|
233
|
+
issueNumber: ISSUE_NUMBER,
|
|
234
|
+
fallback: '## VERIFICATION PASSED (plan-checker unavailable — structural check only)'
|
|
235
|
+
}))
|
|
236
|
+
# If fallback returned, skip the revision loop and proceed to execution
|
|
237
|
+
```
|
|
238
|
+
-->
|
|
239
|
+
|
|
240
|
+
6. **(If --full) Spawn plan-checker (with diagnostic capture), handle revision loop (max 2 iterations):**
|
|
241
|
+
|
|
242
|
+
**Pre-spawn diagnostic hook (plan-checker):**
|
|
243
|
+
```bash
|
|
244
|
+
DIAG_CHECKER=$(node -e "
|
|
245
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
246
|
+
const id = dh.beforeAgentSpawn({
|
|
247
|
+
agentType: 'gsd-plan-checker',
|
|
248
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
249
|
+
prompt: 'Check quick plan: ${issue_title}',
|
|
250
|
+
repoRoot: '${REPO_ROOT}'
|
|
251
|
+
});
|
|
252
|
+
process.stdout.write(id);
|
|
253
|
+
" 2>/dev/null || echo "")
|
|
254
|
+
```
|
|
153
255
|
```
|
|
154
256
|
Task(
|
|
155
257
|
prompt="
|
|
@@ -191,10 +293,43 @@ Skip: context compliance (no CONTEXT.md), cross-plan deps (single plan), ROADMAP
|
|
|
191
293
|
)
|
|
192
294
|
```
|
|
193
295
|
|
|
296
|
+
**Post-spawn diagnostic hook (plan-checker):**
|
|
297
|
+
```bash
|
|
298
|
+
node -e "
|
|
299
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
300
|
+
dh.afterAgentSpawn({
|
|
301
|
+
diagId: '${DIAG_CHECKER}',
|
|
302
|
+
exitReason: 'success',
|
|
303
|
+
repoRoot: '${REPO_ROOT}'
|
|
304
|
+
});
|
|
305
|
+
" 2>/dev/null || true
|
|
306
|
+
```
|
|
307
|
+
|
|
194
308
|
If issues found and iteration < 2: spawn planner revision, then re-check.
|
|
195
309
|
If iteration >= 2: offer force proceed or abort.
|
|
196
310
|
|
|
197
311
|
7. **Spawn executor (task agent):**
|
|
312
|
+
|
|
313
|
+
<!-- mgw:criticality=critical spawn_point=executor -->
|
|
314
|
+
<!-- Critical: execution produces the code changes. Without it, there is
|
|
315
|
+
nothing to commit or PR. On failure: retry via existing retry loop,
|
|
316
|
+
then dead-letter. -->
|
|
317
|
+
|
|
318
|
+
7. **Spawn executor (task agent, with diagnostic capture):**
|
|
319
|
+
|
|
320
|
+
**Pre-spawn diagnostic hook (executor):**
|
|
321
|
+
```bash
|
|
322
|
+
DIAG_EXECUTOR=$(node -e "
|
|
323
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
324
|
+
const id = dh.beforeAgentSpawn({
|
|
325
|
+
agentType: 'gsd-executor',
|
|
326
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
327
|
+
prompt: 'Execute: ${issue_title}',
|
|
328
|
+
repoRoot: '${REPO_ROOT}'
|
|
329
|
+
});
|
|
330
|
+
process.stdout.write(id);
|
|
331
|
+
" 2>/dev/null || echo "")
|
|
332
|
+
```
|
|
198
333
|
```
|
|
199
334
|
Task(
|
|
200
335
|
prompt="
|
|
@@ -219,6 +354,52 @@ Execute quick task ${next_num}.
|
|
|
219
354
|
)
|
|
220
355
|
```
|
|
221
356
|
|
|
357
|
+
8. **Update checkpoint after executor completes:**
|
|
358
|
+
```bash
|
|
359
|
+
# Checkpoint: record execution completion and set resume to verification
|
|
360
|
+
node -e "
|
|
361
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
362
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
363
|
+
pipeline_step: 'execute',
|
|
364
|
+
step_progress: { tasks_completed: ${TASK_COUNT}, tasks_total: ${TASK_COUNT} },
|
|
365
|
+
last_agent_output: '${QUICK_DIR}/${next_num}-SUMMARY.md',
|
|
366
|
+
artifacts: [{ path: '${QUICK_DIR}/${next_num}-SUMMARY.md', type: 'summary', created_at: new Date().toISOString() }],
|
|
367
|
+
step_history: [{ step: 'execute', completed_at: new Date().toISOString(), agent_type: 'gsd-executor', output_path: '${QUICK_DIR}/${next_num}-SUMMARY.md' }],
|
|
368
|
+
resume: { action: '${FULL_MODE ? \"spawn-verifier\" : \"create-pr\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
|
|
369
|
+
|
|
370
|
+
**Post-spawn diagnostic hook (executor):**
|
|
371
|
+
```bash
|
|
372
|
+
EXECUTOR_EXIT=$( [ -f "${QUICK_DIR}/${next_num}-SUMMARY.md" ] && echo "success" || echo "error" )
|
|
373
|
+
node -e "
|
|
374
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
375
|
+
dh.afterAgentSpawn({
|
|
376
|
+
diagId: '${DIAG_EXECUTOR}',
|
|
377
|
+
exitReason: '${EXECUTOR_EXIT}',
|
|
378
|
+
repoRoot: '${REPO_ROOT}'
|
|
379
|
+
});
|
|
380
|
+
" 2>/dev/null || true
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
8. **Checkpoint: record execution completion (atomic write):**
|
|
384
|
+
```bash
|
|
385
|
+
# Checkpoint: record execution completion and set resume to verification or PR creation.
|
|
386
|
+
node -e "
|
|
387
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
388
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
389
|
+
pipeline_step: 'execute',
|
|
390
|
+
step_progress: { tasks_completed: ${TASK_COUNT}, tasks_total: ${TASK_COUNT} },
|
|
391
|
+
last_agent_output: '${QUICK_DIR}/${next_num}-SUMMARY.md',
|
|
392
|
+
artifacts: [{ path: '${QUICK_DIR}/${next_num}-SUMMARY.md', type: 'summary', created_at: new Date().toISOString() }],
|
|
393
|
+
step_history: [{ step: 'execute', completed_at: new Date().toISOString(), agent_type: 'gsd-executor', output_path: '${QUICK_DIR}/${next_num}-SUMMARY.md' }],
|
|
394
|
+
resume: { action: '${FULL_MODE ? \"spawn-verifier\" : \"create-pr\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
|
|
395
|
+
});
|
|
396
|
+
" 2>/dev/null || true
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
8b. **Publish summary comment (non-blocking):**
|
|
400
|
+
|
|
401
|
+
8b. **Publish summary comment (non-blocking):**
|
|
402
|
+
|
|
222
403
|
8. **Publish summary comment (non-blocking):**
|
|
223
404
|
```bash
|
|
224
405
|
SUMMARY_FILE="${QUICK_DIR}/${next_num}-SUMMARY.md"
|
|
@@ -240,6 +421,39 @@ VERIFY_RESULT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify-summary "$
|
|
|
240
421
|
Parse JSON result. Use `passed` field for go/no-go. Checks summary existence, files created, and commits.
|
|
241
422
|
|
|
242
423
|
9. **(If --full) Spawn verifier:**
|
|
424
|
+
|
|
425
|
+
<!-- mgw:criticality=advisory spawn_point=verifier -->
|
|
426
|
+
<!-- Advisory: verification is quality assurance after execution is complete.
|
|
427
|
+
The code changes and commits already exist. If verification fails,
|
|
428
|
+
log a warning and proceed to PR creation with a note that verification
|
|
429
|
+
was skipped.
|
|
430
|
+
|
|
431
|
+
Graceful degradation pattern:
|
|
432
|
+
```
|
|
433
|
+
VERIFY_RESULT=$(wrapAdvisoryAgent(Task(...), 'verifier', {
|
|
434
|
+
issueNumber: ISSUE_NUMBER,
|
|
435
|
+
fallback: null
|
|
436
|
+
}))
|
|
437
|
+
# If fallback returned (null), create a minimal VERIFICATION.md:
|
|
438
|
+
# "## VERIFICATION SKIPPED\nVerifier agent unavailable. Manual review recommended."
|
|
439
|
+
```
|
|
440
|
+
-->
|
|
441
|
+
|
|
442
|
+
9. **(If --full) Spawn verifier (with diagnostic capture):**
|
|
443
|
+
|
|
444
|
+
**Pre-spawn diagnostic hook (verifier):**
|
|
445
|
+
```bash
|
|
446
|
+
DIAG_VERIFIER=$(node -e "
|
|
447
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
448
|
+
const id = dh.beforeAgentSpawn({
|
|
449
|
+
agentType: 'gsd-verifier',
|
|
450
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
451
|
+
prompt: 'Verify: ${issue_title}',
|
|
452
|
+
repoRoot: '${REPO_ROOT}'
|
|
453
|
+
});
|
|
454
|
+
process.stdout.write(id);
|
|
455
|
+
" 2>/dev/null || echo "")
|
|
456
|
+
```
|
|
243
457
|
```
|
|
244
458
|
Task(
|
|
245
459
|
prompt="
|
|
@@ -260,6 +474,52 @@ Check must_haves against actual codebase. Create VERIFICATION.md at ${QUICK_DIR}
|
|
|
260
474
|
)
|
|
261
475
|
```
|
|
262
476
|
|
|
477
|
+
10. **Update checkpoint after verifier completes (--full only):**
|
|
478
|
+
```bash
|
|
479
|
+
# Checkpoint: record verification completion and set resume to PR creation
|
|
480
|
+
node -e "
|
|
481
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
482
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
483
|
+
pipeline_step: 'verify',
|
|
484
|
+
step_progress: { verification_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', must_haves_checked: true },
|
|
485
|
+
last_agent_output: '${QUICK_DIR}/${next_num}-VERIFICATION.md',
|
|
486
|
+
artifacts: [{ path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', type: 'verification', created_at: new Date().toISOString() }],
|
|
487
|
+
step_history: [{ step: 'verify', completed_at: new Date().toISOString(), agent_type: 'gsd-verifier', output_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md' }],
|
|
488
|
+
resume: { action: 'create-pr', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
|
|
489
|
+
|
|
490
|
+
**Post-spawn diagnostic hook (verifier):**
|
|
491
|
+
```bash
|
|
492
|
+
VERIFIER_EXIT=$( [ -f "${QUICK_DIR}/${next_num}-VERIFICATION.md" ] && echo "success" || echo "error" )
|
|
493
|
+
node -e "
|
|
494
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
495
|
+
dh.afterAgentSpawn({
|
|
496
|
+
diagId: '${DIAG_VERIFIER}',
|
|
497
|
+
exitReason: '${VERIFIER_EXIT}',
|
|
498
|
+
repoRoot: '${REPO_ROOT}'
|
|
499
|
+
});
|
|
500
|
+
" 2>/dev/null || true
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
10. **Checkpoint: record verification completion (atomic write, --full only):**
|
|
504
|
+
```bash
|
|
505
|
+
# Checkpoint: record verification completion and set resume to PR creation.
|
|
506
|
+
node -e "
|
|
507
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
508
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
509
|
+
pipeline_step: 'verify',
|
|
510
|
+
step_progress: { verification_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', must_haves_checked: true },
|
|
511
|
+
last_agent_output: '${QUICK_DIR}/${next_num}-VERIFICATION.md',
|
|
512
|
+
artifacts: [{ path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', type: 'verification', created_at: new Date().toISOString() }],
|
|
513
|
+
step_history: [{ step: 'verify', completed_at: new Date().toISOString(), agent_type: 'gsd-verifier', output_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md' }],
|
|
514
|
+
resume: { action: 'create-pr', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
|
|
515
|
+
});
|
|
516
|
+
" 2>/dev/null || true
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
10b. **Publish verification comment (non-blocking, --full only):**
|
|
520
|
+
|
|
521
|
+
10b. **Publish verification comment (non-blocking, --full only):**
|
|
522
|
+
|
|
263
523
|
10. **Publish verification comment (non-blocking, --full only):**
|
|
264
524
|
```bash
|
|
265
525
|
VERIFICATION_FILE="${QUICK_DIR}/${next_num}-VERIFICATION.md"
|
|
@@ -294,8 +554,13 @@ If any step above fails (executor or verifier agent returns error, summary missi
|
|
|
294
554
|
|
|
295
555
|
```bash
|
|
296
556
|
# On failure — classify and decide whether to retry
|
|
557
|
+
# CRITICALITY-AWARE: check if the failing agent is advisory first.
|
|
558
|
+
# Advisory agent failures are logged and skipped (pipeline continues).
|
|
559
|
+
# Critical agent failures follow the existing retry/dead-letter flow.
|
|
560
|
+
|
|
297
561
|
FAILURE_CLASS=$(node -e "
|
|
298
562
|
const { classifyFailure, canRetry, incrementRetry, getBackoffMs } = require('./lib/retry.cjs');
|
|
563
|
+
const { isAdvisory } = require('./lib/agent-criticality.cjs');
|
|
299
564
|
const { loadActiveIssue } = require('./lib/state.cjs');
|
|
300
565
|
const fs = require('fs'), path = require('path');
|
|
301
566
|
|
|
@@ -305,29 +570,43 @@ const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.js
|
|
|
305
570
|
const filePath = path.join(activeDir, file);
|
|
306
571
|
let issueState = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
307
572
|
|
|
308
|
-
//
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
issueState.last_failure_class = result.class;
|
|
315
|
-
|
|
316
|
-
if (result.class === 'transient' && canRetry(issueState)) {
|
|
317
|
-
const backoff = getBackoffMs(issueState.retry_count || 0);
|
|
318
|
-
issueState = incrementRetry(issueState);
|
|
319
|
-
fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
|
|
320
|
-
// Output: backoff ms so shell can sleep
|
|
321
|
-
console.log('retry:' + backoff + ':' + result.class);
|
|
573
|
+
// Check if the failing agent is advisory
|
|
574
|
+
const failingSpawnPoint = '${FAILING_SPAWN_POINT}';
|
|
575
|
+
if (failingSpawnPoint && isAdvisory(failingSpawnPoint)) {
|
|
576
|
+
// Advisory agent failure — log warning and continue pipeline
|
|
577
|
+
console.error('MGW WARNING: Advisory agent \"' + failingSpawnPoint + '\" failed. Continuing pipeline.');
|
|
578
|
+
console.log('advisory_degraded:' + failingSpawnPoint);
|
|
322
579
|
} else {
|
|
323
|
-
//
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
console.
|
|
580
|
+
// Critical agent failure — classify and apply retry/dead-letter logic
|
|
581
|
+
const error = { message: '${EXECUTION_ERROR_MESSAGE}' };
|
|
582
|
+
const result = classifyFailure(error);
|
|
583
|
+
console.error('Failure classified as: ' + result.class + ' — ' + result.reason);
|
|
584
|
+
|
|
585
|
+
// Persist failure class to state
|
|
586
|
+
issueState.last_failure_class = result.class;
|
|
587
|
+
|
|
588
|
+
if (result.class === 'transient' && canRetry(issueState)) {
|
|
589
|
+
const backoff = getBackoffMs(issueState.retry_count || 0);
|
|
590
|
+
issueState = incrementRetry(issueState);
|
|
591
|
+
fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
|
|
592
|
+
// Output: backoff ms so shell can sleep
|
|
593
|
+
console.log('retry:' + backoff + ':' + result.class);
|
|
594
|
+
} else {
|
|
595
|
+
// Permanent failure or retries exhausted — dead-letter
|
|
596
|
+
issueState.dead_letter = true;
|
|
597
|
+
fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
|
|
598
|
+
console.log('dead_letter:' + result.class);
|
|
599
|
+
}
|
|
327
600
|
}
|
|
328
601
|
")
|
|
329
602
|
|
|
330
603
|
case "$FAILURE_CLASS" in
|
|
604
|
+
advisory_degraded:*)
|
|
605
|
+
DEGRADED_AGENT=$(echo "$FAILURE_CLASS" | cut -d':' -f2)
|
|
606
|
+
echo "MGW: Advisory agent '${DEGRADED_AGENT}' failed — gracefully degraded, continuing pipeline."
|
|
607
|
+
# Do NOT set EXECUTION_SUCCEEDED=false — pipeline continues
|
|
608
|
+
# Skip to next step (advisory output is optional)
|
|
609
|
+
;;
|
|
331
610
|
retry:*)
|
|
332
611
|
BACKOFF_MS=$(echo "$FAILURE_CLASS" | cut -d':' -f2)
|
|
333
612
|
BACKOFF_SEC=$(( (BACKOFF_MS + 999) / 1000 ))
|
|
@@ -515,7 +794,7 @@ fi
|
|
|
515
794
|
# Parse PHASE_INIT JSON for: planner_model, checker_model
|
|
516
795
|
```
|
|
517
796
|
|
|
518
|
-
**b. Assemble MGW context and spawn planner agent (gsd:plan-phase):**
|
|
797
|
+
**b. Assemble MGW context and spawn planner agent (gsd:plan-phase, with diagnostic capture):**
|
|
519
798
|
|
|
520
799
|
Assemble multi-machine context from GitHub issue comments before spawning:
|
|
521
800
|
```bash
|
|
@@ -532,6 +811,23 @@ fi
|
|
|
532
811
|
" 2>/dev/null || echo "")
|
|
533
812
|
```
|
|
534
813
|
|
|
814
|
+
<!-- mgw:criticality=critical spawn_point=milestone-planner -->
|
|
815
|
+
<!-- Critical: phase planning is required — cannot execute without a plan.
|
|
816
|
+
On failure: retry via milestone retry loop, then dead-letter. -->
|
|
817
|
+
|
|
818
|
+
**Pre-spawn diagnostic hook (milestone planner):**
|
|
819
|
+
```bash
|
|
820
|
+
DIAG_MS_PLANNER=$(node -e "
|
|
821
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
822
|
+
const id = dh.beforeAgentSpawn({
|
|
823
|
+
agentType: 'gsd-planner',
|
|
824
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
825
|
+
prompt: 'Plan phase ${PHASE_NUMBER}: ${PHASE_NAME}',
|
|
826
|
+
repoRoot: '${REPO_ROOT}'
|
|
827
|
+
});
|
|
828
|
+
process.stdout.write(id);
|
|
829
|
+
" 2>/dev/null || echo "")
|
|
830
|
+
```
|
|
535
831
|
```
|
|
536
832
|
Task(
|
|
537
833
|
prompt="
|
|
@@ -565,6 +861,34 @@ fi
|
|
|
565
861
|
)
|
|
566
862
|
```
|
|
567
863
|
|
|
864
|
+
**Post-spawn diagnostic hook (milestone planner):**
|
|
865
|
+
```bash
|
|
866
|
+
MS_PLANNER_EXIT=$( ls ${phase_dir}/*-PLAN.md 2>/dev/null | wc -l | xargs test 0 -lt && echo "success" || echo "error" )
|
|
867
|
+
node -e "
|
|
868
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
869
|
+
dh.afterAgentSpawn({
|
|
870
|
+
diagId: '${DIAG_MS_PLANNER}',
|
|
871
|
+
exitReason: '${MS_PLANNER_EXIT}',
|
|
872
|
+
repoRoot: '${REPO_ROOT}'
|
|
873
|
+
});
|
|
874
|
+
" 2>/dev/null || true
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
**b1b. Checkpoint: record milestone phase plan completion (atomic write):**
|
|
878
|
+
```bash
|
|
879
|
+
# Checkpoint: record milestone plan completion for this phase.
|
|
880
|
+
node -e "
|
|
881
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
882
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
883
|
+
pipeline_step: 'plan',
|
|
884
|
+
step_progress: { gsd_phase: ${PHASE_NUMBER}, plan_path: '${phase_dir}' },
|
|
885
|
+
last_agent_output: '${phase_dir}',
|
|
886
|
+
step_history: [{ step: 'plan', completed_at: new Date().toISOString(), agent_type: 'gsd-planner', output_path: '${phase_dir}' }],
|
|
887
|
+
resume: { action: 'execute-phase', context: { phase_number: ${PHASE_NUMBER}, phase_dir: '${phase_dir}' } }
|
|
888
|
+
});
|
|
889
|
+
" 2>/dev/null || true
|
|
890
|
+
```
|
|
891
|
+
|
|
568
892
|
**b2. Publish plan comment (non-blocking):**
|
|
569
893
|
```bash
|
|
570
894
|
PLAN_FILES=$(ls ${phase_dir}/*-PLAN.md 2>/dev/null)
|
|
@@ -590,11 +914,30 @@ fi
|
|
|
590
914
|
fi
|
|
591
915
|
```
|
|
592
916
|
|
|
593
|
-
**d. Init execute-phase and spawn executor agent (gsd:execute-phase):**
|
|
917
|
+
**d. Init execute-phase and spawn executor agent (gsd:execute-phase, with diagnostic capture):**
|
|
594
918
|
```bash
|
|
595
919
|
EXEC_INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs init execute-phase "${PHASE_NUMBER}")
|
|
596
920
|
# Parse EXEC_INIT JSON for: executor_model, verifier_model, phase_dir, plans, incomplete_plans, plan_count
|
|
597
921
|
```
|
|
922
|
+
|
|
923
|
+
<!-- mgw:criticality=critical spawn_point=milestone-executor -->
|
|
924
|
+
<!-- Critical: phase execution produces the code changes. Without it,
|
|
925
|
+
there is nothing to commit or PR. On failure: retry via milestone
|
|
926
|
+
retry loop, then dead-letter. -->
|
|
927
|
+
|
|
928
|
+
**Pre-spawn diagnostic hook (milestone executor):**
|
|
929
|
+
```bash
|
|
930
|
+
DIAG_MS_EXECUTOR=$(node -e "
|
|
931
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
932
|
+
const id = dh.beforeAgentSpawn({
|
|
933
|
+
agentType: 'gsd-executor',
|
|
934
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
935
|
+
prompt: 'Execute phase ${PHASE_NUMBER}: ${PHASE_NAME}',
|
|
936
|
+
repoRoot: '${REPO_ROOT}'
|
|
937
|
+
});
|
|
938
|
+
process.stdout.write(id);
|
|
939
|
+
" 2>/dev/null || echo "")
|
|
940
|
+
```
|
|
598
941
|
```
|
|
599
942
|
Task(
|
|
600
943
|
prompt="
|
|
@@ -625,6 +968,34 @@ fi
|
|
|
625
968
|
)
|
|
626
969
|
```
|
|
627
970
|
|
|
971
|
+
**Post-spawn diagnostic hook (milestone executor):**
|
|
972
|
+
```bash
|
|
973
|
+
MS_EXECUTOR_EXIT=$( ls ${phase_dir}/*-SUMMARY.md 2>/dev/null | wc -l | xargs test 0 -lt && echo "success" || echo "error" )
|
|
974
|
+
node -e "
|
|
975
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
976
|
+
dh.afterAgentSpawn({
|
|
977
|
+
diagId: '${DIAG_MS_EXECUTOR}',
|
|
978
|
+
exitReason: '${MS_EXECUTOR_EXIT}',
|
|
979
|
+
repoRoot: '${REPO_ROOT}'
|
|
980
|
+
});
|
|
981
|
+
" 2>/dev/null || true
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
**d1b. Checkpoint: record milestone phase execution completion (atomic write):**
|
|
985
|
+
```bash
|
|
986
|
+
# Checkpoint: record milestone execution completion for this phase.
|
|
987
|
+
node -e "
|
|
988
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
989
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
990
|
+
pipeline_step: 'execute',
|
|
991
|
+
step_progress: { gsd_phase: ${PHASE_NUMBER} },
|
|
992
|
+
last_agent_output: '${phase_dir}',
|
|
993
|
+
step_history: [{ step: 'execute', completed_at: new Date().toISOString(), agent_type: 'gsd-executor', output_path: '${phase_dir}' }],
|
|
994
|
+
resume: { action: 'verify-phase', context: { phase_number: ${PHASE_NUMBER}, phase_dir: '${phase_dir}' } }
|
|
995
|
+
});
|
|
996
|
+
" 2>/dev/null || true
|
|
997
|
+
```
|
|
998
|
+
|
|
628
999
|
**d2. Publish summary comment (non-blocking):**
|
|
629
1000
|
```bash
|
|
630
1001
|
SUMMARY_FILES=$(ls ${phase_dir}/*-SUMMARY.md 2>/dev/null)
|
|
@@ -639,7 +1010,40 @@ fi
|
|
|
639
1010
|
done
|
|
640
1011
|
```
|
|
641
1012
|
|
|
642
|
-
|
|
1013
|
+
**e. Spawn verifier agent (gsd:verify-phase):**
|
|
1014
|
+
|
|
1015
|
+
<!-- mgw:criticality=advisory spawn_point=milestone-verifier -->
|
|
1016
|
+
<!-- Advisory: phase verification is quality assurance after execution
|
|
1017
|
+
completes. The code changes and commits already exist. If verification
|
|
1018
|
+
fails, log a warning and proceed with a note that verification was
|
|
1019
|
+
skipped for this phase.
|
|
1020
|
+
|
|
1021
|
+
Graceful degradation pattern:
|
|
1022
|
+
```
|
|
1023
|
+
VERIFY_RESULT=$(wrapAdvisoryAgent(Task(...), 'milestone-verifier', {
|
|
1024
|
+
issueNumber: ISSUE_NUMBER,
|
|
1025
|
+
fallback: null
|
|
1026
|
+
}))
|
|
1027
|
+
# If fallback returned, create minimal VERIFICATION.md:
|
|
1028
|
+
# "## VERIFICATION SKIPPED\nVerifier agent unavailable for phase ${PHASE_NUMBER}."
|
|
1029
|
+
```
|
|
1030
|
+
-->
|
|
1031
|
+
|
|
1032
|
+
**e. Spawn verifier agent (gsd:verify-phase, with diagnostic capture):**
|
|
1033
|
+
|
|
1034
|
+
**Pre-spawn diagnostic hook (milestone verifier):**
|
|
1035
|
+
```bash
|
|
1036
|
+
DIAG_MS_VERIFIER=$(node -e "
|
|
1037
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
1038
|
+
const id = dh.beforeAgentSpawn({
|
|
1039
|
+
agentType: 'gsd-verifier',
|
|
1040
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
1041
|
+
prompt: 'Verify phase ${PHASE_NUMBER}: ${PHASE_NAME}',
|
|
1042
|
+
repoRoot: '${REPO_ROOT}'
|
|
1043
|
+
});
|
|
1044
|
+
process.stdout.write(id);
|
|
1045
|
+
" 2>/dev/null || echo "")
|
|
1046
|
+
```
|
|
643
1047
|
```
|
|
644
1048
|
Task(
|
|
645
1049
|
prompt="
|
|
@@ -667,6 +1071,34 @@ fi
|
|
|
667
1071
|
)
|
|
668
1072
|
```
|
|
669
1073
|
|
|
1074
|
+
**Post-spawn diagnostic hook (milestone verifier):**
|
|
1075
|
+
```bash
|
|
1076
|
+
MS_VERIFIER_EXIT=$( ls ${phase_dir}/*-VERIFICATION.md 2>/dev/null | wc -l | xargs test 0 -lt && echo "success" || echo "error" )
|
|
1077
|
+
node -e "
|
|
1078
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
1079
|
+
dh.afterAgentSpawn({
|
|
1080
|
+
diagId: '${DIAG_MS_VERIFIER}',
|
|
1081
|
+
exitReason: '${MS_VERIFIER_EXIT}',
|
|
1082
|
+
repoRoot: '${REPO_ROOT}'
|
|
1083
|
+
});
|
|
1084
|
+
" 2>/dev/null || true
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
**e1b. Checkpoint: record milestone phase verification completion (atomic write):**
|
|
1088
|
+
```bash
|
|
1089
|
+
# Checkpoint: record milestone verification completion for this phase.
|
|
1090
|
+
node -e "
|
|
1091
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
1092
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
1093
|
+
pipeline_step: 'verify',
|
|
1094
|
+
step_progress: { gsd_phase: ${PHASE_NUMBER}, verification_complete: true },
|
|
1095
|
+
last_agent_output: '${phase_dir}',
|
|
1096
|
+
step_history: [{ step: 'verify', completed_at: new Date().toISOString(), agent_type: 'gsd-verifier', output_path: '${phase_dir}' }],
|
|
1097
|
+
resume: { action: 'next-phase', context: { completed_phase: ${PHASE_NUMBER}, phase_dir: '${phase_dir}' } }
|
|
1098
|
+
});
|
|
1099
|
+
" 2>/dev/null || true
|
|
1100
|
+
```
|
|
1101
|
+
|
|
670
1102
|
**e2. Publish verification comment (non-blocking):**
|
|
671
1103
|
```bash
|
|
672
1104
|
VERIFICATION_FILES=$(ls ${phase_dir}/*-VERIFICATION.md 2>/dev/null)
|
|
@@ -105,6 +105,26 @@ ic.assembleIssueContext(${ISSUE_NUMBER})
|
|
|
105
105
|
|
|
106
106
|
Read issue state for context.
|
|
107
107
|
|
|
108
|
+
<!-- mgw:criticality=critical spawn_point=pr-creator -->
|
|
109
|
+
<!-- Critical: PR creation is the pipeline's final output. Without it,
|
|
110
|
+
the entire pipeline run produces no deliverable. On failure: the
|
|
111
|
+
pipeline marks the issue as failed (no retry — PR creation errors
|
|
112
|
+
are typically permanent: branch conflicts, permissions, etc.). -->
|
|
113
|
+
|
|
114
|
+
**Pre-spawn diagnostic hook (PR creator):**
|
|
115
|
+
```bash
|
|
116
|
+
DIAG_PR_CREATOR=$(node -e "
|
|
117
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
118
|
+
const id = dh.beforeAgentSpawn({
|
|
119
|
+
agentType: 'general-purpose',
|
|
120
|
+
issueNumber: ${ISSUE_NUMBER},
|
|
121
|
+
prompt: 'Create PR for #${ISSUE_NUMBER}',
|
|
122
|
+
repoRoot: '${REPO_ROOT}'
|
|
123
|
+
});
|
|
124
|
+
process.stdout.write(id);
|
|
125
|
+
" 2>/dev/null || echo "")
|
|
126
|
+
```
|
|
127
|
+
|
|
108
128
|
```
|
|
109
129
|
Task(
|
|
110
130
|
prompt="
|
|
@@ -207,8 +227,34 @@ ${PROGRESS_TABLE}
|
|
|
207
227
|
)
|
|
208
228
|
```
|
|
209
229
|
|
|
230
|
+
**Post-spawn diagnostic hook (PR creator):**
|
|
231
|
+
```bash
|
|
232
|
+
node -e "
|
|
233
|
+
const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
|
|
234
|
+
dh.afterAgentSpawn({
|
|
235
|
+
diagId: '${DIAG_PR_CREATOR}',
|
|
236
|
+
exitReason: '${PR_NUMBER ? \"success\" : \"error\"}',
|
|
237
|
+
repoRoot: '${REPO_ROOT}'
|
|
238
|
+
});
|
|
239
|
+
" 2>/dev/null || true
|
|
240
|
+
```
|
|
241
|
+
|
|
210
242
|
Parse PR number and URL from agent response.
|
|
211
243
|
|
|
244
|
+
**Checkpoint: record PR creation (atomic write):**
|
|
245
|
+
```bash
|
|
246
|
+
# Checkpoint: record PR creation — final checkpoint before pipeline completion.
|
|
247
|
+
node -e "
|
|
248
|
+
const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
|
|
249
|
+
updateCheckpoint(${ISSUE_NUMBER}, {
|
|
250
|
+
pipeline_step: 'pr',
|
|
251
|
+
step_progress: { branch_pushed: true, pr_number: ${PR_NUMBER}, pr_url: '${PR_URL}' },
|
|
252
|
+
step_history: [{ step: 'pr', completed_at: new Date().toISOString(), agent_type: 'general-purpose', output_path: '${PR_URL}' }],
|
|
253
|
+
resume: { action: 'cleanup', context: { pr_number: ${PR_NUMBER}, pr_url: '${PR_URL}' } }
|
|
254
|
+
});
|
|
255
|
+
" 2>/dev/null || true
|
|
256
|
+
```
|
|
257
|
+
|
|
212
258
|
Update state (at `${REPO_ROOT}/.mgw/active/`):
|
|
213
259
|
- linked_pr = PR number
|
|
214
260
|
- pipeline_stage = "pr-created"
|