@snipcodeit/mgw 0.2.2 → 0.3.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.
@@ -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
- ## Consumers
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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var index = require('../index-BiwU0uWA.cjs');
4
+ var index = require('../index-s7v-ifd0.cjs');
5
5
  var require$$0 = require('commander');
6
6
  var require$$1 = require('path');
7
7
  var require$$0$2 = require('fs');
@@ -10,8 +10,8 @@ require('events');
10
10
 
11
11
  var mgw$1 = {};
12
12
 
13
- var version = "0.2.2";
14
- var require$$10 = {
13
+ var version = "0.3.0";
14
+ var require$$11 = {
15
15
  version: version};
16
16
 
17
17
  var hasRequiredMgw;
@@ -29,7 +29,8 @@ function requireMgw () {
29
29
  const { getIssue, listIssues } = index.requireGithub();
30
30
  const { createIssuesBrowser } = index.requireTui();
31
31
  const { createSpinner } = index.requireSpinner();
32
- const pkg = require$$10;
32
+ const { startTimer } = index.requireLogger();
33
+ const pkg = require$$11;
33
34
  const program = new Command();
34
35
  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");
35
36
  const STAGE_LABELS = {
@@ -46,6 +47,11 @@ function requireMgw () {
46
47
  assertClaudeAvailable();
47
48
  const cmdFile = path.join(getCommandsDir(), `${commandName}.md`);
48
49
  const stageLabel = STAGE_LABELS[commandName] || commandName;
50
+ const issueMatch = String(userPrompt).match(/^\d+/);
51
+ const timer = startTimer({
52
+ command: commandName,
53
+ issue: issueMatch ? parseInt(issueMatch[0], 10) : void 0
54
+ });
49
55
  if (opts.quiet) {
50
56
  const spinner = createSpinner(`mgw:${stageLabel}`);
51
57
  spinner.start();
@@ -59,12 +65,15 @@ function requireMgw () {
59
65
  });
60
66
  } catch (err) {
61
67
  spinner.fail(`${stageLabel} failed`);
68
+ timer.finish("error", err.message);
62
69
  throw err;
63
70
  }
64
71
  if (result.exitCode === 0) {
65
72
  spinner.succeed(`${stageLabel} complete`);
73
+ timer.finish("ok");
66
74
  } else {
67
75
  spinner.fail(`${stageLabel} failed (exit ${result.exitCode})`);
76
+ timer.finish("error", `exit ${result.exitCode}`);
68
77
  }
69
78
  if (result.output) {
70
79
  process.stdout.write(result.output);
@@ -81,6 +90,7 @@ function requireMgw () {
81
90
  dryRun: opts.dryRun,
82
91
  json: opts.json
83
92
  });
93
+ timer.finish(result.exitCode === 0 ? "ok" : "error", result.exitCode !== 0 ? `exit ${result.exitCode}` : void 0);
84
94
  process.exitCode = result.exitCode;
85
95
  }
86
96
  }
@@ -150,6 +160,7 @@ function requireMgw () {
150
160
  });
