@rigour-labs/mcp 6.5.4 → 6.6.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.
@@ -11,7 +11,7 @@
11
11
  import fs from 'fs-extra';
12
12
  import path from 'path';
13
13
  import { createHash } from 'crypto';
14
- import { getTaskContextStats, getTaskCostStats, getCacheStats, explainContext, getSemanticQueryCache, setSemanticQueryCache, findRelatedSemanticQueryCache, filterExistingEditScope, estimateTokenCount, ensureAutomaticIndex, getApplicableLessons, searchTeamKnowledge, recordScopeOffer, } from '@rigour-labs/core';
14
+ import { getTaskContextStats, getTaskCostStats, getCacheStats, explainContext, getSemanticQueryCache, setSemanticQueryCache, findRelatedSemanticQueryCache, filterExistingEditScope, estimateTokenCount, ensureAutomaticIndex, getApplicableLessons, recordLessonsServed, searchTeamKnowledge, recordScopeOffer, } from '@rigour-labs/core';
15
15
  import { loadPatternIndex, getDefaultIndexPath, generateEmbedding, semanticSearch, } from '@rigour-labs/core/pattern-index';
16
16
  import { buildTelemetryMeta, getWorkspaceCommitSha } from '../utils/context-telemetry.js';
17
17
  import { appendContextFooter } from '../utils/context-footer.js';
@@ -262,6 +262,7 @@ export async function handleContextScope(cwd, query, limit = 10, taskId, agentId
262
262
  getApplicableLessons(cwd, agentId, process.env.RIGOUR_TEAM_ID),
263
263
  searchTeamKnowledge(query, Math.min(limit, 8)),
264
264
  ]);
265
+ recordLessonsServed(cwd, 'context', applicableLearning.lessons.map(lesson => lesson.subject));
265
266
  let fullFileTokens = 0;
266
267
  const offered = [];
