@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.
- package/README.md +55 -5
- package/bin/mgw-install.cjs +121 -24
- package/commands/board/configure.md +205 -0
- package/commands/board/create.md +688 -0
- package/commands/board/show.md +221 -0
- package/commands/board/sync.md +461 -0
- package/commands/board/views.md +253 -0
- package/commands/board.md +23 -1543
- package/commands/context.md +183 -0
- package/commands/handoff.md +169 -0
- package/commands/issue.md +62 -0
- package/commands/milestone.md +42 -43
- package/commands/project.md +19 -0
- package/commands/review.md +222 -42
- package/commands/run/execute.md +820 -0
- package/commands/run/pr-create.md +324 -0
- package/commands/run/triage.md +510 -0
- package/commands/run/worktree.md +95 -0
- package/commands/run.md +23 -1547
- package/commands/sync.md +69 -0
- package/commands/workflows/gsd.md +1 -13
- package/dist/bin/mgw.cjs +107 -15
- package/dist/{index-BiwU0uWA.cjs → index-B-_JvYpz.cjs} +885 -69
- package/dist/lib/index.cjs +653 -155
- package/package.json +5 -2
package/commands/sync.md
CHANGED
|
@@ -33,6 +33,18 @@ Run periodically or when starting a new session to get a clean view.
|
|
|
33
33
|
|
|
34
34
|
<process>
|
|
35
35
|
|
|
36
|
+
<step name="parse_arguments">
|
|
37
|
+
**Parse sync flags:**
|
|
38
|
+
```bash
|
|
39
|
+
FULL_SYNC=false
|
|
40
|
+
for arg in "$@"; do
|
|
41
|
+
case "$arg" in
|
|
42
|
+
--full) FULL_SYNC=true ;;
|
|
43
|
+
esac
|
|
44
|
+
done
|
|
45
|
+
```
|
|
46
|
+
</step>
|
|
47
|
+
|
|
36
48
|
<step name="pull_board_state">
|
|
37
49
|
**Pull board state to reconstruct missing local .mgw/active/ files.**
|
|
38
50
|
|
|
@@ -348,6 +360,63 @@ rebuilt from board data — triage results and GSD artifacts will need to be re-
|
|
|
348
360
|
issue advances to `planning` or beyond.
|
|
349
361
|
</step>
|
|
350
362
|
|
|
363
|
+
<step name="rebuild_from_committed">
|
|
364
|
+
**Rebuild project context from committed planning files (--full only):**
|
|
365
|
+
|
|
366
|
+
Only runs when `--full` flag is passed. This is the multi-machine context rebuild:
|
|
367
|
+
after `git pull`, a developer runs `mgw:sync --full` to reconstruct full project
|
|
368
|
+
context from committed `.planning/` files and the board.
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
if [ "$FULL_SYNC" = "true" ]; then
|
|
372
|
+
echo "Full sync: rebuilding project context from committed planning files..."
|
|
373
|
+
|
|
374
|
+
# 1. Check for committed ROADMAP.md
|
|
375
|
+
if [ -f ".planning/ROADMAP.md" ]; then
|
|
376
|
+
echo " Found committed ROADMAP.md"
|
|
377
|
+
ROADMAP_ANALYSIS=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs roadmap analyze 2>/dev/null || echo '{}')
|
|
378
|
+
PHASE_COUNT=$(echo "$ROADMAP_ANALYSIS" | python3 -c "import json,sys; print(len(json.load(sys.stdin).get('phases',[])))" 2>/dev/null || echo "0")
|
|
379
|
+
echo " ROADMAP.md contains ${PHASE_COUNT} phases"
|
|
380
|
+
else
|
|
381
|
+
echo " No committed ROADMAP.md found — planning context unavailable"
|
|
382
|
+
echo " (This is expected if the project hasn't run a milestone yet)"
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
# 2. Scan for committed phase artifacts
|
|
386
|
+
COMMITTED_PLANS=$(find .planning -name '*-PLAN.md' -not -path '.planning/quick/*' 2>/dev/null | wc -l)
|
|
387
|
+
COMMITTED_SUMMARIES=$(find .planning -name '*-SUMMARY.md' -not -path '.planning/quick/*' 2>/dev/null | wc -l)
|
|
388
|
+
echo " Committed phase plans: ${COMMITTED_PLANS}"
|
|
389
|
+
echo " Committed phase summaries: ${COMMITTED_SUMMARIES}"
|
|
390
|
+
|
|
391
|
+
# 3. If project.json is missing but board + ROADMAP exist, offer to reconstruct
|
|
392
|
+
if [ ! -f "${MGW_DIR}/project.json" ] && [ -f ".planning/ROADMAP.md" ] && [ -n "$BOARD_NODE_ID" ]; then
|
|
393
|
+
echo ""
|
|
394
|
+
echo " project.json is missing but ROADMAP.md and board are available."
|
|
395
|
+
echo " Run /mgw:project to reconstruct full project state."
|
|
396
|
+
echo " (Board state has been pulled — active issues are available)"
|
|
397
|
+
fi
|
|
398
|
+
|
|
399
|
+
# 4. Rebuild context cache from GitHub issue comments
|
|
400
|
+
echo " Rebuilding context cache from GitHub issue comments..."
|
|
401
|
+
node -e "
|
|
402
|
+
const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
|
|
403
|
+
ic.rebuildContextCache()
|
|
404
|
+
.then(stats => console.log(' Cached summaries for', stats.issueCount, 'issues across', stats.milestoneCount, 'milestones'))
|
|
405
|
+
.catch(e => console.error(' Cache rebuild failed:', e.message));
|
|
406
|
+
" 2>/dev/null || echo " Context cache rebuild skipped (issue-context module not available)"
|
|
407
|
+
|
|
408
|
+
# 5. Refresh Project README with current milestone progress
|
|
409
|
+
echo " Refreshing Project README..."
|
|
410
|
+
node -e "
|
|
411
|
+
const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
|
|
412
|
+
ic.updateProjectReadme()
|
|
413
|
+
.then(ok => console.log(ok ? ' Project README updated' : ' Project README skipped (no board configured)'))
|
|
414
|
+
.catch(() => console.log(' Project README refresh skipped'));
|
|
415
|
+
" 2>/dev/null || true
|
|
416
|
+
fi
|
|
417
|
+
```
|
|
418
|
+
</step>
|
|
419
|
+
|
|
351
420
|
<step name="scan_active">
|
|
352
421
|
**Scan all active issue states:**
|
|
353
422
|
|
|
@@ -364,24 +364,12 @@ and codebase to classify, then MGW presents the result and offers follow-up acti
|
|
|
364
364
|
- **NEVER** let MGW read application source code directly — spawn an analysis agent
|
|
365
365
|
- **NEVER** omit `subagent_type` from a Task() call — always specify the agent type
|
|
366
366
|
|
|
367
|
-
##
|
|
368
|
-
|
|
369
|
-
| Pattern | Referenced By |
|
|
370
|
-
|---------|-------------|
|
|
371
|
-
| Standard spawn template | run.md, issue.md, pr.md, ask.md, review.md |
|
|
372
|
-
| Comment classification | run.md (pre-flight), review.md (standalone) |
|
|
373
|
-
| Quick pipeline | run.md |
|
|
374
|
-
| Milestone pipeline | run.md, milestone.md |
|
|
375
|
-
| Question classification | ask.md |
|
|
376
|
-
| Model resolution | run.md |
|
|
377
|
-
TB|## PR Review Pattern
|
|
367
|
+
## PR Review Pattern
|
|
378
368
|
|
|
379
369
|
MGW:review has two modes:
|
|
380
370
|
1. **Issue Comment Review** (default) — Classifies new comments on an issue since triage
|
|
381
371
|
2. **PR Deep Review** (with --pr flag or PR URL) — Comprehensive senior engineer review
|
|
382
372
|
|
|
383
|
-
The PR Deep Review pattern below is for Mode 2. This is problem-solving orchestration
|
|
384
|
-
|
|
385
373
|
Used by `/mgw:review` for deep PR analysis. This is problem-solving orchestration
|
|
386
374
|
(not execution orchestration) — the reviewer has high autonomy to analyze, question
|
|
387
375
|
assumptions, and provide architectural guidance.
|
package/dist/bin/mgw.cjs
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var index = require('../index-
|
|
4
|
+
var index = require('../index-B-_JvYpz.cjs');
|
|
5
5
|
var require$$0 = require('commander');
|
|
6
6
|
var require$$1 = require('path');
|
|
7
|
-
var require$$
|
|
7
|
+
var require$$2 = require('fs');
|
|
8
8
|
var require$$0$1 = require('child_process');
|
|
9
|
+
require('os');
|
|
9
10
|
require('events');
|
|
10
11
|
|
|
11
12
|
var mgw$1 = {};
|
|
12
13
|
|
|
13
|
-
var version = "0.
|
|
14
|
-
var require$$
|
|
14
|
+
var version = "0.4.0";
|
|
15
|
+
var require$$11 = {
|
|
15
16
|
version: version};
|
|
16
17
|
|
|
17
18
|
var hasRequiredMgw;
|
|
@@ -21,17 +22,18 @@ function requireMgw () {
|
|
|
21
22
|
hasRequiredMgw = 1;
|
|
22
23
|
const { Command } = require$$0;
|
|
23
24
|
const path = require$$1;
|
|
24
|
-
const fs = require$$
|
|
25
|
+
const fs = require$$2;
|
|
25
26
|
const { execSync } = require$$0$1;
|
|
26
|
-
const {
|
|
27
|
+
const { ProviderManager } = index.requireProviderManager();
|
|
27
28
|
const { log, error, formatJson, verbose } = index.requireOutput();
|
|
28
29
|
const { getActiveDir, getCompletedDir, getMgwDir } = index.requireState();
|
|
29
30
|
const { getIssue, listIssues } = index.requireGithub();
|
|
30
31
|
const { createIssuesBrowser } = index.requireTui();
|
|
31
32
|
const { createSpinner } = index.requireSpinner();
|
|
32
|
-
const
|
|
33
|
+
const { startTimer } = index.requireLogger();
|
|
34
|
+
const pkg = require$$11;
|
|
33
35
|
const program = new Command();
|
|
34
|
-
program.name("mgw").description("GitHub issue pipeline automation \u2014 Day 1 idea to Go Live").version(pkg.version).option("--dry-run", "show what would happen without executing").option("--json", "output structured JSON").option("-v, --verbose", "show API calls and file writes").option("--debug", "full payloads and timings").option("--model <model>", "Claude model override");
|
|
36
|
+
program.name("mgw").description("GitHub issue pipeline automation \u2014 Day 1 idea to Go Live").version(pkg.version).option("--dry-run", "show what would happen without executing").option("--json", "output structured JSON").option("-v, --verbose", "show API calls and file writes").option("--debug", "full payloads and timings").option("--model <model>", "Claude model override").option("--provider <provider>", "AI provider override (default: claude)");
|
|
35
37
|
const STAGE_LABELS = {
|
|
36
38
|
run: "pipeline",
|
|
37
39
|
init: "init",
|
|
@@ -43,15 +45,21 @@ function requireMgw () {
|
|
|
43
45
|
next: "next"
|
|
44
46
|
};
|
|
45
47
|
async function runAiCommand(commandName, userPrompt, opts) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
const provider = ProviderManager.getProvider(opts.provider);
|
|
49
|
+
provider.assertAvailable();
|
|
50
|
+
const cmdFile = path.join(provider.getCommandsDir(), `${commandName}.md`);
|
|
48
51
|
const stageLabel = STAGE_LABELS[commandName] || commandName;
|
|
52
|
+
const issueMatch = String(userPrompt).match(/^\d+/);
|
|
53
|
+
const timer = startTimer({
|
|
54
|
+
command: commandName,
|
|
55
|
+
issue: issueMatch ? parseInt(issueMatch[0], 10) : void 0
|
|
56
|
+
});
|
|
49
57
|
if (opts.quiet) {
|
|
50
58
|
const spinner = createSpinner(`mgw:${stageLabel}`);
|
|
51
59
|
spinner.start();
|
|
52
60
|
let result;
|
|
53
61
|
try {
|
|
54
|
-
result = await
|
|
62
|
+
result = await provider.invoke(cmdFile, userPrompt, {
|
|
55
63
|
model: opts.model,
|
|
56
64
|
quiet: true,
|
|
57
65
|
dryRun: opts.dryRun,
|
|
@@ -59,12 +67,15 @@ function requireMgw () {
|
|
|
59
67
|
});
|
|
60
68
|
} catch (err) {
|
|
61
69
|
spinner.fail(`${stageLabel} failed`);
|
|
70
|
+
timer.finish("error", err.message);
|
|
62
71
|
throw err;
|
|
63
72
|
}
|
|
64
73
|
if (result.exitCode === 0) {
|
|
65
74
|
spinner.succeed(`${stageLabel} complete`);
|
|
75
|
+
timer.finish("ok");
|
|
66
76
|
} else {
|
|
67
77
|
spinner.fail(`${stageLabel} failed (exit ${result.exitCode})`);
|
|
78
|
+
timer.finish("error", `exit ${result.exitCode}`);
|
|
68
79
|
}
|
|
69
80
|
if (result.output) {
|
|
70
81
|
process.stdout.write(result.output);
|
|
@@ -75,12 +86,13 @@ function requireMgw () {
|
|
|
75
86
|
spinner.start();
|
|
76
87
|
await new Promise((r) => setTimeout(r, 80));
|
|
77
88
|
spinner.stop();
|
|
78
|
-
const result = await
|
|
89
|
+
const result = await provider.invoke(cmdFile, userPrompt, {
|
|
79
90
|
model: opts.model,
|
|
80
91
|
quiet: false,
|
|
81
92
|
dryRun: opts.dryRun,
|
|
82
93
|
json: opts.json
|
|
83
94
|
});
|
|
95
|
+
timer.finish(result.exitCode === 0 ? "ok" : "error", result.exitCode !== 0 ? `exit ${result.exitCode}` : void 0);
|
|
84
96
|
process.exitCode = result.exitCode;
|
|
85
97
|
}
|
|
86
98
|
}
|
|
@@ -150,6 +162,7 @@ function requireMgw () {
|
|
|
150
162
|
});
|
|
151
163
|
program.command("sync").description("Reconcile .mgw/ state with GitHub").action(async function() {
|
|
152
164
|
const opts = this.optsWithGlobals();
|
|
165
|
+
const syncTimer = startTimer({ command: "sync" });
|
|
153
166
|
const activeDir = getActiveDir();
|
|
154
167
|
if (!fs.existsSync(activeDir)) {
|
|
155
168
|
if (opts.json) {
|
|
@@ -192,7 +205,7 @@ function requireMgw () {
|
|
|
192
205
|
}
|
|
193
206
|
let ghIssue;
|
|
194
207
|
try {
|
|
195
|
-
ghIssue = getIssue(number);
|
|
208
|
+
ghIssue = await getIssue(number);
|
|
196
209
|
} catch (err) {
|
|
197
210
|
error(`Failed to fetch issue #${number} from GitHub: ${err.message}`);
|
|
198
211
|
results.push({ number, file, status: "error", error: err.message });
|
|
@@ -234,6 +247,7 @@ function requireMgw () {
|
|
|
234
247
|
const ok = results.filter((r) => r.status === "ok").length;
|
|
235
248
|
log(`sync complete: ${ok} up-to-date, ${archived} archived`);
|
|
236
249
|
}
|
|
250
|
+
syncTimer.finish("ok");
|
|
237
251
|
});
|
|
238
252
|
program.command("issues [filters...]").description("Browse open issues \u2014 interactive TUI in TTY, static table otherwise").option("--label <label>", "filter by label").option("--milestone <name>", "filter by milestone").option("--assignee <user>", 'filter by assignee ("all" = no filter, default: all)', "all").option("--state <state>", "issue state: open, closed, all (default: open)", "open").option("-s, --search <query>", "pre-populate fuzzy search input").option("--limit <n>", "max issues to load (default: 50)", "50").action(async function() {
|
|
239
253
|
const opts = this.optsWithGlobals();
|
|
@@ -248,7 +262,7 @@ function requireMgw () {
|
|
|
248
262
|
if (opts.milestone) ghFilters.milestone = opts.milestone;
|
|
249
263
|
let issues;
|
|
250
264
|
try {
|
|
251
|
-
issues = listIssues(ghFilters);
|
|
265
|
+
issues = await listIssues(ghFilters);
|
|
252
266
|
} catch (err) {
|
|
253
267
|
error("Failed to list issues: " + err.message);
|
|
254
268
|
process.exitCode = 1;
|
|
@@ -343,8 +357,86 @@ function requireMgw () {
|
|
|
343
357
|
log("Linked: " + refA + " <-> " + refB);
|
|
344
358
|
}
|
|
345
359
|
});
|
|
360
|
+
program.command("log").description("Query execution logs").option("--since <period>", "time period: 1d, 7d, 30d, or ISO date").option("--issue <number>", "filter by issue number").option("--command <name>", "filter by command name").option("--limit <n>", "max entries (default: 50)", "50").option("--metrics", "show aggregated metrics instead of log entries").action(function() {
|
|
361
|
+
const opts = this.optsWithGlobals();
|
|
362
|
+
const { readLogs, aggregateMetrics } = index.requireLogger();
|
|
363
|
+
const logOpts = {
|
|
364
|
+
since: opts.since,
|
|
365
|
+
issue: opts.issue ? parseInt(opts.issue, 10) : void 0,
|
|
366
|
+
command: opts.command,
|
|
367
|
+
limit: opts.metrics ? void 0 : parseInt(opts.limit, 10) || 50
|
|
368
|
+
};
|
|
369
|
+
const entries = readLogs(logOpts);
|
|
370
|
+
if (opts.metrics) {
|
|
371
|
+
const metrics = aggregateMetrics(entries);
|
|
372
|
+
if (opts.json) {
|
|
373
|
+
log(formatJson(metrics));
|
|
374
|
+
} else {
|
|
375
|
+
log(`Total invocations: ${metrics.total}`);
|
|
376
|
+
log(`Avg duration: ${metrics.avgDuration}ms`);
|
|
377
|
+
log(`Failure rate: ${metrics.failureRate}%`);
|
|
378
|
+
log("");
|
|
379
|
+
log("By command:");
|
|
380
|
+
for (const [cmd, stats] of Object.entries(metrics.byCommand)) {
|
|
381
|
+
log(` ${cmd}: ${stats.count} calls, ${stats.errors} errors, avg ${stats.avgDuration}ms`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (entries.length === 0) {
|
|
387
|
+
log("No log entries found.");
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (opts.json) {
|
|
391
|
+
log(formatJson(entries));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
for (const e of entries) {
|
|
395
|
+
const ts = e.timestamp ? e.timestamp.slice(0, 19).replace("T", " ") : "?";
|
|
396
|
+
const issue = e.issue ? `#${e.issue}` : "";
|
|
397
|
+
const dur = typeof e.duration_ms === "number" ? `${e.duration_ms}ms` : "";
|
|
398
|
+
const status = e.status === "error" ? `ERR: ${e.error || "unknown"}` : e.status;
|
|
399
|
+
log(`${ts} ${(e.command || "").padEnd(12)} ${issue.padEnd(6)} ${dur.padEnd(8)} ${status}`);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
program.command("metrics").description("Show execution metrics \u2014 success rates, durations, command usage").option("--since <period>", "time period: 1d, 7d, 30d, or ISO date (default: 7d)", "7d").option("--issue <number>", "filter by issue number").option("--command <name>", "filter by command name").action(function() {
|
|
403
|
+
const opts = this.optsWithGlobals();
|
|
404
|
+
const { readLogs, aggregateMetrics } = index.requireLogger();
|
|
405
|
+
const { USE_COLOR, COLORS } = index.requireOutput();
|
|
406
|
+
const logOpts = {
|
|
407
|
+
since: opts.since,
|
|
408
|
+
issue: opts.issue ? parseInt(opts.issue, 10) : void 0,
|
|
409
|
+
command: opts.command
|
|
410
|
+
};
|
|
411
|
+
const entries = readLogs(logOpts);
|
|
412
|
+
const metrics = aggregateMetrics(entries);
|
|
413
|
+
if (opts.json) {
|
|
414
|
+
log(formatJson(metrics));
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (metrics.total === 0) {
|
|
418
|
+
log("No log entries found for the given period.");
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const dim = USE_COLOR ? COLORS.dim : "";
|
|
422
|
+
const bold = USE_COLOR ? COLORS.bold : "";
|
|
423
|
+
const reset = USE_COLOR ? COLORS.reset : "";
|
|
424
|
+
log(`${bold}Execution Metrics${reset} ${dim}(${opts.since})${reset}`);
|
|
425
|
+
log("");
|
|
426
|
+
log(` Total invocations: ${metrics.total}`);
|
|
427
|
+
log(` Avg duration: ${metrics.avgDuration}ms`);
|
|
428
|
+
log(` Failure rate: ${metrics.failureRate}%`);
|
|
429
|
+
log("");
|
|
430
|
+
log(`${bold}By Command${reset}`);
|
|
431
|
+
log(`${" Command".padEnd(16)} ${"Calls".padEnd(8)} ${"Errors".padEnd(8)} ${"Avg ms".padEnd(10)}`);
|
|
432
|
+
log(` ${dim}${"\u2500".repeat(38)}${reset}`);
|
|
433
|
+
for (const [cmd, stats] of Object.entries(metrics.byCommand)) {
|
|
434
|
+
log(` ${cmd.padEnd(14)} ${String(stats.count).padEnd(8)} ${String(stats.errors).padEnd(8)} ${String(stats.avgDuration).padEnd(10)}`);
|
|
435
|
+
}
|
|
436
|
+
});
|
|
346
437
|
program.command("help").description("Show command reference").action(function() {
|
|
347
|
-
const
|
|
438
|
+
const opts = this.optsWithGlobals();
|
|
439
|
+
const helpMdPath = path.join(ProviderManager.getProvider(opts.provider).getCommandsDir(), "help.md");
|
|
348
440
|
let helpText;
|
|
349
441
|
try {
|
|
350
442
|
const raw = fs.readFileSync(helpMdPath, "utf-8");
|