edgegate-mcp 0.1.2 → 0.2.1

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 CHANGED
@@ -4,7 +4,7 @@ MCP server for [EdgeGate](https://edgegate.frozo.ai) — set up edge-AI regressi
4
4
 
5
5
  ## What does it do?
6
6
 
7
- EdgeGate runs AI model regression tests on real Snapdragon hardware via Qualcomm AI Hub, then produces signed evidence bundles you can attach to CI gates. This npm package exposes EdgeGate's REST API as 7 MCP tools, plus 4 bundled skills, so you can drive the whole flow from a prompt:
7
+ EdgeGate runs AI model regression tests on real Snapdragon hardware via Qualcomm AI Hub, then produces signed evidence bundles you can attach to CI gates. This npm package exposes EdgeGate's REST API as 9 MCP tools, plus 4 bundled skills, so you can drive the whole flow from a prompt:
8
8
 
9
9
  ```
10
10
  > Use the edgegate MCP to set up a CI gate for my MobileNet ONNX model.
@@ -67,6 +67,8 @@ See [docs/tools.md](./docs/tools.md) for the full tool reference. Quick list:
67
67
  | `edgegate_get_report` | List recent runs |
68
68
  | `edgegate_get_audit_report` | Fetch the signed audit PDF |
69
69
  | `edgegate_setup_github_action` | Generate the GitHub Actions workflow + secret commands |
70
+ | `edgegate_compare_runs` | Diff two runs — gate flips, metric deltas, per-device breakdown, REGRESSION / IMPROVEMENT / NEUTRAL verdict |
71
+ | `edgegate_export_run_report` | Save a complete run report as a markdown file to disk (returns the file path + preview) |
70
72
 
71
73
  ## Skills
72
74
 
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { APIKeyCreateResponse, Pipeline, RunBundle, RunDetail, RunSummary, Workspace, WorkflowTemplate } from "./types.js";
1
+ import type { APIKeyCreateResponse, Pipeline, RunBundle, RunComparison, RunDetail, RunSummary, Workspace, WorkflowTemplate } from "./types.js";
2
2
  export interface EdgeGateClientOptions {
3
3
  apiUrl: string;
4
4
  apiKey: string;
@@ -60,6 +60,8 @@ export declare class EdgeGateClient {
60
60
  }): Promise<RunSummary>;
61
61
  getRun(workspaceId: string, runId: string): Promise<RunDetail>;
62
62
  listRuns(workspaceId: string, limit?: number): Promise<RunSummary[]>;
63
+ listRunsByPipeline(workspaceId: string, pipelineId: string, limit?: number): Promise<RunSummary[]>;
64
+ getRunDiff(workspaceId: string, runId: string): Promise<RunComparison>;
63
65
  getRunBundle(workspaceId: string, runId: string): Promise<RunBundle>;
64
66
  getWorkflowTemplate(workspaceId: string): Promise<WorkflowTemplate>;
65
67
  private request;
package/dist/client.js CHANGED
@@ -48,6 +48,12 @@ export class EdgeGateClient {
48
48
  async listRuns(workspaceId, limit = 20) {
49
49
  return this.request("GET", `/v1/workspaces/${workspaceId}/runs?limit=${limit}`);
50
50
  }
51
+ async listRunsByPipeline(workspaceId, pipelineId, limit = 20) {
52
+ return this.request("GET", `/v1/workspaces/${workspaceId}/runs?pipeline_id=${pipelineId}&limit=${limit}`);
53
+ }
54
+ async getRunDiff(workspaceId, runId) {
55
+ return this.request("GET", `/v1/workspaces/${workspaceId}/runs/${runId}/diff`);
56
+ }
51
57
  async getRunBundle(workspaceId, runId) {
52
58
  return this.request("GET", `/v1/workspaces/${workspaceId}/runs/${runId}/bundle`);
53
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -11,6 +11,8 @@ import { checkStatusHandler, checkStatusInputSchema } from "./tools/check_status
11
11
  import { getReportHandler, getReportInputSchema } from "./tools/get_report.js";
12
12
  import { getAuditReportHandler, getAuditReportInputSchema } from "./tools/get_audit_report.js";
13
13
  import { setupGithubActionHandler, setupGithubActionInputSchema, } from "./tools/setup_github_action.js";
14
+ import { compareRunsHandler, compareRunsInputSchema, } from "./tools/compare_runs.js";
15
+ import { exportRunReportHandler, exportRunReportInputSchema, } from "./tools/export_run_report.js";
14
16
  const TOOLS = [
15
17
  {
16
18
  name: "edgegate_setup_workspace",
@@ -60,6 +62,23 @@ const TOOLS = [
60
62
  schema: setupGithubActionInputSchema,
61
63
  handler: setupGithubActionHandler,
62
64
  },
65
+ {
66
+ name: "edgegate_compare_runs",
67
+ description: "Diff two EdgeGate runs in the same pipeline — metrics delta, gate flips (✓→✗ regressions " +
68
+ "and ✗→✓ recoveries), per-device breakdown, and an overall verdict (REGRESSION / IMPROVEMENT / " +
69
+ "NEUTRAL / NO BASELINE). When baseline_run_id is omitted, auto-selects the most recent " +
70
+ "PASSED run from the same pipeline as the baseline.",
71
+ schema: compareRunsInputSchema,
72
+ handler: compareRunsHandler,
73
+ },
74
+ {
75
+ name: "edgegate_export_run_report",
76
+ description: "Download a human-readable markdown report for an EdgeGate run and save it to disk. " +
77
+ "Returns the absolute file path plus a preview of the first 30 lines. " +
78
+ "Optionally includes a run-vs-baseline diff section (include_diff=true).",
79
+ schema: exportRunReportInputSchema,
80
+ handler: exportRunReportHandler,
81
+ },
63
82
  ];
64
83
  function getClient() {
65
84
  const apiUrl = process.env.EDGEGATE_API_URL ?? "https://edgegateapi.frozo.ai";
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * edgegate_compare_runs — run-over-run diff with smart auto-baseline selection.
3
+ *
4
+ * When baseline_run_id is omitted:
5
+ * 1. Fetch candidate run's pipeline_id
6
+ * 2. List last 20 runs in that pipeline
7
+ * 3. Pick the most recent PASSED run with a bundle (excluding candidate itself)
8
+ * 4. Fallback: most recent completed run (any status) excluding candidate
9
+ * 5. If nothing found: "NO BASELINE" response
10
+ *
11
+ * The backend already exposes GET /v1/workspaces/{id}/runs/{run_id}/diff which
12
+ * returns the pre-computed, signed diff embedded in the evidence bundle (commit
13
+ * 41167a6). We call that endpoint for the candidate run — it internally uses
14
+ * the baseline the Celery task stored at completion time. When the user
15
+ * explicitly provides a baseline_run_id that differs from what the backend
16
+ * stored, we fall back to client-side diff from both runs' detail endpoints.
17
+ */
18
+ import { z } from "zod";
19
+ import { EdgeGateClient } from "../client.js";
20
+ import type { ToolResult } from "./setup_workspace.js";
21
+ export declare const compareRunsInputSchema: z.ZodObject<{
22
+ workspace_id: z.ZodString;
23
+ run_id: z.ZodString;
24
+ baseline_run_id: z.ZodOptional<z.ZodString>;
25
+ }, "strip", z.ZodTypeAny, {
26
+ workspace_id: string;
27
+ run_id: string;
28
+ baseline_run_id?: string | undefined;
29
+ }, {
30
+ workspace_id: string;
31
+ run_id: string;
32
+ baseline_run_id?: string | undefined;
33
+ }>;
34
+ export type CompareRunsInput = z.infer<typeof compareRunsInputSchema>;
35
+ export declare function compareRunsHandler(client: EdgeGateClient, input: CompareRunsInput): Promise<ToolResult>;
@@ -0,0 +1,409 @@
1
+ /**
2
+ * edgegate_compare_runs — run-over-run diff with smart auto-baseline selection.
3
+ *
4
+ * When baseline_run_id is omitted:
5
+ * 1. Fetch candidate run's pipeline_id
6
+ * 2. List last 20 runs in that pipeline
7
+ * 3. Pick the most recent PASSED run with a bundle (excluding candidate itself)
8
+ * 4. Fallback: most recent completed run (any status) excluding candidate
9
+ * 5. If nothing found: "NO BASELINE" response
10
+ *
11
+ * The backend already exposes GET /v1/workspaces/{id}/runs/{run_id}/diff which
12
+ * returns the pre-computed, signed diff embedded in the evidence bundle (commit
13
+ * 41167a6). We call that endpoint for the candidate run — it internally uses
14
+ * the baseline the Celery task stored at completion time. When the user
15
+ * explicitly provides a baseline_run_id that differs from what the backend
16
+ * stored, we fall back to client-side diff from both runs' detail endpoints.
17
+ */
18
+ import { z } from "zod";
19
+ import { EdgeGateError } from "../client.js";
20
+ export const compareRunsInputSchema = z.object({
21
+ workspace_id: z.string().uuid(),
22
+ run_id: z.string().uuid().describe("Candidate run to evaluate"),
23
+ baseline_run_id: z
24
+ .string()
25
+ .uuid()
26
+ .optional()
27
+ .describe("Baseline to compare against. When omitted, auto-selects the most recent " +
28
+ "PASSED run from the same pipeline (excluding the candidate itself), " +
29
+ "or the most recent completed run as a fallback."),
30
+ });
31
+ // Metrics where lower is better (high delta% is bad)
32
+ const LOWER_IS_BETTER = new Set(["inference_time_ms", "peak_memory_mb", "latency_ms"]);
33
+ // Threshold for "significant regression" in lower-is-better metrics
34
+ const REGRESSION_THRESHOLD_PCT = 25;
35
+ export async function compareRunsHandler(client, input) {
36
+ try {
37
+ const { workspace_id, run_id, baseline_run_id } = input;
38
+ // --- Fetch candidate run detail (need pipeline_id for auto-baseline) ---
39
+ let candidateRun;
40
+ try {
41
+ candidateRun = await client.getRun(workspace_id, run_id);
42
+ }
43
+ catch (err) {
44
+ if (err instanceof EdgeGateError) {
45
+ return {
46
+ isError: true,
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: `Could not fetch candidate run ${run_id}: ${err.detail}`,
51
+ },
52
+ ],
53
+ };
54
+ }
55
+ throw err;
56
+ }
57
+ // --- Try the backend /diff endpoint first (Scenario A fast path) ---
58
+ // The backend stores the diff from the previous pipeline run at completion.
59
+ // If the caller did NOT supply a baseline_run_id (or it matches what the
60
+ // backend would pick), use the pre-computed signed diff directly.
61
+ if (!baseline_run_id) {
62
+ try {
63
+ const comparison = await client.getRunDiff(workspace_id, run_id);
64
+ // Backend returned a diff — render it
65
+ return { content: [{ type: "text", text: renderComparison(comparison, candidateRun) }] };
66
+ }
67
+ catch (diffErr) {
68
+ if (diffErr instanceof EdgeGateError && diffErr.status === 404) {
69
+ // No server-side diff yet: either first run or still in flight.
70
+ // Attempt client-side auto-baseline selection.
71
+ }
72
+ else {
73
+ // Unexpected error — propagate
74
+ if (diffErr instanceof EdgeGateError) {
75
+ return {
76
+ isError: true,
77
+ content: [
78
+ {
79
+ type: "text",
80
+ text: `EdgeGate returned ${diffErr.status} fetching diff: ${diffErr.detail}`,
81
+ },
82
+ ],
83
+ };
84
+ }
85
+ throw diffErr;
86
+ }
87
+ }
88
+ }
89
+ // --- Auto-baseline or explicit baseline: client-side path ---
90
+ let resolvedBaselineId = baseline_run_id ?? null;
91
+ if (!resolvedBaselineId) {
92
+ // Auto-select: list recent runs in the same pipeline
93
+ resolvedBaselineId = await pickAutoBaseline(client, workspace_id, candidateRun);
94
+ if (!resolvedBaselineId) {
95
+ return {
96
+ content: [
97
+ {
98
+ type: "text",
99
+ text: formatNoBaseline(candidateRun),
100
+ },
101
+ ],
102
+ };
103
+ }
104
+ }
105
+ // Fetch baseline run detail
106
+ let baselineRun;
107
+ try {
108
+ baselineRun = await client.getRun(workspace_id, resolvedBaselineId);
109
+ }
110
+ catch (err) {
111
+ if (err instanceof EdgeGateError) {
112
+ return {
113
+ isError: true,
114
+ content: [
115
+ {
116
+ type: "text",
117
+ text: `Could not fetch baseline run ${resolvedBaselineId}: ${err.detail}`,
118
+ },
119
+ ],
120
+ };
121
+ }
122
+ throw err;
123
+ }
124
+ // Build client-side diff
125
+ const comparison = buildClientSideDiff(candidateRun, baselineRun);
126
+ return { content: [{ type: "text", text: renderComparison(comparison, candidateRun) }] };
127
+ }
128
+ catch (err) {
129
+ if (err instanceof EdgeGateError) {
130
+ return {
131
+ isError: true,
132
+ content: [{ type: "text", text: `EdgeGate returned ${err.status}: ${err.detail}` }],
133
+ };
134
+ }
135
+ throw err;
136
+ }
137
+ }
138
+ // ─── Auto-baseline selection ───────────────────────────────────────────────
139
+ async function pickAutoBaseline(client, workspaceId, candidateRun) {
140
+ const pipelineId = candidateRun.pipeline_id;
141
+ let runs;
142
+ try {
143
+ runs = await client.listRunsByPipeline(workspaceId, pipelineId, 20);
144
+ }
145
+ catch {
146
+ // Fall back to listing all runs if pipeline filter fails
147
+ try {
148
+ runs = await client.listRuns(workspaceId, 20);
149
+ }
150
+ catch {
151
+ return null;
152
+ }
153
+ }
154
+ // Filter to same pipeline, excluding candidate itself
155
+ const eligible = runs.filter((r) => r.id !== candidateRun.id && r.pipeline_id === pipelineId);
156
+ // Priority 1: most recent PASSED with a bundle
157
+ // (RunSummary doesn't have bundle_artifact_id, but passed status implies a bundle)
158
+ const passedRun = eligible.find((r) => r.status === "passed");
159
+ if (passedRun)
160
+ return passedRun.id;
161
+ // Priority 2: most recent completed run (any terminal status)
162
+ const completedRun = eligible.find((r) => ["passed", "failed", "error"].includes(r.status));
163
+ if (completedRun)
164
+ return completedRun.id;
165
+ return null;
166
+ }
167
+ // ─── Client-side diff construction ────────────────────────────────────────
168
+ function buildClientSideDiff(candidate, baseline) {
169
+ const candidateMetrics = candidate.normalized_metrics ?? {};
170
+ const baselineMetrics = baseline.normalized_metrics ?? {};
171
+ // Metric deltas
172
+ const allMetricKeys = new Set([
173
+ ...Object.keys(candidateMetrics),
174
+ ...Object.keys(baselineMetrics),
175
+ ]);
176
+ const metric_deltas = {};
177
+ for (const k of allMetricKeys) {
178
+ const cur = candidateMetrics[k] ?? null;
179
+ const prev = baselineMetrics[k] ?? null;
180
+ const delta = cur !== null && prev !== null ? cur - prev : null;
181
+ const delta_pct = delta !== null && prev !== null && prev !== 0 ? (delta / prev) * 100 : null;
182
+ metric_deltas[k] = { current: cur, previous: prev, delta, delta_pct };
183
+ }
184
+ // Gate flips
185
+ const candidateGates = candidate.gates_eval?.gates ?? [];
186
+ const baselineGates = baseline.gates_eval?.gates ?? [];
187
+ const prevByMetric = new Map(baselineGates.map((g) => [g.metric, g]));
188
+ const currByMetric = new Map(candidateGates.map((g) => [g.metric, g]));
189
+ const allGateMetrics = new Set([...prevByMetric.keys(), ...currByMetric.keys()]);
190
+ const gate_flips = [];
191
+ for (const m of [...allGateMetrics].sort()) {
192
+ const prev = prevByMetric.get(m) ?? null;
193
+ const curr = currByMetric.get(m) ?? null;
194
+ let transition;
195
+ if (!prev)
196
+ transition = "new";
197
+ else if (!curr)
198
+ transition = "removed";
199
+ else {
200
+ const p = prev.passed;
201
+ const c = curr.passed;
202
+ if (c && p)
203
+ transition = "unchanged";
204
+ else if (c && !p)
205
+ transition = "improved";
206
+ else if (!c && p)
207
+ transition = "regressed";
208
+ else
209
+ transition = "still_failing";
210
+ }
211
+ gate_flips.push({
212
+ metric: m,
213
+ transition,
214
+ previous: prev
215
+ ? {
216
+ passed: prev.passed,
217
+ threshold: prev.threshold,
218
+ operator: prev.operator,
219
+ actual_value: prev.actual_value,
220
+ }
221
+ : null,
222
+ current: curr
223
+ ? {
224
+ passed: curr.passed,
225
+ threshold: curr.threshold,
226
+ operator: curr.operator,
227
+ actual_value: curr.actual_value,
228
+ }
229
+ : null,
230
+ });
231
+ }
232
+ return {
233
+ current_run_id: candidate.id,
234
+ previous_run_id: baseline.id,
235
+ diff_sha256: null, // client-side, not signed
236
+ diff: {
237
+ current_run_id: candidate.id,
238
+ previous_run_id: baseline.id,
239
+ current_commit: {},
240
+ previous_commit: {},
241
+ current_completed_at: candidate.completed_at,
242
+ previous_completed_at: baseline.completed_at,
243
+ metric_deltas,
244
+ gate_flips,
245
+ per_device: null,
246
+ per_cell: null,
247
+ is_baseline: false,
248
+ },
249
+ created_at: new Date().toISOString(),
250
+ };
251
+ }
252
+ // ─── Rendering ─────────────────────────────────────────────────────────────
253
+ function renderComparison(comparison, candidateRun) {
254
+ const diff = comparison.diff;
255
+ const lines = [];
256
+ // Header
257
+ lines.push(`## Run Comparison`, ``, `**Pipeline:** ${candidateRun.pipeline_name} (${candidateRun.pipeline_id})`, `**Candidate:** \`${comparison.current_run_id}\` ` +
258
+ `(${diff.current_completed_at ?? "in flight"})`, `**Baseline:** \`${comparison.previous_run_id ?? "—"}\` ` +
259
+ `(${diff.previous_completed_at ?? "—"})`, ``);
260
+ if (diff.is_baseline) {
261
+ lines.push(`> **NO BASELINE** — this is the first completed run in this pipeline.`);
262
+ lines.push(``);
263
+ return lines.join("\n");
264
+ }
265
+ // Commit context (only if server-side diff has it)
266
+ const cc = diff.current_commit;
267
+ const pc = diff.previous_commit;
268
+ if (cc?.sha || pc?.sha) {
269
+ lines.push(`### Commit Context`);
270
+ if (cc?.sha)
271
+ lines.push(`**Candidate:** \`${cc.sha}\` — ${cc.message ?? ""}`);
272
+ if (pc?.sha)
273
+ lines.push(`**Baseline:** \`${pc.sha}\` — ${pc.message ?? ""}`);
274
+ lines.push(``);
275
+ }
276
+ // Metrics
277
+ const metricKeys = Object.keys(diff.metric_deltas).sort();
278
+ if (metricKeys.length > 0) {
279
+ lines.push(`### Metrics`);
280
+ lines.push(`| Metric | Baseline | Candidate | Delta | Direction |`);
281
+ lines.push(`|---|---|---|---|---|`);
282
+ for (const k of metricKeys) {
283
+ const m = diff.metric_deltas[k];
284
+ const pct = m.delta_pct !== null ? `${m.delta_pct > 0 ? "+" : ""}${m.delta_pct.toFixed(1)}%` : "—";
285
+ const arrow = m.delta === null ? "" : m.delta > 0 ? "↑" : m.delta < 0 ? "↓" : "→";
286
+ const direction = m.delta === null ? "—" : buildDirectionLabel(k, m.delta);
287
+ lines.push(`| ${k} | ${fmt(m.previous)} | ${fmt(m.current)} | ${fmtDelta(m.delta)} (${pct}) ${arrow} | ${direction} |`);
288
+ }
289
+ lines.push(``);
290
+ }
291
+ // Gate flips
292
+ if (diff.gate_flips.length > 0) {
293
+ lines.push(`### Gate Status`);
294
+ lines.push(`| Gate | Baseline | Candidate | Status |`);
295
+ lines.push(`|---|---|---|---|`);
296
+ for (const gf of diff.gate_flips) {
297
+ const baseIcon = gateIcon(gf.previous?.passed ?? null);
298
+ const candIcon = gateIcon(gf.current?.passed ?? null);
299
+ const statusLabel = flipLabel(gf.transition);
300
+ lines.push(`| ${gf.metric} | ${baseIcon} | ${candIcon} | ${statusLabel} |`);
301
+ }
302
+ lines.push(``);
303
+ }
304
+ // Per-device breakdown
305
+ if (diff.per_device && Object.keys(diff.per_device).length > 0) {
306
+ lines.push(`### Per-Device Breakdown`);
307
+ for (const [device, metrics] of Object.entries(diff.per_device)) {
308
+ lines.push(`**${device}**`);
309
+ for (const [k, m] of Object.entries(metrics)) {
310
+ const pct = m.delta_pct !== null ? `${m.delta_pct > 0 ? "+" : ""}${m.delta_pct.toFixed(1)}%` : "—";
311
+ lines.push(` - ${k}: ${fmt(m.previous)} → ${fmt(m.current)} (${pct})`);
312
+ }
313
+ }
314
+ lines.push(``);
315
+ }
316
+ // Verdict
317
+ const verdict = computeVerdict(diff.gate_flips, diff.metric_deltas);
318
+ lines.push(`### Verdict`);
319
+ lines.push(``);
320
+ lines.push(verdictBadge(verdict));
321
+ lines.push(``);
322
+ // Audit trail
323
+ lines.push(`### Audit Trail`);
324
+ if (comparison.diff_sha256) {
325
+ lines.push(`Diff SHA-256: \`${comparison.diff_sha256}\` (signed, embedded in evidence bundle)`);
326
+ }
327
+ else {
328
+ lines.push(`Diff computed client-side (no SHA-256 — backend diff not yet available for this run)`);
329
+ }
330
+ if (candidateRun.bundle_artifact_id) {
331
+ lines.push(`Candidate bundle artifact: \`${candidateRun.bundle_artifact_id}\``);
332
+ }
333
+ if (comparison.previous_run_id) {
334
+ lines.push(`Baseline run ID: \`${comparison.previous_run_id}\``);
335
+ }
336
+ return lines.join("\n");
337
+ }
338
+ function formatNoBaseline(candidateRun) {
339
+ return [
340
+ `## Run Comparison`,
341
+ ``,
342
+ `**Pipeline:** ${candidateRun.pipeline_name} (${candidateRun.pipeline_id})`,
343
+ `**Candidate:** \`${candidateRun.id}\``,
344
+ ``,
345
+ `> **NO BASELINE** — this is the first completed run in pipeline "${candidateRun.pipeline_name}", ` +
346
+ `or no prior completed runs were found. There is nothing to compare against yet.`,
347
+ ``,
348
+ `**Verdict: NO BASELINE**`,
349
+ ].join("\n");
350
+ }
351
+ // ─── Helpers ───────────────────────────────────────────────────────────────
352
+ function fmt(v) {
353
+ return v === null ? "—" : v.toFixed(2);
354
+ }
355
+ function fmtDelta(v) {
356
+ if (v === null)
357
+ return "—";
358
+ return `${v > 0 ? "+" : ""}${v.toFixed(2)}`;
359
+ }
360
+ function gateIcon(passed) {
361
+ if (passed === null)
362
+ return "—";
363
+ return passed ? "✓" : "✗";
364
+ }
365
+ function flipLabel(transition) {
366
+ switch (transition) {
367
+ case "regressed": return "**REGRESSION** ✓→✗";
368
+ case "improved": return "RECOVERY ✗→✓";
369
+ case "unchanged": return "passing";
370
+ case "still_failing": return "still failing";
371
+ case "new": return "new gate";
372
+ case "removed": return "removed";
373
+ default: return transition;
374
+ }
375
+ }
376
+ function buildDirectionLabel(metric, delta) {
377
+ if (delta === 0)
378
+ return "no change";
379
+ const lowerBetter = LOWER_IS_BETTER.has(metric);
380
+ if (lowerBetter) {
381
+ return delta > 0 ? "worse ↑" : "better ↓";
382
+ }
383
+ return delta > 0 ? "better ↑" : "worse ↓";
384
+ }
385
+ function computeVerdict(gateFlips, metricDeltas) {
386
+ const hasRegression = gateFlips.some((gf) => gf.transition === "regressed");
387
+ const hasRecovery = gateFlips.some((gf) => gf.transition === "improved");
388
+ // Also flag metric-only regression even if no gate flip
389
+ const significantMetricRegression = Object.entries(metricDeltas).some(([k, m]) => {
390
+ if (!LOWER_IS_BETTER.has(k))
391
+ return false;
392
+ return m.delta_pct !== null && m.delta_pct >= REGRESSION_THRESHOLD_PCT;
393
+ });
394
+ if (hasRegression || significantMetricRegression)
395
+ return "REGRESSION";
396
+ if (hasRecovery && !hasRegression)
397
+ return "IMPROVEMENT";
398
+ return "NEUTRAL";
399
+ }
400
+ function verdictBadge(verdict) {
401
+ switch (verdict) {
402
+ case "REGRESSION": return `**REGRESSION** — one or more gates regressed or a lower-is-better metric increased by ≥${REGRESSION_THRESHOLD_PCT}%.`;
403
+ case "IMPROVEMENT": return `**IMPROVEMENT** — previously-failing gates now pass; no regressions.`;
404
+ case "NEUTRAL": return `**NEUTRAL** — no gate flips and no significant metric regressions.`;
405
+ case "NO BASELINE": return `**NO BASELINE** — no prior run to compare against.`;
406
+ default: return `**${verdict}**`;
407
+ }
408
+ }
409
+ //# sourceMappingURL=compare_runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare_runs.js","sourceRoot":"","sources":["../../src/tools/compare_runs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * edgegate_export_run_report — render a human-readable markdown report for a
3
+ * completed (or in-flight) EdgeGate run and write it to disk.
4
+ *
5
+ * Steps:
6
+ * 1. Fetch run detail via getRun
7
+ * 2. If the run is completed, fetch the evidence bundle via getRunBundle
8
+ * 3. Optionally fetch the run diff via getRunDiff (when include_diff=true)
9
+ * 4. Render a comprehensive markdown report
10
+ * 5. Write the file to disk (creating parent directories as needed)
11
+ * 6. Return the absolute file path + first ~30 lines of the report
12
+ */
13
+ import { z } from "zod";
14
+ import { tmpdir } from "node:os";
15
+ import { EdgeGateClient } from "../client.js";
16
+ import type { ToolResult } from "./setup_workspace.js";
17
+ export declare const exportRunReportInputSchema: z.ZodObject<{
18
+ workspace_id: z.ZodString;
19
+ run_id: z.ZodString;
20
+ output_path: z.ZodOptional<z.ZodString>;
21
+ include_diff: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
22
+ }, "strip", z.ZodTypeAny, {
23
+ workspace_id: string;
24
+ run_id: string;
25
+ include_diff: boolean;
26
+ output_path?: string | undefined;
27
+ }, {
28
+ workspace_id: string;
29
+ run_id: string;
30
+ output_path?: string | undefined;
31
+ include_diff?: boolean | undefined;
32
+ }>;
33
+ export type ExportRunReportInput = z.infer<typeof exportRunReportInputSchema>;
34
+ export declare function exportRunReportHandler(client: EdgeGateClient, input: ExportRunReportInput): Promise<ToolResult>;
35
+ export { tmpdir as _tmpdir };
@@ -0,0 +1,327 @@
1
+ /**
2
+ * edgegate_export_run_report — render a human-readable markdown report for a
3
+ * completed (or in-flight) EdgeGate run and write it to disk.
4
+ *
5
+ * Steps:
6
+ * 1. Fetch run detail via getRun
7
+ * 2. If the run is completed, fetch the evidence bundle via getRunBundle
8
+ * 3. Optionally fetch the run diff via getRunDiff (when include_diff=true)
9
+ * 4. Render a comprehensive markdown report
10
+ * 5. Write the file to disk (creating parent directories as needed)
11
+ * 6. Return the absolute file path + first ~30 lines of the report
12
+ */
13
+ import { z } from "zod";
14
+ import { join } from "node:path";
15
+ import { homedir, tmpdir } from "node:os";
16
+ import { mkdir, stat, writeFile } from "node:fs/promises";
17
+ import { EdgeGateError } from "../client.js";
18
+ import { VERSION } from "../version.js";
19
+ export const exportRunReportInputSchema = z.object({
20
+ workspace_id: z.string().uuid(),
21
+ run_id: z.string().uuid(),
22
+ output_path: z
23
+ .string()
24
+ .optional()
25
+ .describe("Where to write the markdown file. Defaults to `./edgegate-run-{id-short}.md` in the " +
26
+ "current working directory. If a directory, the file is named `edgegate-run-{id-short}.md` " +
27
+ "inside it. Supports `~` and relative paths."),
28
+ include_diff: z
29
+ .boolean()
30
+ .optional()
31
+ .default(false)
32
+ .describe("When true, also fetches the run-vs-baseline diff and appends a diff section to the report."),
33
+ });
34
+ // Terminal statuses that should have a bundle available
35
+ const TERMINAL_STATUSES = new Set(["passed", "failed", "error"]);
36
+ export async function exportRunReportHandler(client, input) {
37
+ try {
38
+ const { workspace_id, run_id, output_path, include_diff } = input;
39
+ // --- 1. Fetch run detail ---
40
+ let run;
41
+ try {
42
+ run = await client.getRun(workspace_id, run_id);
43
+ }
44
+ catch (err) {
45
+ if (err instanceof EdgeGateError) {
46
+ return {
47
+ isError: true,
48
+ content: [
49
+ {
50
+ type: "text",
51
+ text: `Could not fetch run ${run_id}: ${err.detail}`,
52
+ },
53
+ ],
54
+ };
55
+ }
56
+ throw err;
57
+ }
58
+ // --- 2. Fetch evidence bundle (only for terminal runs) ---
59
+ let bundle = null;
60
+ if (TERMINAL_STATUSES.has(run.status)) {
61
+ try {
62
+ bundle = await client.getRunBundle(workspace_id, run_id);
63
+ }
64
+ catch (err) {
65
+ if (err instanceof EdgeGateError && (err.status === 404 || err.status === 409)) {
66
+ // Bundle not ready yet — proceed without it
67
+ bundle = null;
68
+ }
69
+ else {
70
+ throw err;
71
+ }
72
+ }
73
+ }
74
+ // --- 3. Optionally fetch diff ---
75
+ let comparison = null;
76
+ if (include_diff) {
77
+ try {
78
+ comparison = await client.getRunDiff(workspace_id, run_id);
79
+ }
80
+ catch (err) {
81
+ if (err instanceof EdgeGateError && err.status === 404) {
82
+ // No diff yet — silently omit the section
83
+ comparison = null;
84
+ }
85
+ else if (err instanceof EdgeGateError) {
86
+ // Non-fatal — skip the diff section but note it
87
+ comparison = null;
88
+ }
89
+ else {
90
+ throw err;
91
+ }
92
+ }
93
+ }
94
+ // --- 4. Render markdown ---
95
+ const markdown = renderReport(run, bundle, comparison, workspace_id);
96
+ // --- 5. Resolve output path ---
97
+ const idShort = run_id.slice(0, 8);
98
+ const defaultFilename = `edgegate-run-${idShort}.md`;
99
+ const resolvedPath = await resolveOutputPath(output_path, defaultFilename);
100
+ // Ensure parent directory exists
101
+ const parent = resolvedPath.slice(0, resolvedPath.lastIndexOf("/"));
102
+ if (parent) {
103
+ await mkdir(parent, { recursive: true });
104
+ }
105
+ // --- 6. Write the file ---
106
+ await writeFile(resolvedPath, markdown, "utf8");
107
+ // --- 7. Return result ---
108
+ const previewLines = markdown.split("\n").slice(0, 30).join("\n");
109
+ const header = `Wrote run report to ${resolvedPath}\n\n`;
110
+ return {
111
+ content: [{ type: "text", text: header + previewLines }],
112
+ };
113
+ }
114
+ catch (err) {
115
+ if (err instanceof EdgeGateError) {
116
+ return {
117
+ isError: true,
118
+ content: [{ type: "text", text: `EdgeGate returned ${err.status}: ${err.detail}` }],
119
+ };
120
+ }
121
+ throw err;
122
+ }
123
+ }
124
+ // ─── Path resolution ──────────────────────────────────────────────────────────
125
+ async function resolveOutputPath(outputPath, defaultFilename) {
126
+ if (!outputPath) {
127
+ // Default: CWD / edgegate-run-{id-short}.md
128
+ return join(process.cwd(), defaultFilename);
129
+ }
130
+ // Expand ~ to home dir
131
+ let expanded = outputPath;
132
+ if (expanded.startsWith("~/")) {
133
+ expanded = join(homedir(), expanded.slice(2));
134
+ }
135
+ else if (expanded === "~") {
136
+ expanded = homedir();
137
+ }
138
+ // Resolve relative to CWD
139
+ const resolved = expanded.startsWith("/") ? expanded : join(process.cwd(), expanded);
140
+ // Check if it's an existing directory
141
+ try {
142
+ const s = await stat(resolved);
143
+ if (s.isDirectory()) {
144
+ return join(resolved, defaultFilename);
145
+ }
146
+ }
147
+ catch {
148
+ // Doesn't exist yet — treat as file path
149
+ }
150
+ return resolved;
151
+ }
152
+ // ─── Rendering ────────────────────────────────────────────────────────────────
153
+ function statusBadge(status) {
154
+ const upper = status.toUpperCase();
155
+ switch (upper) {
156
+ case "PASSED": return "**PASSED**";
157
+ case "FAILED": return "**FAILED**";
158
+ case "RUNNING": return "_RUNNING_";
159
+ case "PENDING": return "_PENDING_";
160
+ case "ERROR": return "**ERROR**";
161
+ default: return `_${upper}_`;
162
+ }
163
+ }
164
+ function wallClock(run) {
165
+ if (!run.completed_at || !run.created_at)
166
+ return "(pending)";
167
+ const startMs = new Date(run.created_at).getTime();
168
+ const endMs = new Date(run.completed_at).getTime();
169
+ const totalS = Math.round((endMs - startMs) / 1000);
170
+ const m = Math.floor(totalS / 60);
171
+ const s = totalS % 60;
172
+ return m > 0 ? `${m}m ${s}s` : `${s}s`;
173
+ }
174
+ function renderReport(run, bundle, comparison, workspaceId) {
175
+ const lines = [];
176
+ // ── Header ──
177
+ lines.push(`# EdgeGate Run Report`);
178
+ lines.push(``);
179
+ lines.push(`**Run ID:** \`${run.id}\``);
180
+ lines.push(`**Pipeline:** ${run.pipeline_name} (\`${run.pipeline_id}\`)`);
181
+ lines.push(`**Status:** ${statusBadge(run.status)}`);
182
+ lines.push(`**Trigger:** ${run.trigger}`);
183
+ lines.push(`**Created:** ${run.created_at}`);
184
+ lines.push(`**Completed:** ${run.completed_at ?? "(in flight)"}`);
185
+ lines.push(`**Wall clock:** ${wallClock(run)}`);
186
+ lines.push(``);
187
+ // ── Model ──
188
+ if (run.model_artifact_id || run.hub_model_id || run.hub_job_id) {
189
+ lines.push(`## Model`);
190
+ if (run.model_artifact_id)
191
+ lines.push(`- Artifact ID: \`${run.model_artifact_id}\``);
192
+ if (run.model_filename)
193
+ lines.push(`- Filename: ${run.model_filename}`);
194
+ if (run.hub_model_id)
195
+ lines.push(`- AI Hub model: \`${run.hub_model_id}\``);
196
+ if (run.hub_job_id)
197
+ lines.push(`- AI Hub job: \`${run.hub_job_id}\``);
198
+ lines.push(``);
199
+ }
200
+ // ── In-flight guard ──
201
+ const isComplete = TERMINAL_STATUSES.has(run.status) && (bundle !== null || run.gates_eval !== null);
202
+ if (!isComplete) {
203
+ lines.push(`## Status`);
204
+ lines.push(``);
205
+ lines.push(`_Run not yet complete — check back._`);
206
+ lines.push(``);
207
+ if (run.error_code) {
208
+ lines.push(`**Error code:** ${run.error_code}`);
209
+ if (run.error_detail)
210
+ lines.push(`**Error detail:** ${run.error_detail}`);
211
+ lines.push(``);
212
+ }
213
+ appendFooter(lines);
214
+ if (comparison)
215
+ appendDiffSection(lines, comparison);
216
+ return lines.join("\n");
217
+ }
218
+ // ── Metrics ──
219
+ const metrics = bundle?.normalized_metrics ?? run.normalized_metrics;
220
+ if (metrics && Object.keys(metrics).length > 0) {
221
+ lines.push(`## Metrics`);
222
+ lines.push(`| Metric | Value |`);
223
+ lines.push(`|---|---|`);
224
+ for (const [k, v] of Object.entries(metrics)) {
225
+ lines.push(`| ${k} | ${v} |`);
226
+ }
227
+ lines.push(``);
228
+ }
229
+ // ── Gate Results ──
230
+ const gatesEval = bundle?.gates_eval ?? run.gates_eval;
231
+ if (gatesEval && gatesEval.gates.length > 0) {
232
+ lines.push(`## Gate Results`);
233
+ lines.push(`| Metric | Operator | Threshold | Actual | Status |`);
234
+ lines.push(`|---|---|---|---|---|`);
235
+ for (const gate of gatesEval.gates) {
236
+ lines.push(renderGateRow(gate));
237
+ }
238
+ lines.push(``);
239
+ lines.push(`**Overall verdict:** ${gatesEval.passed ? "**PASSED**" : "**FAILED**"}`);
240
+ lines.push(``);
241
+ }
242
+ // ── Error info ──
243
+ if (run.error_code) {
244
+ lines.push(`## Error`);
245
+ lines.push(`- Code: ${run.error_code}`);
246
+ if (run.error_detail)
247
+ lines.push(`- Detail: ${run.error_detail}`);
248
+ lines.push(``);
249
+ }
250
+ // ── Evidence Bundle ──
251
+ const bundleArtifactId = bundle?.bundle_artifact_id ?? run.bundle_artifact_id;
252
+ if (bundleArtifactId) {
253
+ lines.push(`## Evidence Bundle`);
254
+ lines.push(`- Bundle artifact ID: \`${bundleArtifactId}\``);
255
+ lines.push(`- Download via API: \`GET /v1/workspaces/${workspaceId}/bundles/${bundleArtifactId}/artifact-url\`` +
256
+ ` (returns short-lived signed URL)`);
257
+ lines.push(``);
258
+ }
259
+ // ── Diff section ──
260
+ if (comparison) {
261
+ appendDiffSection(lines, comparison);
262
+ }
263
+ appendFooter(lines);
264
+ return lines.join("\n");
265
+ }
266
+ function renderGateRow(gate) {
267
+ const statusIcon = gate.passed ? "✓ PASSED" : "✗ FAILED";
268
+ return `| ${gate.metric} | ${gate.operator} | ${gate.threshold} | ${gate.actual_value} | ${statusIcon} |`;
269
+ }
270
+ function appendDiffSection(lines, comparison) {
271
+ const diff = comparison.diff;
272
+ lines.push(`## Run-vs-Baseline Diff`);
273
+ lines.push(``);
274
+ lines.push(`**Candidate:** \`${comparison.current_run_id}\` ` +
275
+ `(${diff.current_completed_at ?? "in flight"})`);
276
+ lines.push(`**Baseline:** \`${comparison.previous_run_id ?? "—"}\` ` +
277
+ `(${diff.previous_completed_at ?? "—"})`);
278
+ lines.push(``);
279
+ if (diff.is_baseline) {
280
+ lines.push(`> **NO BASELINE** — this is the first completed run in this pipeline.`);
281
+ lines.push(``);
282
+ return;
283
+ }
284
+ // Metrics
285
+ const metricKeys = Object.keys(diff.metric_deltas).sort();
286
+ if (metricKeys.length > 0) {
287
+ lines.push(`### Metrics`);
288
+ lines.push(`| Metric | Baseline | Candidate | Delta |`);
289
+ lines.push(`|---|---|---|---|`);
290
+ for (const k of metricKeys) {
291
+ const m = diff.metric_deltas[k];
292
+ const pct = m.delta_pct !== null
293
+ ? `${m.delta_pct > 0 ? "+" : ""}${m.delta_pct.toFixed(1)}%`
294
+ : "—";
295
+ const delta = m.delta !== null ? `${m.delta > 0 ? "+" : ""}${m.delta.toFixed(2)} (${pct})` : "—";
296
+ lines.push(`| ${k} | ${m.previous ?? "—"} | ${m.current ?? "—"} | ${delta} |`);
297
+ }
298
+ lines.push(``);
299
+ }
300
+ // Gate flips
301
+ if (diff.gate_flips.length > 0) {
302
+ lines.push(`### Gate Status`);
303
+ lines.push(`| Gate | Baseline | Candidate | Transition |`);
304
+ lines.push(`|---|---|---|---|`);
305
+ for (const gf of diff.gate_flips) {
306
+ const baseIcon = gf.previous?.passed === true ? "✓" : gf.previous?.passed === false ? "✗" : "—";
307
+ const candIcon = gf.current?.passed === true ? "✓" : gf.current?.passed === false ? "✗" : "—";
308
+ const label = gf.transition === "regressed" ? "**REGRESSION** ✓→✗"
309
+ : gf.transition === "improved" ? "RECOVERY ✗→✓"
310
+ : gf.transition;
311
+ lines.push(`| ${gf.metric} | ${baseIcon} | ${candIcon} | ${label} |`);
312
+ }
313
+ lines.push(``);
314
+ }
315
+ // Audit
316
+ if (comparison.diff_sha256) {
317
+ lines.push(`**Diff SHA-256:** \`${comparison.diff_sha256}\` (signed, embedded in evidence bundle)`);
318
+ lines.push(``);
319
+ }
320
+ }
321
+ function appendFooter(lines) {
322
+ lines.push(`---`);
323
+ lines.push(`_Generated by edgegate-mcp@${VERSION} on ${new Date().toISOString()}_`);
324
+ }
325
+ // Export the tmpdir helper so tests can use the same default resolution logic
326
+ export { tmpdir as _tmpdir };
327
+ //# sourceMappingURL=export_run_report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export_run_report.js","sourceRoot":"","sources":["../../src/tools/export_run_report.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -89,3 +89,46 @@ export interface AuditReport {
89
89
  url?: string;
