@rigour-labs/mcp 4.3.3 → 4.3.5

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/dist/index.js CHANGED
@@ -102,7 +102,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
102
102
  break;
103
103
  case "rigour_run_supervised": {
104
104
  const { command, maxRetries = 3, dryRun = false } = args;
105
- result = await handleRunSupervised(runner, cwd, command, maxRetries, dryRun, requestId);
105
+ result = await handleRunSupervised(runner, cwd, command, maxRetries, dryRun, requestId, config);
106
106
  break;
107
107
  }
108
108
  // Multi-agent governance
@@ -1,4 +1,5 @@
1
1
  import { GateRunner } from "@rigour-labs/core";
2
+ import type { Config } from "@rigour-labs/core";
2
3
  type ToolResult = {
3
4
  content: {
4
5
  type: string;
@@ -7,5 +8,5 @@ type ToolResult = {
7
8
  isError?: boolean;
8
9
  };
9
10
  export declare function handleRun(cwd: string, command: string, requestId: string): Promise<ToolResult>;
10
- export declare function handleRunSupervised(runner: GateRunner, cwd: string, command: string, maxRetries: number, dryRun: boolean, requestId: string): Promise<ToolResult>;
11
+ export declare function handleRunSupervised(runner: GateRunner, cwd: string, command: string, maxRetries: number, dryRun: boolean, requestId: string, config?: Config): Promise<ToolResult>;
11
12
  export {};
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import fs from "fs-extra";
9
9
  import path from "path";
10
+ import { FixPacketService } from "@rigour-labs/core";
10
11
  import { logStudioEvent } from '../utils/config.js';
11
12
  export async function handleRun(cwd, command, requestId) {
12
13
  // 1. Log Interceptable Event
@@ -40,7 +41,7 @@ export async function handleRun(cwd, command, requestId) {
40
41
  };
41
42
  }
42
43
  }
43
- export async function handleRunSupervised(runner, cwd, command, maxRetries, dryRun, requestId) {
44
+ export async function handleRunSupervised(runner, cwd, command, maxRetries, dryRun, requestId, config) {
44
45
  const { execa } = await import("execa");
45
46
  let iteration = 0;
46
47
  let lastReport = null;
@@ -67,39 +68,50 @@ export async function handleRunSupervised(runner, cwd, command, maxRetries, dryR
67
68
  console.error(`[RIGOUR] Iteration ${iteration} (DRY RUN - skipping command execution)`);
68
69
  }
69
70
  lastReport = await runner.run(cwd);
70
- iterations.push({ iteration, status: lastReport.status, failures: lastReport.failures.length });
71
+ const failedGateIds = [...new Set(lastReport.failures.map(f => f.id))];
72
+ iterations.push({
73
+ iteration,
74
+ status: lastReport.status,
75
+ failures: lastReport.failures.length,
76
+ failedGates: failedGateIds,
77
+ });
71
78
  await logStudioEvent(cwd, {
72
79
  type: "supervisor_iteration",
73
80
  requestId,
74
81
  iteration,
75
82
  status: lastReport.status,
76
83
  failures: lastReport.failures.length,
84
+ failedGates: failedGateIds,
77
85
  });
78
86
  if (lastReport.status === "PASS") {
87
+ const score = lastReport.stats.score !== undefined ? ` | Score: ${lastReport.stats.score}/100` : '';
79
88
  result = {
80
89
  content: [{
81
90
  type: "text",
82
- text: `✅ SUPERVISOR MODE: PASSED on iteration ${iteration}/${maxRetries}\n\nIterations:\n${iterations.map(i => ` ${i.iteration}. ${i.status} (${i.failures} failures)`).join("\n")}\n\nAll quality gates have been satisfied.`,
91
+ text: `✅ SUPERVISOR MODE: PASSED on iteration ${iteration}/${maxRetries}${score}\n\nIterations:\n${formatIterationHistory(iterations)}\n\nAll quality gates have been satisfied.`,
83
92
  }],
84
93
  };
85
94
  break;
86
95
  }
87
96
  if (iteration >= maxRetries) {
88
- const fixPacket = lastReport.failures.map((f, i) => {
89
- const sevTag = `[${(f.severity || 'medium').toUpperCase()}]`;
90
- const provTag = f.provenance ? `(${f.provenance})` : '';
91
- let text = `FIX TASK ${i + 1}: ${sevTag} ${provTag} [${f.id.toUpperCase()}] ${f.title}\n`;
92
- text += ` - CONTEXT: ${f.details}\n`;
93
- if (f.files && f.files.length > 0)
94
- text += ` - TARGET FILES: ${f.files.join(", ")}\n`;
95
- if (f.hint)
96
- text += ` - REFACTORING GUIDANCE: ${f.hint}\n`;
97
- return text;
98
- }).join("\n---\n");
97
+ // Use FixPacketService for structured output instead of ad-hoc formatting
98
+ let fixPacketText;
99
+ if (config) {
100
+ const fixPacketService = new FixPacketService();
101
+ const fixPacket = fixPacketService.generate(lastReport, config);
102
+ fixPacketText = formatFixPacketForSupervisor(fixPacket);
103
+ }
104
+ else {
105
+ // Fallback if config not available
106
+ fixPacketText = lastReport.failures.map((f, i) => {
107
+ const sevTag = `[${(f.severity || 'medium').toUpperCase()}]`;
108
+ return `${i + 1}. ${sevTag} [${f.id}] ${f.title}: ${f.details}${f.files?.length ? ` (${f.files.join(', ')})` : ''}`;
109
+ }).join('\n');
110
+ }
99
111
  result = {
100
112
  content: [{
101
113
  type: "text",
102
- text: `❌ SUPERVISOR MODE: FAILED after ${iteration} iterations\n\nIterations:\n${iterations.map(i => ` ${i.iteration}. ${i.status} (${i.failures} failures)`).join("\n")}\n\nFINAL FIX PACKET:\n${fixPacket}`,
114
+ text: `❌ SUPERVISOR MODE: FAILED after ${iteration} iterations\n\nIterations:\n${formatIterationHistory(iterations)}\n\n${fixPacketText}`,
103
115
  }],
104
116
  isError: true,
105
117
  };
@@ -113,6 +125,44 @@ export async function handleRunSupervised(runner, cwd, command, maxRetries, dryR
113
125
  });
114
126
  return result;
115
127
  }
128
+ function formatIterationHistory(iterations) {
129
+ return iterations.map(i => {
130
+ const gates = i.failedGates.length > 0 ? ` [${i.failedGates.join(', ')}]` : '';
131
+ return ` ${i.iteration}. ${i.status} (${i.failures} failures)${gates}`;
132
+ }).join('\n');
133
+ }
134
+ function formatFixPacketForSupervisor(fixPacket) {
135
+ const lines = [];
136
+ lines.push(`FINAL FIX PACKET (${fixPacket.violations.length} violations across gates: ${fixPacket.failed_gates.join(', ')})`);
137
+ lines.push('');
138
+ fixPacket.violations.forEach((v, i) => {
139
+ const sevTag = `[${(v.severity || 'medium').toUpperCase()}]`;
140
+ lines.push(`${i + 1}. ${sevTag} [${v.id}] ${v.title}`);
141
+ lines.push(` PROBLEM: ${v.details}`);
142
+ if (v.locations?.length > 0) {
143
+ const locs = v.locations.map((l) => l.line ? `${l.file}:${l.line}` : l.file);
144
+ lines.push(` WHERE: ${locs.join(', ')}`);
145
+ }
146
+ else if (v.files?.length > 0) {
147
+ lines.push(` FILES: ${v.files.join(', ')}`);
148
+ }
149
+ if (v.instructions?.length > 0) {
150
+ lines.push(` FIX: ${v.instructions[0]}`);
151
+ }
152
+ });
153
+ if (fixPacket.verification?.commands?.length > 0) {
154
+ lines.push('');
155
+ lines.push('VERIFICATION COMMANDS (run after fixing):');
156
+ fixPacket.verification.commands.forEach((c) => {
157
+ lines.push(` $ ${c.cmd} — ${c.purpose}`);
158
+ });
159
+ }
160
+ if (fixPacket.constraints?.allowed_scope?.length > 0) {
161
+ lines.push('');
162
+ lines.push(`ALLOWED SCOPE: ${fixPacket.constraints.allowed_scope.join(', ')}`);
163
+ }
164
+ return lines.join('\n');
165
+ }
116
166
  // ─── Private Helpers ──────────────────────────────────────────────
117
167
  async function pollArbitration(cwd, rid, timeout) {
118
168
  const start = Date.now();
@@ -108,27 +108,92 @@ export async function handleGetFixPacket(runner, cwd, config) {
108
108
  const { FixPacketService } = await import("@rigour-labs/core");
109
109
  const fixPacketService = new FixPacketService();
110
110
  const fixPacket = fixPacketService.generate(report, config);
111
- const packet = fixPacket.violations.map((v, i) => {
112
- const sevTag = `[${(v.severity || 'medium').toUpperCase()}]`;
113
- const catTag = v.category ? `(${v.category})` : '';
114
- let text = `FIX TASK ${i + 1}: ${sevTag} ${catTag} [${v.id.toUpperCase()}] ${v.title}\n`;
115
- text += ` - CONTEXT: ${v.details}\n`;
116
- if (v.files?.length > 0)
117
- text += ` - TARGET FILES: ${v.files.join(", ")}\n`;
118
- if (v.hint)
119
- text += ` - REFACTORING GUIDANCE: ${v.hint}\n`;
120
- return text;
121
- }).join("\n---\n");
122
- let scoreHeader = formatScoreText(report.stats).trim();
123
- if (scoreHeader)
124
- scoreHeader += '\n';
125
111
  return {
126
- content: [{
127
- type: "text",
128
- text: `ENGINEERING REFINEMENT REQUIRED:\n${scoreHeader}\nThe project state violated ${report.failures.length} quality gates. You MUST address these failures before declaring the task complete (critical issues first):\n\n${packet}`,
129
- }],
112
+ content: [{ type: "text", text: formatFixPacketText(fixPacket, report) }],
130
113
  };
131
114
  }
115
+ /**
116
+ * Formats a FixPacketV2 into a structured, agent-readable text block.
117
+ * Every violation includes: who failed, which files, what rule, where (line numbers),
118
+ * and what commands must pass after fixing.
119
+ */
120
+ function formatFixPacketText(fixPacket, report) {
121
+ const lines = [];
122
+ // Header
123
+ let scoreHeader = formatScoreText(report.stats).trim();
124
+ lines.push('ENGINEERING REFINEMENT REQUIRED');
125
+ if (scoreHeader)
126
+ lines.push(scoreHeader);
127
+ lines.push(`Violations: ${report.failures.length} | Failed gates: ${fixPacket.failed_gates.join(', ')}`);
128
+ lines.push('');
129
+ // Violations
130
+ fixPacket.violations.forEach((v, i) => {
131
+ const sevTag = `[${(v.severity || 'medium').toUpperCase()}]`;
132
+ const catTag = v.category ? ` (${v.category})` : '';
133
+ lines.push(`━━━ FIX ${i + 1}/${fixPacket.violations.length}: ${sevTag}${catTag} ${v.title} ━━━`);
134
+ lines.push(`GATE: ${v.id}`);
135
+ lines.push(`PROBLEM: ${v.details}`);
136
+ // Locations with line numbers (precise targeting)
137
+ if (v.locations && v.locations.length > 0) {
138
+ const locStrs = v.locations.map((loc) => {
139
+ let s = loc.file;
140
+ if (loc.line)
141
+ s += `:${loc.line}`;
142
+ if (loc.endLine && loc.endLine !== loc.line)
143
+ s += `-${loc.endLine}`;
144
+ return s;
145
+ });
146
+ lines.push(`WHERE: ${locStrs.join(', ')}`);
147
+ }
148
+ else if (v.files && v.files.length > 0) {
149
+ lines.push(`FILES: ${v.files.join(', ')}`);
150
+ }
151
+ // Metrics (thresholds vs actuals)
152
+ if (v.metrics && Object.keys(v.metrics).length > 0) {
153
+ const metricStrs = Object.entries(v.metrics).map(([k, val]) => `${k}=${val}`);
154
+ lines.push(`METRICS: ${metricStrs.join(', ')}`);
155
+ }
156
+ // Instructions
157
+ if (v.instructions && v.instructions.length > 0) {
158
+ lines.push(`FIX:`);
159
+ v.instructions.forEach((inst, j) => {
160
+ lines.push(` ${j + 1}. ${inst}`);
161
+ });
162
+ }
163
+ else if (v.hint) {
164
+ lines.push(`HINT: ${v.hint}`);
165
+ }
166
+ lines.push('');
167
+ });
168
+ // Verification commands
169
+ if (fixPacket.verification?.commands?.length > 0) {
170
+ lines.push('━━━ VERIFICATION (run these after fixing) ━━━');
171
+ fixPacket.verification.commands.forEach((c) => {
172
+ lines.push(` $ ${c.cmd} — ${c.purpose}`);
173
+ });
174
+ lines.push('');
175
+ }
176
+ // Constraints
177
+ const c = fixPacket.constraints;
178
+ if (c) {
179
+ const constraintParts = [];
180
+ if (c.allowed_scope?.length > 0)
181
+ constraintParts.push(`ALLOWED SCOPE: ${c.allowed_scope.join(', ')}`);
182
+ if (c.do_not_touch?.length > 0)
183
+ constraintParts.push(`DO NOT TOUCH: ${c.do_not_touch.join(', ')}`);
184
+ if (c.max_files_changed)
185
+ constraintParts.push(`MAX FILES CHANGED: ${c.max_files_changed}`);
186
+ if (c.no_new_deps)
187
+ constraintParts.push('NO NEW DEPENDENCIES');
188
+ if (c.paradigm)
189
+ constraintParts.push(`PARADIGM: ${c.paradigm}`);
190
+ if (constraintParts.length > 0) {
191
+ lines.push('━━━ CONSTRAINTS ━━━');
192
+ constraintParts.forEach(p => lines.push(` ${p}`));
193
+ }
194
+ }
195
+ return lines.join('\n');
196
+ }
132
197
  export function handleListGates(config) {
133
198
  return {
134
199
  content: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/mcp",
3
- "version": "4.3.3",
3
+ "version": "4.3.5",
4
4
  "description": "MCP server for AI code governance — OWASP LLM Top 10 (10/10), real-time hooks, 25+ security patterns, hallucinated import detection, multi-agent governance. Works with Claude, Cursor, Cline, Windsurf, Gemini. Industry presets for HIPAA, SOC2, FedRAMP.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rigour.run",
@@ -48,7 +48,7 @@
48
48
  "execa": "^8.0.1",
49
49
  "fs-extra": "^11.2.0",
50
50
  "yaml": "^2.8.2",
51
- "@rigour-labs/core": "4.3.3"
51
+ "@rigour-labs/core": "4.3.5"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^25.0.3",