@rigour-labs/mcp 2.10.0 → 2.11.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
@@ -1,18 +1,14 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
8
- const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
- const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
10
- const fs_extra_1 = __importDefault(require("fs-extra"));
11
- const path_1 = __importDefault(require("path"));
12
- const yaml_1 = __importDefault(require("yaml"));
13
- const core_1 = require("@rigour-labs/core");
14
- const pattern_index_1 = require("@rigour-labs/core/pattern-index");
15
- const server = new index_js_1.Server({
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import fs from "fs-extra";
6
+ import path from "path";
7
+ import yaml from "yaml";
8
+ import { randomUUID } from "crypto";
9
+ import { GateRunner, ConfigSchema, } from "@rigour-labs/core";
10
+ import { PatternMatcher, loadPatternIndex, getDefaultIndexPath, StalenessDetector, SecurityDetector } from "@rigour-labs/core/pattern-index";
11
+ const server = new Server({
16
12
  name: "rigour-mcp",
17
13
  version: "1.0.0",
18
14
  }, {
@@ -21,31 +17,48 @@ const server = new index_js_1.Server({
21
17
  },
22
18
  });
23
19
  async function loadConfig(cwd) {
24
- const configPath = path_1.default.join(cwd, "rigour.yml");
25
- if (!(await fs_extra_1.default.pathExists(configPath))) {
20
+ const configPath = path.join(cwd, "rigour.yml");
21
+ if (!(await fs.pathExists(configPath))) {
26
22
  throw new Error("Rigour configuration (rigour.yml) not found. The agent must run `rigour init` first to establish engineering standards.");
27
23
  }
28
- const configContent = await fs_extra_1.default.readFile(configPath, "utf-8");
29
- return core_1.ConfigSchema.parse(yaml_1.default.parse(configContent));
24
+ const configContent = await fs.readFile(configPath, "utf-8");
25
+ return ConfigSchema.parse(yaml.parse(configContent));
30
26
  }
31
27
  async function getMemoryPath(cwd) {
32
- const rigourDir = path_1.default.join(cwd, ".rigour");
33
- await fs_extra_1.default.ensureDir(rigourDir);
34
- return path_1.default.join(rigourDir, "memory.json");
28
+ const rigourDir = path.join(cwd, ".rigour");
29
+ await fs.ensureDir(rigourDir);
30
+ return path.join(rigourDir, "memory.json");
35
31
  }
36
32
  async function loadMemory(cwd) {
37
33
  const memPath = await getMemoryPath(cwd);
38
- if (await fs_extra_1.default.pathExists(memPath)) {
39
- const content = await fs_extra_1.default.readFile(memPath, "utf-8");
34
+ if (await fs.pathExists(memPath)) {
35
+ const content = await fs.readFile(memPath, "utf-8");
40
36
  return JSON.parse(content);
41
37
  }
42
38
  return { memories: {} };
43
39
  }
44
40
  async function saveMemory(cwd, store) {
45
41
  const memPath = await getMemoryPath(cwd);
46
- await fs_extra_1.default.writeFile(memPath, JSON.stringify(store, null, 2));
42
+ await fs.writeFile(memPath, JSON.stringify(store, null, 2));
47
43
  }
48
- server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
44
+ // Helper to log events for Rigour Studio
45
+ async function logStudioEvent(cwd, event) {
46
+ try {
47
+ const rigourDir = path.join(cwd, ".rigour");
48
+ await fs.ensureDir(rigourDir);
49
+ const eventsPath = path.join(rigourDir, "events.jsonl");
50
+ const logEntry = JSON.stringify({
51
+ id: randomUUID(),
52
+ timestamp: new Date().toISOString(),
53
+ ...event
54
+ }) + "\n";
55
+ await fs.appendFile(eventsPath, logEntry);
56
+ }
57
+ catch {
58
+ // Silent fail - Studio logging is non-blocking and zero-telemetry
59
+ }
60
+ }
61
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
49
62
  return {
50
63
  tools: [
51
64
  {
@@ -233,16 +246,24 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
233
246
  ],
234
247
  };
235
248
  });
236
- server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
249
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
237
250
  const { name, arguments: args } = request.params;
238
251
  const cwd = args?.cwd || process.cwd();
252
+ const requestId = randomUUID();
239
253
  try {
254
+ await logStudioEvent(cwd, {
255
+ type: "tool_call",
256
+ requestId,
257
+ tool: name,
258
+ arguments: args
259
+ });
240
260
  const config = await loadConfig(cwd);
241
- const runner = new core_1.GateRunner(config);
261
+ const runner = new GateRunner(config);
262
+ let result;
242
263
  switch (name) {
243
264
  case "rigour_check": {
244
265
  const report = await runner.run(cwd);
245
- return {
266
+ result = {
246
267
  content: [
247
268
  {
248
269
  type: "text",
@@ -250,11 +271,14 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
250
271
  },
251
272
  ],
252
273
  };
274
+ // Add the report to the tool_response log for high-fidelity Studio visualization
275
+ result._rigour_report = report;
276
+ break;
253
277
  }
254
278
  case "rigour_explain": {
255
279
  const report = await runner.run(cwd);
256
280
  if (report.status === "PASS") {
257
- return {
281
+ result = {
258
282
  content: [
259
283
  {
260
284
  type: "text",
@@ -263,21 +287,24 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
263
287
  ],
264
288
  };
265
289
  }
266
- const bullets = report.failures.map((f, i) => {
267
- return `${i + 1}. [${f.id.toUpperCase()}] ${f.title}: ${f.details}${f.hint ? ` (Hint: ${f.hint})` : ''}`;
268
- }).join("\n");
269
- return {
270
- content: [
271
- {
272
- type: "text",
273
- text: `RIGOUR EXPLAIN:\n\n${bullets}`,
274
- },
275
- ],
276
- };
290
+ else {
291
+ const bullets = report.failures.map((f, i) => {
292
+ return `${i + 1}. [${f.id.toUpperCase()}] ${f.title}: ${f.details}${f.hint ? ` (Hint: ${f.hint})` : ''}`;
293
+ }).join("\n");
294
+ result = {
295
+ content: [
296
+ {
297
+ type: "text",
298
+ text: `RIGOUR EXPLAIN:\n\n${bullets}`,
299
+ },
300
+ ],
301
+ };
302
+ }
303
+ break;
277
304
  }
278
305
  case "rigour_status": {
279
306
  const report = await runner.run(cwd);
280
- return {
307
+ result = {
281
308
  content: [
282
309
  {
283
310
  type: "text",
@@ -290,11 +317,12 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
290
317
  },
291
318
  ],
292
319
  };
320
+ break;
293
321
  }
294
322
  case "rigour_get_fix_packet": {
295
323
  const report = await runner.run(cwd);
296
324
  if (report.status === "PASS") {
297
- return {
325
+ result = {
298
326
  content: [
299
327
  {
300
328
  type: "text",
@@ -303,28 +331,31 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
303
331
  ],
304
332
  };
305
333
  }
306
- const packet = report.failures.map((f, i) => {
307
- let text = `FIX TASK ${i + 1}: [${f.id.toUpperCase()}] ${f.title}\n`;
308
- text += ` - CONTEXT: ${f.details}\n`;
309
- if (f.files && f.files.length > 0) {
310
- text += ` - TARGET FILES: ${f.files.join(", ")}\n`;
311
- }
312
- if (f.hint) {
313
- text += ` - REFACTORING GUIDANCE: ${f.hint}\n`;
314
- }
315
- return text;
316
- }).join("\n---\n");
317
- return {
318
- content: [
319
- {
320
- type: "text",
321
- text: `ENGINEERING REFINEMENT REQUIRED:\n\nThe project state violated ${report.failures.length} quality gates. You MUST address these failures before declaring the task complete:\n\n${packet}`,
322
- },
323
- ],
324
- };
334
+ else {
335
+ const packet = report.failures.map((f, i) => {
336
+ let text = `FIX TASK ${i + 1}: [${f.id.toUpperCase()}] ${f.title}\n`;
337
+ text += ` - CONTEXT: ${f.details}\n`;
338
+ if (f.files && f.files.length > 0) {
339
+ text += ` - TARGET FILES: ${f.files.join(", ")}\n`;
340
+ }
341
+ if (f.hint) {
342
+ text += ` - REFACTORING GUIDANCE: ${f.hint}\n`;
343
+ }
344
+ return text;
345
+ }).join("\n---\n");
346
+ result = {
347
+ content: [
348
+ {
349
+ type: "text",
350
+ text: `ENGINEERING REFINEMENT REQUIRED:\n\nThe project state violated ${report.failures.length} quality gates. You MUST address these failures before declaring the task complete:\n\n${packet}`,
351
+ },
352
+ ],
353
+ };
354
+ }
355
+ break;
325
356
  }
326
357
  case "rigour_list_gates":
327
- return {
358
+ result = {
328
359
  content: [
329
360
  {
330
361
  type: "text",
@@ -337,8 +368,9 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
337
368
  },
338
369
  ],
339
370
  };
371
+ break;
340
372
  case "rigour_get_config":
341
- return {
373
+ result = {
342
374
  content: [
343
375
  {
344
376
  type: "text",
@@ -346,6 +378,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
346
378
  },
347
379
  ],
348
380
  };
381
+ break;
349
382
  case "rigour_remember": {
350
383
  const { key, value } = args;
351
384
  const store = await loadMemory(cwd);
@@ -354,7 +387,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
354
387
  timestamp: new Date().toISOString(),
355
388
  };
356
389
  await saveMemory(cwd, store);
357
- return {
390
+ result = {
358
391
  content: [
359
392
  {
360
393
  type: "text",
@@ -362,6 +395,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
362
395
  },
363
396
  ],
364
397
  };
398
+ break;
365
399
  }
366
400
  case "rigour_recall": {
367
401
  const { key } = args;
@@ -369,7 +403,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
369
403
  if (key) {
370
404
  const memory = store.memories[key];
371
405
  if (!memory) {
372
- return {
406
+ result = {
373
407
  content: [
374
408
  {
375
409
  type: "text",
@@ -378,44 +412,51 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
378
412
  ],
379
413
  };
380
414
  }
381
- return {
382
- content: [
383
- {
384
- type: "text",
385
- text: `RECALLED MEMORY [${key}]:\n${memory.value}\n\n(Stored: ${memory.timestamp})`,
386
- },
387
- ],
388
- };
415
+ else {
416
+ result = {
417
+ content: [
418
+ {
419
+ type: "text",
420
+ text: `RECALLED MEMORY [${key}]:\n${memory.value}\n\n(Stored: ${memory.timestamp})`,
421
+ },
422
+ ],
423
+ };
424
+ }
389
425
  }
390
- const keys = Object.keys(store.memories);
391
- if (keys.length === 0) {
392
- return {
393
- content: [
394
- {
395
- type: "text",
396
- text: "NO MEMORIES STORED. Use rigour_remember to persist important instructions.",
397
- },
398
- ],
399
- };
426
+ else {
427
+ const keys = Object.keys(store.memories);
428
+ if (keys.length === 0) {
429
+ result = {
430
+ content: [
431
+ {
432
+ type: "text",
433
+ text: "NO MEMORIES STORED. Use rigour_remember to persist important instructions.",
434
+ },
435
+ ],
436
+ };
437
+ }
438
+ else {
439
+ const allMemories = keys.map(k => {
440
+ const mem = store.memories[k];
441
+ return `## ${k}\n${mem.value}\n(Stored: ${mem.timestamp})`;
442
+ }).join("\n\n---\n\n");
443
+ result = {
444
+ content: [
445
+ {
446
+ type: "text",
447
+ text: `RECALLED ALL MEMORIES (${keys.length} items):\n\n${allMemories}\n\n---\nIMPORTANT: Follow these stored instructions throughout this session.`,
448
+ },
449
+ ],
450
+ };
451
+ }
400
452
  }
401
- const allMemories = keys.map(k => {
402
- const mem = store.memories[k];
403
- return `## ${k}\n${mem.value}\n(Stored: ${mem.timestamp})`;
404
- }).join("\n\n---\n\n");
405
- return {
406
- content: [
407
- {
408
- type: "text",
409
- text: `RECALLED ALL MEMORIES (${keys.length} items):\n\n${allMemories}\n\n---\nIMPORTANT: Follow these stored instructions throughout this session.`,
410
- },
411
- ],
412
- };
453
+ break;
413
454
  }
414
455
  case "rigour_forget": {
415
456
  const { key } = args;
416
457
  const store = await loadMemory(cwd);
417
458
  if (!store.memories[key]) {
418
- return {
459
+ result = {
419
460
  content: [
420
461
  {
421
462
  type: "text",
@@ -424,25 +465,28 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
424
465
  ],
425
466
  };
426
467
  }
427
- delete store.memories[key];
428
- await saveMemory(cwd, store);
429
- return {
430
- content: [
431
- {
432
- type: "text",
433
- text: `MEMORY DELETED: "${key}" has been removed.`,
434
- },
435
- ],
436
- };
468
+ else {
469
+ delete store.memories[key];
470
+ await saveMemory(cwd, store);
471
+ result = {
472
+ content: [
473
+ {
474
+ type: "text",
475
+ text: `MEMORY DELETED: "${key}" has been removed.`,
476
+ },
477
+ ],
478
+ };
479
+ }
480
+ break;
437
481
  }
438
482
  case "rigour_check_pattern": {
439
483
  const { name: patternName, type, intent } = args;
440
- const indexPath = (0, pattern_index_1.getDefaultIndexPath)(cwd);
441
- const index = await (0, pattern_index_1.loadPatternIndex)(indexPath);
484
+ const indexPath = getDefaultIndexPath(cwd);
485
+ const index = await loadPatternIndex(indexPath);
442
486
  let resultText = "";
443
487
  // 1. Check for Reinvention
444
488
  if (index) {
445
- const matcher = new pattern_index_1.PatternMatcher(index);
489
+ const matcher = new PatternMatcher(index);
446
490
  const matchResult = await matcher.match({ name: patternName, type, intent });
447
491
  if (matchResult.status === "FOUND_SIMILAR") {
448
492
  resultText += `🚨 PATTERN REINVENTION DETECTED\n`;
@@ -454,7 +498,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
454
498
  resultText += `⚠️ Pattern index not found. Run 'rigour index' to enable reinvention detection.\n\n`;
455
499
  }
456
500
  // 2. Check for Staleness/Best Practices
457
- const detector = new pattern_index_1.StalenessDetector(cwd);
501
+ const detector = new StalenessDetector(cwd);
458
502
  const staleness = await detector.checkStaleness(`${type || 'function'} ${patternName} {}`);
459
503
  if (staleness.status !== "FRESH") {
460
504
  resultText += `⚠️ STALENESS/ANTI-PATTERN WARNING\n`;
@@ -465,7 +509,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
465
509
  }
466
510
  // 3. Check Security for this library (if it's an import)
467
511
  if (intent && intent.includes('import')) {
468
- const security = new pattern_index_1.SecurityDetector(cwd);
512
+ const security = new SecurityDetector(cwd);
469
513
  const audit = await security.runAudit();
470
514
  const relatedVulns = audit.vulnerabilities.filter(v => patternName.toLowerCase().includes(v.packageName.toLowerCase()) ||
471
515
  intent.toLowerCase().includes(v.packageName.toLowerCase()));
@@ -493,7 +537,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
493
537
  }
494
538
  resultText += `\nRECOMMENDED ACTION: ${recommendation}`;
495
539
  }
496
- return {
540
+ result = {
497
541
  content: [
498
542
  {
499
543
  type: "text",
@@ -501,11 +545,12 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
501
545
  },
502
546
  ],
503
547
  };
548
+ break;
504
549
  }
505
550
  case "rigour_security_audit": {
506
- const security = new pattern_index_1.SecurityDetector(cwd);
551
+ const security = new SecurityDetector(cwd);
507
552
  const summary = await security.getSecuritySummary();
508
- return {
553
+ result = {
509
554
  content: [
510
555
  {
511
556
  type: "text",
@@ -513,13 +558,23 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
513
558
  },
514
559
  ],
515
560
  };
561
+ break;
516
562
  }
517
563
  default:
518
564
  throw new Error(`Unknown tool: ${name}`);
519
565
  }
566
+ await logStudioEvent(cwd, {
567
+ type: "tool_response",
568
+ requestId,
569
+ tool: name,
570
+ status: "success",
571
+ content: result.content,
572
+ _rigour_report: result._rigour_report
573
+ });
574
+ return result;
520
575
  }
521
576
  catch (error) {
522
- return {
577
+ const errorResponse = {
523
578
  content: [
524
579
  {
525
580
  type: "text",
@@ -528,10 +583,19 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
528
583
  ],
529
584
  isError: true,
530
585
  };
586
+ await logStudioEvent(cwd, {
587
+ type: "tool_response",
588
+ requestId,
589
+ tool: name,
590
+ status: "error",
591
+ error: error.message,
592
+ content: errorResponse.content
593
+ });
594
+ return errorResponse;
531
595
  }
532
596
  });
533
597
  async function main() {
534
- const transport = new stdio_js_1.StdioServerTransport();
598
+ const transport = new StdioServerTransport();
535
599
  await server.connect(transport);
536
600
  console.error("Rigour MCP server v1.0.0 running on stdio");
537
601
  }
@@ -1,8 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- (0, vitest_1.describe)('MCP Smoke Test', () => {
5
- (0, vitest_1.it)('should pass', async () => {
6
- (0, vitest_1.expect)(true).toBe(true);
1
+ import { describe, it, expect } from 'vitest';
2
+ describe('MCP Smoke Test', () => {
3
+ it('should pass', async () => {
4
+ expect(true).toBe(true);
7
5
  });
8
6
  });
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@rigour-labs/mcp",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
4
+ "type": "module",
4
5
  "mcpName": "io.github.rigour-labs/rigour",
5
6
  "description": "Quality gates for AI-generated code. Forces AI agents to meet strict engineering standards with PASS/FAIL enforcement.",
6
7
  "bin": {
@@ -18,7 +19,7 @@
18
19
  "@modelcontextprotocol/sdk": "^1.25.2",
19
20
  "fs-extra": "^11.2.0",
20
21
  "yaml": "^2.8.2",
21
- "@rigour-labs/core": "2.10.0"
22
+ "@rigour-labs/core": "2.11.0"
22
23
  },
23
24
  "devDependencies": {
24
25
  "@types/node": "^25.0.3"
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  import fs from "fs-extra";
9
9
  import path from "path";
10
10
  import yaml from "yaml";
11
+ import { randomUUID } from "crypto";
11
12
  import {
12
13
  GateRunner,
13
14
  ConfigSchema,
@@ -67,6 +68,23 @@ async function saveMemory(cwd: string, store: MemoryStore): Promise<void> {
67
68
  await fs.writeFile(memPath, JSON.stringify(store, null, 2));
68
69
  }
69
70
 
71
+ // Helper to log events for Rigour Studio
72
+ async function logStudioEvent(cwd: string, event: any) {
73
+ try {
74
+ const rigourDir = path.join(cwd, ".rigour");
75
+ await fs.ensureDir(rigourDir);
76
+ const eventsPath = path.join(rigourDir, "events.jsonl");
77
+ const logEntry = JSON.stringify({
78
+ id: randomUUID(),
79
+ timestamp: new Date().toISOString(),
80
+ ...event
81
+ }) + "\n";
82
+ await fs.appendFile(eventsPath, logEntry);
83
+ } catch {
84
+ // Silent fail - Studio logging is non-blocking and zero-telemetry
85
+ }
86
+ }
87
+
70
88
  server.setRequestHandler(ListToolsRequestSchema, async () => {
71
89
  return {
72
90
  tools: [
@@ -259,15 +277,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
259
277
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
260
278
  const { name, arguments: args } = request.params;
261
279
  const cwd = (args as any)?.cwd || process.cwd();
280
+ const requestId = randomUUID();
262
281
 
263
282
  try {
283
+ await logStudioEvent(cwd, {
284
+ type: "tool_call",
285
+ requestId,
286
+ tool: name,
287
+ arguments: args
288
+ });
289
+
264
290
  const config = await loadConfig(cwd);
265
291
  const runner = new GateRunner(config);
266
292
 
293
+ let result: any;
294
+
267
295
  switch (name) {
268
296
  case "rigour_check": {
269
297
  const report = await runner.run(cwd);
270
- return {
298
+ result = {
271
299
  content: [
272
300
  {
273
301
  type: "text",
@@ -275,12 +303,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
275
303
  },
276
304
  ],
277
305
  };
306
+
307
+ // Add the report to the tool_response log for high-fidelity Studio visualization
308
+ (result as any)._rigour_report = report;
309
+ break;
278
310
  }
279
311
 
280
312
  case "rigour_explain": {
281
313
  const report = await runner.run(cwd);
282
314
  if (report.status === "PASS") {
283
- return {
315
+ result = {
284
316
  content: [
285
317
  {
286
318
  type: "text",
@@ -288,25 +320,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
288
320
  },
289
321
  ],
290
322
  };
291
- }
292
-
293
- const bullets = report.failures.map((f, i) => {
294
- return `${i + 1}. [${f.id.toUpperCase()}] ${f.title}: ${f.details}${f.hint ? ` (Hint: ${f.hint})` : ''}`;
295
- }).join("\n");
323
+ } else {
324
+ const bullets = report.failures.map((f, i) => {
325
+ return `${i + 1}. [${f.id.toUpperCase()}] ${f.title}: ${f.details}${f.hint ? ` (Hint: ${f.hint})` : ''}`;
326
+ }).join("\n");
296
327
 
297
- return {
298
- content: [
299
- {
300
- type: "text",
301
- text: `RIGOUR EXPLAIN:\n\n${bullets}`,
302
- },
303
- ],
304
- };
328
+ result = {
329
+ content: [
330
+ {
331
+ type: "text",
332
+ text: `RIGOUR EXPLAIN:\n\n${bullets}`,
333
+ },
334
+ ],
335
+ };
336
+ }
337
+ break;
305
338
  }
306
339
 
307
340
  case "rigour_status": {
308
341
  const report = await runner.run(cwd);
309
- return {
342
+ result = {
310
343
  content: [
311
344
  {
312
345
  type: "text",
@@ -319,12 +352,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
319
352
  },
320
353
  ],
321
354
  };
355
+ break;
322
356
  }
323
357
 
324
358
  case "rigour_get_fix_packet": {
325
359
  const report = await runner.run(cwd);
326
360
  if (report.status === "PASS") {
327
- return {
361
+ result = {
328
362
  content: [
329
363
  {
330
364
  type: "text",
@@ -332,32 +366,33 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
332
366
  },
333
367
  ],
334
368
  };
335
- }
336
-
337
- const packet = report.failures.map((f, i) => {
338
- let text = `FIX TASK ${i + 1}: [${f.id.toUpperCase()}] ${f.title}\n`;
339
- text += ` - CONTEXT: ${f.details}\n`;
340
- if (f.files && f.files.length > 0) {
341
- text += ` - TARGET FILES: ${f.files.join(", ")}\n`;
342
- }
343
- if (f.hint) {
344
- text += ` - REFACTORING GUIDANCE: ${f.hint}\n`;
345
- }
346
- return text;
347
- }).join("\n---\n");
369
+ } else {
370
+ const packet = report.failures.map((f, i) => {
371
+ let text = `FIX TASK ${i + 1}: [${f.id.toUpperCase()}] ${f.title}\n`;
372
+ text += ` - CONTEXT: ${f.details}\n`;
373
+ if (f.files && f.files.length > 0) {
374
+ text += ` - TARGET FILES: ${f.files.join(", ")}\n`;
375
+ }
376
+ if (f.hint) {
377
+ text += ` - REFACTORING GUIDANCE: ${f.hint}\n`;
378
+ }
379
+ return text;
380
+ }).join("\n---\n");
348
381
 
349
- return {
350
- content: [
351
- {
352
- type: "text",
353
- text: `ENGINEERING REFINEMENT REQUIRED:\n\nThe project state violated ${report.failures.length} quality gates. You MUST address these failures before declaring the task complete:\n\n${packet}`,
354
- },
355
- ],
356
- };
382
+ result = {
383
+ content: [
384
+ {
385
+ type: "text",
386
+ text: `ENGINEERING REFINEMENT REQUIRED:\n\nThe project state violated ${report.failures.length} quality gates. You MUST address these failures before declaring the task complete:\n\n${packet}`,
387
+ },
388
+ ],
389
+ };
390
+ }
391
+ break;
357
392
  }
358
393
 
359
394
  case "rigour_list_gates":
360
- return {
395
+ result = {
361
396
  content: [
362
397
  {
363
398
  type: "text",
@@ -370,9 +405,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
370
405
  },
371
406
  ],
372
407
  };
408
+ break;
373
409
 
374
410
  case "rigour_get_config":
375
- return {
411
+ result = {
376
412
  content: [
377
413
  {
378
414
  type: "text",
@@ -380,6 +416,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
380
416
  },
381
417
  ],
382
418
  };
419
+ break;
383
420
 
384
421
  case "rigour_remember": {
385
422
  const { key, value } = args as any;
@@ -389,7 +426,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
389
426
  timestamp: new Date().toISOString(),
390
427
  };
391
428
  await saveMemory(cwd, store);
392
- return {
429
+ result = {
393
430
  content: [
394
431
  {
395
432
  type: "text",
@@ -397,6 +434,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
397
434
  },
398
435
  ],
399
436
  };
437
+ break;
400
438
  }
401
439
 
402
440
  case "rigour_recall": {
@@ -406,7 +444,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
406
444
  if (key) {
407
445
  const memory = store.memories[key];
408
446
  if (!memory) {
409
- return {
447
+ result = {
410
448
  content: [
411
449
  {
412
450
  type: "text",
@@ -414,42 +452,44 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
414
452
  },
415
453
  ],
416
454
  };
455
+ } else {
456
+ result = {
457
+ content: [
458
+ {
459
+ type: "text",
460
+ text: `RECALLED MEMORY [${key}]:\n${memory.value}\n\n(Stored: ${memory.timestamp})`,
461
+ },
462
+ ],
463
+ };
417
464
  }
418
- return {
419
- content: [
420
- {
421
- type: "text",
422
- text: `RECALLED MEMORY [${key}]:\n${memory.value}\n\n(Stored: ${memory.timestamp})`,
423
- },
424
- ],
425
- };
426
- }
465
+ } else {
466
+ const keys = Object.keys(store.memories);
467
+ if (keys.length === 0) {
468
+ result = {
469
+ content: [
470
+ {
471
+ type: "text",
472
+ text: "NO MEMORIES STORED. Use rigour_remember to persist important instructions.",
473
+ },
474
+ ],
475
+ };
476
+ } else {
477
+ const allMemories = keys.map(k => {
478
+ const mem = store.memories[k];
479
+ return `## ${k}\n${mem.value}\n(Stored: ${mem.timestamp})`;
480
+ }).join("\n\n---\n\n");
427
481
 
428
- const keys = Object.keys(store.memories);
429
- if (keys.length === 0) {
430
- return {
431
- content: [
432
- {
433
- type: "text",
434
- text: "NO MEMORIES STORED. Use rigour_remember to persist important instructions.",
435
- },
436
- ],
437
- };
482
+ result = {
483
+ content: [
484
+ {
485
+ type: "text",
486
+ text: `RECALLED ALL MEMORIES (${keys.length} items):\n\n${allMemories}\n\n---\nIMPORTANT: Follow these stored instructions throughout this session.`,
487
+ },
488
+ ],
489
+ };
490
+ }
438
491
  }
439
-
440
- const allMemories = keys.map(k => {
441
- const mem = store.memories[k];
442
- return `## ${k}\n${mem.value}\n(Stored: ${mem.timestamp})`;
443
- }).join("\n\n---\n\n");
444
-
445
- return {
446
- content: [
447
- {
448
- type: "text",
449
- text: `RECALLED ALL MEMORIES (${keys.length} items):\n\n${allMemories}\n\n---\nIMPORTANT: Follow these stored instructions throughout this session.`,
450
- },
451
- ],
452
- };
492
+ break;
453
493
  }
454
494
 
455
495
  case "rigour_forget": {
@@ -457,7 +497,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
457
497
  const store = await loadMemory(cwd);
458
498
 
459
499
  if (!store.memories[key]) {
460
- return {
500
+ result = {
461
501
  content: [
462
502
  {
463
503
  type: "text",
@@ -465,19 +505,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
465
505
  },
466
506
  ],
467
507
  };
468
- }
469
-
470
- delete store.memories[key];
471
- await saveMemory(cwd, store);
508
+ } else {
509
+ delete store.memories[key];
510
+ await saveMemory(cwd, store);
472
511
 
473
- return {
474
- content: [
475
- {
476
- type: "text",
477
- text: `MEMORY DELETED: "${key}" has been removed.`,
478
- },
479
- ],
480
- };
512
+ result = {
513
+ content: [
514
+ {
515
+ type: "text",
516
+ text: `MEMORY DELETED: "${key}" has been removed.`,
517
+ },
518
+ ],
519
+ };
520
+ }
521
+ break;
481
522
  }
482
523
 
483
524
  case "rigour_check_pattern": {
@@ -546,7 +587,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
546
587
  resultText += `\nRECOMMENDED ACTION: ${recommendation}`;
547
588
  }
548
589
 
549
- return {
590
+ result = {
550
591
  content: [
551
592
  {
552
593
  type: "text",
@@ -554,12 +595,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
554
595
  },
555
596
  ],
556
597
  };
598
+ break;
557
599
  }
558
600
 
559
601
  case "rigour_security_audit": {
560
602
  const security = new SecurityDetector(cwd);
561
603
  const summary = await security.getSecuritySummary();
562
- return {
604
+ result = {
563
605
  content: [
564
606
  {
565
607
  type: "text",
@@ -567,13 +609,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
567
609
  },
568
610
  ],
569
611
  };
612
+ break;
570
613
  }
571
614
 
572
615
  default:
573
616
  throw new Error(`Unknown tool: ${name}`);
574
617
  }
618
+
619
+ await logStudioEvent(cwd, {
620
+ type: "tool_response",
621
+ requestId,
622
+ tool: name,
623
+ status: "success",
624
+ content: result.content,
625
+ _rigour_report: (result as any)._rigour_report
626
+ });
627
+
628
+ return result;
629
+
575
630
  } catch (error: any) {
576
- return {
631
+ const errorResponse = {
577
632
  content: [
578
633
  {
579
634
  type: "text",
@@ -582,6 +637,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
582
637
  ],
583
638
  isError: true,
584
639
  };
640
+
641
+ await logStudioEvent(cwd, {
642
+ type: "tool_response",
643
+ requestId,
644
+ tool: name,
645
+ status: "error",
646
+ error: error.message,
647
+ content: errorResponse.content
648
+ });
649
+
650
+ return errorResponse;
585
651
  }
586
652
  });
587
653