@rigour-labs/mcp 2.11.0 → 2.12.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/dist/index.js CHANGED
@@ -243,6 +243,28 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
243
243
  required: ["cwd"],
244
244
  },
245
245
  },
246
+ {
247
+ name: "rigour_run",
248
+ description: "Execute a command under Rigour supervision. This tool can be INTERCEPTED and ARBITRATED by the Governance Studio.",
249
+ inputSchema: {
250
+ type: "object",
251
+ properties: {
252
+ cwd: {
253
+ type: "string",
254
+ description: "Absolute path to the project root.",
255
+ },
256
+ command: {
257
+ type: "string",
258
+ description: "The command to run (e.g., 'npm test', 'pytest').",
259
+ },
260
+ silent: {
261
+ type: "boolean",
262
+ description: "If true, hides the command output from the agent.",
263
+ }
264
+ },
265
+ required: ["cwd", "command"],
266
+ },
267
+ }
246
268
  ],
247
269
  };
248
270
  });
@@ -560,6 +582,76 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
560
582
  };
561
583
  break;
562
584
  }
585
+ case "rigour_run": {
586
+ const { command } = args;
587
+ // 1. Log Interceptable Event
588
+ await logStudioEvent(cwd, {
589
+ type: "interception_requested",
590
+ requestId: requestId,
591
+ tool: "rigour_run",
592
+ command
593
+ });
594
+ // 2. Poll for Human Arbitration (Max 60s wait for this demo/test)
595
+ // In production, this would be a blocking call wait
596
+ console.error(`[RIGOUR] Waiting for human arbitration for command: ${command}`);
597
+ const pollArbitration = async (rid, timeout) => {
598
+ const start = Date.now();
599
+ const eventsPath = path.join(cwd, '.rigour/events.jsonl');
600
+ while (Date.now() - start < timeout) {
601
+ if (await fs.pathExists(eventsPath)) {
602
+ const content = await fs.readFile(eventsPath, 'utf-8');
603
+ const lines = content.split('\n').filter(l => l.trim());
604
+ for (const line of lines.reverse()) {
605
+ const event = JSON.parse(line);
606
+ if (event.tool === 'human_arbitration' && event.requestId === rid) {
607
+ return event.decision;
608
+ }
609
+ }
610
+ }
611
+ await new Promise(r => setTimeout(r, 1000));
612
+ }
613
+ return "approve"; // Default to auto-approve if no human response (for non-blocking feel)
614
+ };
615
+ const decision = await pollArbitration(requestId, 60000);
616
+ if (decision === 'reject') {
617
+ result = {
618
+ content: [
619
+ {
620
+ type: "text",
621
+ text: `❌ COMMAND REJECTED BY GOVERNOR: The execution of "${command}" was blocked by a human operator in the Governance Studio.`,
622
+ },
623
+ ],
624
+ isError: true
625
+ };
626
+ }
627
+ else {
628
+ // Execute
629
+ const { execa } = await import("execa");
630
+ try {
631
+ const { stdout, stderr } = await execa(command, { shell: true, cwd });
632
+ result = {
633
+ content: [
634
+ {
635
+ type: "text",
636
+ text: `✅ COMMAND EXECUTED (Approved by Governor):\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}`,
637
+ },
638
+ ],
639
+ };
640
+ }
641
+ catch (e) {
642
+ result = {
643
+ content: [
644
+ {
645
+ type: "text",
646
+ text: `❌ COMMAND FAILED:\n\n${e.message}`,
647
+ },
648
+ ],
649
+ isError: true
650
+ };
651
+ }
652
+ }
653
+ break;
654
+ }
563
655
  default:
564
656
  throw new Error(`Unknown tool: ${name}`);
565
657
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/mcp",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "type": "module",
5
5
  "mcpName": "io.github.rigour-labs/rigour",
6
6
  "description": "Quality gates for AI-generated code. Forces AI agents to meet strict engineering standards with PASS/FAIL enforcement.",
@@ -17,9 +17,10 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@modelcontextprotocol/sdk": "^1.25.2",
20
+ "execa": "^8.0.1",
20
21
  "fs-extra": "^11.2.0",