267
268
  for (const file of editScope) {
@@ -3,50 +3,11 @@
3
3
  *
4
4
  * Wraps PatternIndexer for agent-accessible index build/update.
5
5
  */
6
- import path from 'path';
7
6
  import { PatternIndexer, savePatternIndex, loadPatternIndex, getDefaultIndexPath, } from '@rigour-labs/core/pattern-index';
8
- import { setStaticCache, setComponentCache, recordIndexChoice, } from '@rigour-labs/core';
7
+ import { recordIndexChoice } from '@rigour-labs/core';
9
8
  import { notifyProgress } from '../utils/notifications.js';
10
- import { buildTelemetryMeta, getWorkspaceCommitSha } from '../utils/context-telemetry.js';
9
+ import { buildTelemetryMeta } from '../utils/context-telemetry.js';
11
10
  import { appendContextFooter } from '../utils/context-footer.js';
12
- import fs from 'fs-extra';
13
- async function syncIndexToCache(cwd, index) {
14
- const commitSha = await getWorkspaceCommitSha(cwd);
15
- const repo = path.basename(cwd);
16
- const byFile = new Map();
17
- for (const pattern of index.patterns) {
18
- const list = byFile.get(pattern.file) ?? [];
19
- list.push(pattern);
20
- byFile.set(pattern.file, list);
21
- }
22
- for (const [filePath, patterns] of byFile) {
23
- const absPath = path.join(cwd, filePath);
24
- let content = '';
25
- try {
26
- if (await fs.pathExists(absPath)) {
27
- content = await fs.readFile(absPath, 'utf-8');
28
- }
29
- }
30
- catch {
31
- content = patterns.map(p => p.signature ?? p.name).join('\n');
32
- }
33
- await setStaticCache(repo, 'main', filePath, content || filePath, {
34
- exports: patterns.map(p => p.name),
35
- rigourPatterns: patterns.map(p => `${p.type}:${p.name}`),
36
- ownership: path.dirname(filePath),
37
- }, cwd);
38
- const componentName = path.dirname(filePath) || filePath;
39
- const dossier = {
40
- component: componentName,
41
- responsibility: `Indexed patterns in ${filePath}`,
42
- canonicalFiles: [filePath],
43
- contracts: patterns.filter(p => p.type === 'interface' || p.type === 'type').map(p => p.name),
44
- directConsumers: [],
45
- validationCommands: [],
46
- };
47
- await setComponentCache(componentName, commitSha, dossier, `index-${index.lastUpdated}`, '3', cwd);
48
- }
49
- }
50
11
  export async function handleIndex(cwd, options = {}) {
51
12
  const indexPath = options.output || getDefaultIndexPath(cwd);
52
13
  const candidateEstimate = 'Full codebase AST scan for pattern extraction';
@@ -63,7 +24,6 @@ export async function handleIndex(cwd, options = {}) {
63
24
  index = await indexer.buildIndex();
64
25
  }
65
26
  await savePatternIndex(index, indexPath);
66
- await syncIndexToCache(cwd, index);
67
27
  await recordIndexChoice(cwd, index, semantic);
68
28
  notifyProgress('info', 'Pattern index complete');
69
29
  const byType = Object.entries(index.stats.byType)
@@ -76,7 +36,7 @@ export async function handleIndex(cwd, options = {}) {
76
36
  text += `- Duration: ${index.stats.indexDurationMs}ms\n`;
77
37
  text += `- Search by meaning: ${semantic ? (index.patterns.some(p => p.embedding?.length) ? 'on' : 'unavailable (local model did not load; name matching still works)') : 'off'}\n`;
78
38
  text += `- Types: ${byType}\n\n`;
79
- text += `Index synced to context cache layers. Use rigour_context_scope before reading files.`;
39
+ text += `Use rigour_context_scope before reading files.`;
80
40
  const telemetry = buildTelemetryMeta({
81
41
  candidateText: candidateEstimate,
82
42
  returnedText: text,
@@ -145,7 +145,7 @@ async function shareWithTeam(cwd, key, value) {
145
145
  if (!(await loadTeamConfiguration())) {
146
146
  return '\nKept as a team candidate on this machine; it is shared once team mode is configured (rigour team configure).';
147
147
  }
148
- return '\nShared with your team as a candidate. Teammates\' agents receive it once someone promotes it in Studio (Knowledge › Lessons).';
148
+ return '\nShared with your team as a candidate. Teammates\' agents receive it once someone shares it from Studio (How it learns).';
149
149
  }
150
150
  export async function handleForget(cwd, key, scope = 'repo') {
151
151
  const store = await loadMemory(cwd, scope);
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * Every returned memory passes the credential scan first; nothing is cached.
12
12
  */
13
- import { formatDLPAlert, createDLPAuditEntry, listKnowledgeLessons, rankByMeaning, rankMemories, scanInputForCredentials, searchTeamKnowledge } from '@rigour-labs/core';
13
+ import { formatDLPAlert, createDLPAuditEntry, listKnowledgeLessons, rankByMeaning, rankMemories, recordLessonsServed, scanInputForCredentials, searchTeamKnowledge } from '@rigour-labs/core';
14
14
  import { loadMemory } from '../utils/config.js';
15
15
  import { appendDLPAudit, getIndexHealthBlock, wrapRecallResult } from './memory-handlers.js';
16
16
  export async function handleRecall(cwd, args = {}) {
@@ -51,6 +51,7 @@ async function recallQuery(cwd, query, entries, candidateText) {
51
51
  searchTeamKnowledge(query, 3),
52
52
  ]);
53
53
  const teamOnly = team.status === 'ready' ? team.candidates.filter(c => !lessons.some(l => l.id === c.lessonId)) : [];
54
+ recordLessonsServed(cwd, 'recall', [...lessons.map(l => l.subject), ...teamOnly.map(c => c.subject)]);
54
55
  const sections = [];
55
56
  if (ranked.length) {
56
57
  sections.push(`MEMORIES MATCHING "${query}":\n\n` + ranked.map(m => `## ${m.key} (${m.scope}, ${m.match} ${m.score.toFixed(2)})\n${m.value}`).join('\n\n'));
@@ -9,7 +9,7 @@ import path from "path";
9
9
  import yaml from "yaml";
10
10
  import fs from "fs-extra";
11
11
  import { assessPattern, loadPatternIndex, getDefaultIndexPath, SecurityDetector, } from "@rigour-labs/core/pattern-index";
12
- import { ConfigSchema, estimateTokenCount } from "@rigour-labs/core";
12
+ import { ConfigSchema, estimateTokenCount, recordReuseSuggested } from "@rigour-labs/core";
13
13
  import { notifyProgress } from '../utils/notifications.js';
14
14
  import { buildTelemetryMeta } from '../utils/context-telemetry.js';
15
15
  import { appendContextFooter } from '../utils/context-footer.js';
@@ -90,6 +90,8 @@ export async function handleCheckPattern(cwd, patternName, type, intent, file, s
90
90
  resultText += action === 'BLOCK' ? `🚨 PATTERN REINVENTION DETECTED\n` : `💡 SIMILAR PATTERN EXISTS\n`;
91
91
  resultText += `"${best.pattern.name}" in ${best.pattern.file}:${best.pattern.line} (${best.matchType}, ${best.confidence}%)\n`;
92
92
  resultText += `SUGGESTION: ${assessment.suggestion}\n\n`;
93
+ if (action !== 'ALLOW')
94
+ recordReuseSuggested(cwd, patternName, `${best.pattern.name} in ${best.pattern.file}:${best.pattern.line}`, action);
93
95
  }
94
96
  if (assessment.deprecations.length) {
95
97
  resultText += `⚠️ THE EXISTING "${matchedPattern?.name}" USES SOMETHING DEPRECATED\n`;
@@ -5,7 +5,7 @@
5
5
  * With no diff, the change is taken from git: uncommitted work (what the
6
6
  * agent just wrote, new files included), or the branch against `base`.
7
7
  */
8
- import { acknowledgeReview, buildReviewTask, diffFromGit, recordFixLessons, recordReviewOutcome, reviewChange, toReviewFinding } from "@rigour-labs/core";
8
+ import { acknowledgeReview, buildReviewTask, diffFromGit, recordFixLessons, recordLessonsServed, recordReviewOutcome, reviewChange, toReviewFinding } from "@rigour-labs/core";
9
9
  import { notifyProgress } from '../utils/notifications.js';
10
10
  export async function handleReview(config, cwd, args) {
11
11
  notifyProgress("info", args.diff ? "Reviewing the provided diff..." : `Reviewing ${args.base ? `this branch against ${args.base}` : "uncommitted changes"}...`);
@@ -13,7 +13,9 @@ export async function handleReview(config, cwd, args) {
13
13
  const diff = args.diff ?? diffFromGit(cwd, args.base ? { mode: 'base', base: args.base } : { mode: 'working' });
14
14
  const result = await reviewChange({ cwd, config, diff, files: args.files });
15
15
  const task = args.mode === 'agent' ? buildReviewTask(cwd, diff, config.gates.deep?.router, config.gates.deep?.review_lessons, config.gates.deep?.repo_rules) : undefined;
16
- const capture = recordReviewOutcome(cwd, result.findings, Object.keys(result.changedLines));
16
+ const capture = recordReviewOutcome(cwd, result.findings, Object.keys(result.changedLines), 'review');
17
+ if (task)
18
+ recordLessonsServed(cwd, 'review', task.lessons.map(l => l.text));
17
19
  await recordFixLessons(cwd, capture.fixes).catch(() => undefined); // learning never fails a review
18
20
  const stats = result.report?.stats;
19
21
  return text({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/mcp",
3
- "version": "6.5.4",
3
+ "version": "6.6.0",
4
4
  "description": "MCP server + live dashboard for AI code governance — OWASP LLM Top 10 (10/10), real-time MCP App UI, 25+ security patterns, memory and lessons recalled by meaning, hallucinated import detection, multi-agent governance. Works with Claude, Cursor, VS Code, ChatGPT, Goose, Windsurf. Industry presets for HIPAA, SOC2, FedRAMP.",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -65,7 +65,7 @@
65
65
  "execa": "^8.0.1",
66
66
  "fs-extra": "^11.4.0",
67
67
  "yaml": "^2.8.2",
68
- "@rigour-labs/core": "6.5.4"
68
+ "@rigour-labs/core": "6.6.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.0.3",