151
161
  program.command("sync").description("Reconcile .mgw/ state with GitHub").action(async function() {
152
162
  const opts = this.optsWithGlobals();
163
+ const syncTimer = startTimer({ command: "sync" });
153
164
  const activeDir = getActiveDir();
154
165
  if (!fs.existsSync(activeDir)) {
155
166
  if (opts.json) {
@@ -192,7 +203,7 @@ function requireMgw () {
192
203
  }
193
204
  let ghIssue;
194
205
  try {
195
- ghIssue = getIssue(number);
206
+ ghIssue = await getIssue(number);
196
207
  } catch (err) {
197
208
  error(`Failed to fetch issue #${number} from GitHub: ${err.message}`);
198
209
  results.push({ number, file, status: "error", error: err.message });
@@ -234,6 +245,7 @@ function requireMgw () {
234
245
  const ok = results.filter((r) => r.status === "ok").length;
235
246
  log(`sync complete: ${ok} up-to-date, ${archived} archived`);
236
247
  }
248
+ syncTimer.finish("ok");
237
249
  });
238
250
  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
251
  const opts = this.optsWithGlobals();
@@ -248,7 +260,7 @@ function requireMgw () {
248
260
  if (opts.milestone) ghFilters.milestone = opts.milestone;
249
261
  let issues;
250
262
  try {
251
- issues = listIssues(ghFilters);
263
+ issues = await listIssues(ghFilters);
252
264
  } catch (err) {
253
265
  error("Failed to list issues: " + err.message);
254
266
  process.exitCode = 1;
@@ -343,6 +355,83 @@ function requireMgw () {
343
355
  log("Linked: " + refA + " <-> " + refB);
344
356
  }
345
357
  });
358
+ 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() {
359
+ const opts = this.optsWithGlobals();
360
+ const { readLogs, aggregateMetrics } = index.requireLogger();
361
+ const logOpts = {
362
+ since: opts.since,
363
+ issue: opts.issue ? parseInt(opts.issue, 10) : void 0,
364
+ command: opts.command,
365
+ limit: opts.metrics ? void 0 : parseInt(opts.limit, 10) || 50
366
+ };
367
+ const entries = readLogs(logOpts);
368
+ if (opts.metrics) {
369
+ const metrics = aggregateMetrics(entries);
370
+ if (opts.json) {
371
+ log(formatJson(metrics));
372
+ } else {
373
+ log(`Total invocations: ${metrics.total}`);
374
+ log(`Avg duration: ${metrics.avgDuration}ms`);
375
+ log(`Failure rate: ${metrics.failureRate}%`);
376
+ log("");
377
+ log("By command:");
378
+ for (const [cmd, stats] of Object.entries(metrics.byCommand)) {
379
+ log(` ${cmd}: ${stats.count} calls, ${stats.errors} errors, avg ${stats.avgDuration}ms`);
380
+ }
381
+ }
382
+ return;
383
+ }
384
+ if (entries.length === 0) {
385
+ log("No log entries found.");
386
+ return;
387
+ }
388
+ if (opts.json) {
389
+ log(formatJson(entries));
390
+ return;
391
+ }
392
+ for (const e of entries) {
393
+ const ts = e.timestamp ? e.timestamp.slice(0, 19).replace("T", " ") : "?";
394
+ const issue = e.issue ? `#${e.issue}` : "";
395
+ const dur = typeof e.duration_ms === "number" ? `${e.duration_ms}ms` : "";
396
+ const status = e.status === "error" ? `ERR: ${e.error || "unknown"}` : e.status;
397
+ log(`${ts} ${(e.command || "").padEnd(12)} ${issue.padEnd(6)} ${dur.padEnd(8)} ${status}`);
398
+ }
399
+ });
400
+ 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() {
401
+ const opts = this.optsWithGlobals();
402
+ const { readLogs, aggregateMetrics } = index.requireLogger();
403
+ const { USE_COLOR, COLORS } = index.requireOutput();
404
+ const logOpts = {
405
+ since: opts.since,
406
+ issue: opts.issue ? parseInt(opts.issue, 10) : void 0,
407
+ command: opts.command
408
+ };
409
+ const entries = readLogs(logOpts);
410
+ const metrics = aggregateMetrics(entries);
411
+ if (opts.json) {
412
+ log(formatJson(metrics));
413
+ return;
414
+ }
415
+ if (metrics.total === 0) {
416
+ log("No log entries found for the given period.");
417
+ return;
418
+ }
419
+ const dim = USE_COLOR ? COLORS.dim : "";
420
+ const bold = USE_COLOR ? COLORS.bold : "";
421
+ const reset = USE_COLOR ? COLORS.reset : "";
422
+ log(`${bold}Execution Metrics${reset} ${dim}(${opts.since})${reset}`);
423
+ log("");
424
+ log(` Total invocations: ${metrics.total}`);
425
+ log(` Avg duration: ${metrics.avgDuration}ms`);
426
+ log(` Failure rate: ${metrics.failureRate}%`);
427
+ log("");
428
+ log(`${bold}By Command${reset}`);
429
+ log(`${" Command".padEnd(16)} ${"Calls".padEnd(8)} ${"Errors".padEnd(8)} ${"Avg ms".padEnd(10)}`);
430
+ log(` ${dim}${"\u2500".repeat(38)}${reset}`);
431
+ for (const [cmd, stats] of Object.entries(metrics.byCommand)) {
432
+ log(` ${cmd.padEnd(14)} ${String(stats.count).padEnd(8)} ${String(stats.errors).padEnd(8)} ${String(stats.avgDuration).padEnd(10)}`);
433
+ }
434
+ });
346
435
  program.command("help").description("Show command reference").action(function() {
347
436
  const helpMdPath = path.join(getCommandsDir(), "help.md");
348
437
  let helpText;