21
22
  "yaml": "^2.8.2",
22
- "@rigour-labs/core": "2.11.0"
23
+ "@rigour-labs/core": "2.12.0"
23
24
  },
24
25
  "devDependencies": {
25
26
  "@types/node": "^25.0.3"
package/src/index.ts CHANGED
@@ -270,6 +270,28 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
270
270
  required: ["cwd"],
271
271
  },
272
272
  },
273
+ {
274
+ name: "rigour_run",
275
+ description: "Execute a command under Rigour supervision. This tool can be INTERCEPTED and ARBITRATED by the Governance Studio.",
276
+ inputSchema: {
277
+ type: "object",
278
+ properties: {
279
+ cwd: {
280
+ type: "string",
281
+ description: "Absolute path to the project root.",
282
+ },
283
+ command: {
284
+ type: "string",
285
+ description: "The command to run (e.g., 'npm test', 'pytest').",
286
+ },
287
+ silent: {
288
+ type: "boolean",
289
+ description: "If true, hides the command output from the agent.",
290
+ }
291
+ },
292
+ required: ["cwd", "command"],
293
+ },
294
+ }
273
295
  ],
274
296
  };
275
297
  });
@@ -612,6 +634,80 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
612
634
  break;
613
635
  }
614
636
 
637
+ case "rigour_run": {
638
+ const { command } = args as any;
639
+
640
+ // 1. Log Interceptable Event
641
+ await logStudioEvent(cwd, {
642
+ type: "interception_requested",
643
+ requestId: requestId,
644
+ tool: "rigour_run",
645
+ command
646
+ });
647
+
648
+ // 2. Poll for Human Arbitration (Max 60s wait for this demo/test)
649
+ // In production, this would be a blocking call wait
650
+ console.error(`[RIGOUR] Waiting for human arbitration for command: ${command}`);
651
+
652
+ const pollArbitration = async (rid: string, timeout: number): Promise<string | null> => {
653
+ const start = Date.now();
654
+ const eventsPath = path.join(cwd, '.rigour/events.jsonl');
655
+ while (Date.now() - start < timeout) {
656
+ if (await fs.pathExists(eventsPath)) {
657
+ const content = await fs.readFile(eventsPath, 'utf-8');
658
+ const lines = content.split('\n').filter(l => l.trim());
659
+ for (const line of lines.reverse()) {
660
+ const event = JSON.parse(line);
661
+ if (event.tool === 'human_arbitration' && event.requestId === rid) {
662
+ return event.decision;
663
+ }
664
+ }
665
+ }
666
+ await new Promise(r => setTimeout(r, 1000));
667
+ }
668
+ return "approve"; // Default to auto-approve if no human response (for non-blocking feel)
669
+ };
670
+
671
+ const decision = await pollArbitration(requestId, 60000);
672
+
673
+ if (decision === 'reject') {
674
+ result = {
675
+ content: [
676
+ {
677
+ type: "text",
678
+ text: `❌ COMMAND REJECTED BY GOVERNOR: The execution of "${command}" was blocked by a human operator in the Governance Studio.`,
679
+ },
680
+ ],
681
+ isError: true
682
+ };
683
+ } else {
684
+ // Execute
685
+ const { execa } = await import("execa");
686
+ try {
687
+ const { stdout, stderr } = await execa(command, { shell: true, cwd });
688
+ result = {
689
+ content: [
690
+ {
691
+ type: "text",
692
+ text: `✅ COMMAND EXECUTED (Approved by Governor):\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}`,
693
+ },
694
+ ],
695
+ };
696
+ } catch (e: any) {
697
+ result = {
698
+ content: [
699
+ {
700
+ type: "text",
701
+ text: `❌ COMMAND FAILED:\n\n${e.message}`,
702
+ },
703
+ ],
704
+ isError: true
705
+ };
706
+ }
707
+ }
708
+ break;
709
+ }
710
+
615
711
  default:
616
712
  throw new Error(`Unknown tool: ${name}`);
617
713
  }