90
90
  generated_at?: string;
91
91
  }
92
+ export interface MetricDelta {
93
+ current: number | null;
94
+ previous: number | null;
95
+ delta: number | null;
96
+ delta_pct: number | null;
97
+ }
98
+ export interface GateFlip {
99
+ metric: string;
100
+ /** "unchanged" | "improved" | "regressed" | "still_failing" | "new" | "removed" */
101
+ transition: string;
102
+ previous: {
103
+ passed: boolean | null;
104
+ threshold: number | null;
105
+ operator: string | null;
106
+ actual_value: number | null;
107
+ } | null;
108
+ current: {
109
+ passed: boolean | null;
110
+ threshold: number | null;
111
+ operator: string | null;
112
+ actual_value: number | null;
113
+ } | null;
114
+ }
115
+ export interface RunDiffPayload {
116
+ current_run_id: UUID;
117
+ previous_run_id: UUID | null;
118
+ current_commit: Record<string, string | null>;
119
+ previous_commit: Record<string, string | null> | null;
120
+ current_completed_at: string | null;
121
+ previous_completed_at: string | null;
122
+ metric_deltas: Record<string, MetricDelta>;
123
+ gate_flips: GateFlip[];
124
+ per_device: Record<string, Record<string, MetricDelta>> | null;
125
+ per_cell: unknown[] | null;
126
+ is_baseline: boolean;
127
+ }
128
+ export interface RunComparison {
129
+ current_run_id: UUID;
130
+ previous_run_id: UUID | null;
131
+ diff_sha256: string | null;
132
+ diff: RunDiffPayload;
133
+ created_at: string;
134
+ }
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.2";
2
- export declare const USER_AGENT = "edgegate-mcp/0.1.2";
1
+ export declare const VERSION = "0.2.1";
2
+ export declare const USER_AGENT = "edgegate-mcp/0.2.1";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
- export const VERSION = "0.1.2";
1
+ export const VERSION = "0.2.1";
2
2
  export const USER_AGENT = `edgegate-mcp/${VERSION}`;
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edgegate-mcp",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "MCP server for EdgeGate — set up edge-AI regression gates from Claude Code, Cursor, or Claude Desktop.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,3 +12,11 @@ The user wants to know how a run is doing.
12
12
  3. Render the result. If the run is FAILED, lead with the violating gate and the actual value — don't bury it.
13
13
 
14
14
  For PASSED runs, briefly summarize the metrics so the user has the numbers handy for a PR comment.
15
+
16
+ ## "Is this run a regression?"
17
+
18
+ If the user asks whether a run is a regression, or wants to see how it compares to the previous one, call `edgegate_compare_runs` with the `run_id` (and optionally a `baseline_run_id`). The tool auto-selects the baseline from the same pipeline when no explicit baseline is given. Read the **Verdict** section of the output — REGRESSION means at least one gate flipped ✓→✗ or a lower-is-better metric increased by ≥ 25%.
19
+
20
+ ## "Save" or "export" the report
21
+
22
+ If the user asks to save, export, or download the run report as a file, call `edgegate_export_run_report` with the `workspace_id`, `run_id`, and optionally an `output_path`. Pass `include_diff: true` if they also want the baseline comparison included in the file. The tool writes a complete markdown file to disk and returns the absolute path.