@rigour-labs/mcp 6.5.2 → 6.5.3
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 +8 -10
- package/dist/advertised-tools.d.ts +49 -0
- package/dist/dashboard/html.d.ts +1 -1
- package/dist/dashboard/html.js +16 -13
- package/dist/dashboard/index.d.ts +2 -1
- package/dist/dashboard/index.js +2 -1
- package/dist/dashboard/knowledge.d.ts +15 -0
- package/dist/dashboard/knowledge.js +47 -0
- package/dist/dashboard/state.d.ts +17 -3
- package/dist/dashboard/state.js +19 -6
- package/dist/index.js +23 -17
- package/dist/tools/definitions.d.ts +49 -0
- package/dist/tools/definitions.js +9 -4
- package/dist/tools/index-handlers.js +6 -5
- package/dist/tools/memory-handlers.d.ts +27 -4
- package/dist/tools/memory-handlers.js +34 -125
- package/dist/tools/memory-recall.d.ts +6 -0
- package/dist/tools/memory-recall.js +105 -0
- package/dist/tools/pattern-handlers.d.ts +1 -1
- package/dist/tools/pattern-handlers.js +26 -59
- package/dist/tools/review-handler.js +4 -2
- package/dist/utils/config.d.ts +19 -3
- package/dist/utils/config.js +11 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -48,8 +48,8 @@ Rigour moves code quality enforcement from "Post-Commit" to "In-Progress." By ru
|
|
|
48
48
|
|
|
49
49
|
| Tool | Description |
|
|
50
50
|
|:---|:---|
|
|
51
|
-
| `rigour_remember` |
|
|
52
|
-
| `rigour_recall` |
|
|
51
|
+
| `rigour_remember` | Memory for this repository, all your repositories (`scope: "user"`), or your team (`scope: "team"`, served once promoted). Refuses values containing credentials. |
|
|
52
|
+
| `rigour_recall` | `query`: the memories that match by meaning, plus promoted team knowledge; `key`: one memory. Withholds any memory containing a credential. |
|
|
53
53
|
| `rigour_forget` | Removes a stored memory by key. |
|
|
54
54
|
|
|
55
55
|
### Real-Time Hooks & DLP
|
|
@@ -111,21 +111,17 @@ Hallucinated import detection with full stdlib whitelists and dependency manifes
|
|
|
111
111
|
|
|
112
112
|
## 📦 Installation
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
npm install -g @rigour-labs/mcp
|
|
117
|
-
```
|
|
114
|
+
No global install: npx fetches the server when your agent starts it. Keep a version in the package name (`@latest`, or a major such as `@6`); with a bare `@rigour-labs/mcp`, npx runs any older copy installed globally instead. If you once ran `npm install -g @rigour-labs/mcp`, remove it with `npm rm -g @rigour-labs/mcp`.
|
|
118
115
|
|
|
119
|
-
|
|
116
|
+
**Claude Code:** use the plugin (`/plugin marketplace add rigour-labs/rigour-plugin`, then `/plugin install rigour@rigour-labs`).
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
Add the following to your MCP settings:
|
|
118
|
+
**Cursor, Claude Desktop and other MCP clients:**
|
|
123
119
|
```json
|
|
124
120
|
{
|
|
125
121
|
"mcpServers": {
|
|
126
122
|
"rigour": {
|
|
127
123
|
"command": "npx",
|
|
128
|
-
"args": ["-y", "@rigour-labs/mcp@
|
|
124
|
+
"args": ["-y", "@rigour-labs/mcp@latest"],
|
|
129
125
|
"env": {
|
|
130
126
|
"RIGOUR_CWD": "/path/to/your/project"
|
|
131
127
|
}
|
|
@@ -134,6 +130,8 @@ Add the following to your MCP settings:
|
|
|
134
130
|
}
|
|
135
131
|
```
|
|
136
132
|
|
|
133
|
+
Only Rigour's core tools are listed by default; add `"RIGOUR_MCP_TOOLS": "governance,telemetry"` (or `"full"`) to `env` for the rest. Node.js 22 or later is required.
|
|
134
|
+
|
|
137
135
|
---
|
|
138
136
|
|
|
139
137
|
## 📖 Documentation
|
|
@@ -154,6 +154,11 @@ export declare function getAdvertisedToolDefinitions(spec?: string): ({
|
|
|
154
154
|
type: string;
|
|
155
155
|
description: string;
|
|
156
156
|
};
|
|
157
|
+
scope: {
|
|
158
|
+
type: string;
|
|
159
|
+
enum: string[];
|
|
160
|
+
description: string;
|
|
161
|
+
};
|
|
157
162
|
cwd: {
|
|
158
163
|
type: "string";
|
|
159
164
|
description: string;
|
|
@@ -178,6 +183,39 @@ export declare function getAdvertisedToolDefinitions(spec?: string): ({
|
|
|
178
183
|
type: string;
|
|
179
184
|
description: string;
|
|
180
185
|
};
|
|
186
|
+
query: {
|
|
187
|
+
type: string;
|
|
188
|
+
description: string;
|
|
189
|
+
};
|
|
190
|
+
cwd: {
|
|
191
|
+
type: "string";
|
|
192
|
+
description: string;
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
required: string[];
|
|
196
|
+
};
|
|
197
|
+
annotations: {
|
|
198
|
+
title: string;
|
|
199
|
+
readOnlyHint: boolean;
|
|
200
|
+
destructiveHint: boolean;
|
|
201
|
+
idempotentHint: boolean;
|
|
202
|
+
openWorldHint: boolean;
|
|
203
|
+
};
|
|
204
|
+
} | {
|
|
205
|
+
name: string;
|
|
206
|
+
description: string;
|
|
207
|
+
inputSchema: {
|
|
208
|
+
type: string;
|
|
209
|
+
properties: {
|
|
210
|
+
key: {
|
|
211
|
+
type: string;
|
|
212
|
+
description: string;
|
|
213
|
+
};
|
|
214
|
+
scope: {
|
|
215
|
+
type: string;
|
|
216
|
+
enum: string[];
|
|
217
|
+
description: string;
|
|
218
|
+
};
|
|
181
219
|
cwd: {
|
|
182
220
|
type: "string";
|
|
183
221
|
description: string;
|
|
@@ -210,6 +248,17 @@ export declare function getAdvertisedToolDefinitions(spec?: string): ({
|
|
|
210
248
|
type: string;
|
|
211
249
|
description: string;
|
|
212
250
|
};
|
|
251
|
+
signature: {
|
|
252
|
+
type: string;
|
|
253
|
+
description: string;
|
|
254
|
+
};
|
|
255
|
+
keywords: {
|
|
256
|
+
type: string;
|
|
257
|
+
items: {
|
|
258
|
+
type: string;
|
|
259
|
+
};
|
|
260
|
+
description: string;
|
|
261
|
+
};
|
|
213
262
|
file: {
|
|
214
263
|
type: string;
|
|
215
264
|
description: string;
|
package/dist/dashboard/html.d.ts
CHANGED
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
*
|
|
13
13
|
* No external dependencies. Initial state injected via __INITIAL_STATE__.
|
|
14
14
|
*/
|
|
15
|
-
export declare const DASHBOARD_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>Rigour Governance</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0d1117;color:#c9d1d9;padding:16px;font-size:13px;line-height:1.5}\n.header{display:flex;align-items:center;gap:8px;margin-bottom:16px}\n.header h1{font-size:15px;font-weight:600;color:#f0f6fc}\n.header .badge{font-size:11px;padding:2px 8px;border-radius:12px;font-weight:500}\n.badge-pass{background:#1a7f37;color:#fff}\n.badge-fail{background:#da3633;color:#fff}\n.badge-scanning{background:#9e6a03;color:#fff}\n.badge-idle{background:#30363d;color:#8b949e}\n.top{display:flex;gap:16px;margin-bottom:16px}\n.gauge-wrap{flex:0 0 100px;text-align:center}\n.gauge-label{font-size:11px;color:#8b949e;margin-top:4px}\n.severity-wrap{flex:1;display:flex;flex-direction:column;justify-content:center;gap:6px}\n.sev-row{display:flex;align-items:center;gap:6px;font-size:12px}\n.sev-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}\n.sev-critical{background:#da3633}\n.sev-high{background:#db6d28}\n.sev-medium{background:#9e6a03}\n.sev-low{background:#388bfd}\n.sev-info{background:#8b949e}\n.sev-count{color:#f0f6fc;font-weight:600;min-width:18px}\n.section-title{font-size:11px;color:#8b949e;text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;font-weight:600}\n.timeline{max-height:200px;overflow-y:auto;margin-bottom:16px}\n.timeline::-webkit-scrollbar{width:4px}\n.timeline::-webkit-scrollbar-thumb{background:#30363d;border-radius:2px}\n.tl-entry{display:flex;gap:8px;padding:4px 0;border-bottom:1px solid #21262d;font-size:12px}\n.tl-time{color:#8b949e;flex:0 0 55px;font-family:'SF Mono',Monaco,monospace;font-size:11px}\n.tl-tool{color:#58a6ff;flex:0 0 auto}\n.tl-arrow{color:#484f58}\n.tl-detail{color:#c9d1d9;flex:1}\n.tl-status-success .tl-detail{color:#3fb950}\n.tl-status-error .tl-detail{color:#da3633}\n.tl-status-warning .tl-detail{color:#d29922}\n.brain{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#161b22;border:1px solid #30363d;border-radius:6px;font-size:12px}\n.brain-icon{font-size:16px}\n.brain-text{color:#c9d1d9}\n.brain-trend{color:#3fb950;font-weight:600}\n.brain-trend.down{color:#da3633}\n.empty{text-align:center;padding:32px 16px;color:#484f58;font-size:12px}\n</style>\n</head>\n<body>\n<div class=\"header\">\n <h1>Rigour Governance</h1>\n <span class=\"badge badge-idle\" id=\"statusBadge\">idle</span>\n</div>\n\n<div class=\"top\">\n <div class=\"gauge-wrap\">\n <svg viewBox=\"0 0 100 100\" width=\"90\" height=\"90\">\n <circle cx=\"50\" cy=\"50\" r=\"42\" fill=\"none\" stroke=\"#21262d\" stroke-width=\"8\"/>\n <circle cx=\"50\" cy=\"50\" r=\"42\" fill=\"none\" stroke=\"#30363d\" stroke-width=\"8\"\n stroke-dasharray=\"264\" stroke-dashoffset=\"264\" stroke-linecap=\"round\"\n transform=\"rotate(-90 50 50)\" id=\"gaugeArc\"/>\n <text x=\"50\" y=\"46\" text-anchor=\"middle\" fill=\"#f0f6fc\" font-size=\"22\" font-weight=\"700\" id=\"gaugeText\">--</text>\n <text x=\"50\" y=\"62\" text-anchor=\"middle\" fill=\"#8b949e\" font-size=\"9\">SCORE</text>\n </svg>\n </div>\n <div class=\"severity-wrap\" id=\"severityWrap\">\n <div class=\"sev-row\"><span class=\"sev-dot sev-critical\"></span><span class=\"sev-count\" id=\"sevCritical\">0</span>critical</div>\n <div class=\"sev-row\"><span class=\"sev-dot sev-high\"></span><span class=\"sev-count\" id=\"sevHigh\">0</span>high</div>\n <div class=\"sev-row\"><span class=\"sev-dot sev-medium\"></span><span class=\"sev-count\" id=\"sevMedium\">0</span>medium</div>\n <div class=\"sev-row\"><span class=\"sev-dot sev-low\"></span><span class=\"sev-count\" id=\"sevLow\">0</span>low</div>\n </div>\n</div>\n\n<div class=\"section-title\">Activity</div>\n<div class=\"timeline\" id=\"timeline\">\n <div class=\"empty\">Waiting for agent activity...</div>\n</div>\n\n<div class=\"brain\" id=\"brainSection\">\n <span class=\"brain-icon\">🧠</span>\n <span class=\"brain-text\" id=\"brainText\">
|
|
15
|
+
export declare const DASHBOARD_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>Rigour Governance</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0d1117;color:#c9d1d9;padding:16px;font-size:13px;line-height:1.5}\n.header{display:flex;align-items:center;gap:8px;margin-bottom:16px}\n.header h1{font-size:15px;font-weight:600;color:#f0f6fc}\n.header .badge{font-size:11px;padding:2px 8px;border-radius:12px;font-weight:500}\n.badge-pass{background:#1a7f37;color:#fff}\n.badge-fail{background:#da3633;color:#fff}\n.badge-scanning{background:#9e6a03;color:#fff}\n.badge-idle{background:#30363d;color:#8b949e}\n.top{display:flex;gap:16px;margin-bottom:16px}\n.gauge-wrap{flex:0 0 100px;text-align:center}\n.gauge-label{font-size:11px;color:#8b949e;margin-top:4px}\n.severity-wrap{flex:1;display:flex;flex-direction:column;justify-content:center;gap:6px}\n.sev-row{display:flex;align-items:center;gap:6px;font-size:12px}\n.sev-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}\n.sev-critical{background:#da3633}\n.sev-high{background:#db6d28}\n.sev-medium{background:#9e6a03}\n.sev-low{background:#388bfd}\n.sev-info{background:#8b949e}\n.sev-count{color:#f0f6fc;font-weight:600;min-width:18px}\n.section-title{font-size:11px;color:#8b949e;text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;font-weight:600}\n.timeline{max-height:200px;overflow-y:auto;margin-bottom:16px}\n.timeline::-webkit-scrollbar{width:4px}\n.timeline::-webkit-scrollbar-thumb{background:#30363d;border-radius:2px}\n.tl-entry{display:flex;gap:8px;padding:4px 0;border-bottom:1px solid #21262d;font-size:12px}\n.tl-time{color:#8b949e;flex:0 0 55px;font-family:'SF Mono',Monaco,monospace;font-size:11px}\n.tl-tool{color:#58a6ff;flex:0 0 auto}\n.tl-arrow{color:#484f58}\n.tl-detail{color:#c9d1d9;flex:1}\n.tl-status-success .tl-detail{color:#3fb950}\n.tl-status-error .tl-detail{color:#da3633}\n.tl-status-warning .tl-detail{color:#d29922}\n.brain{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#161b22;border:1px solid #30363d;border-radius:6px;font-size:12px}\n.brain-icon{font-size:16px}\n.brain-text{color:#c9d1d9}\n.brain-trend{color:#3fb950;font-weight:600}\n.brain-trend.down{color:#da3633}\n.empty{text-align:center;padding:32px 16px;color:#484f58;font-size:12px}\n</style>\n</head>\n<body>\n<div class=\"header\">\n <h1>Rigour Governance</h1>\n <span class=\"badge badge-idle\" id=\"statusBadge\">idle</span>\n</div>\n\n<div class=\"top\">\n <div class=\"gauge-wrap\">\n <svg viewBox=\"0 0 100 100\" width=\"90\" height=\"90\">\n <circle cx=\"50\" cy=\"50\" r=\"42\" fill=\"none\" stroke=\"#21262d\" stroke-width=\"8\"/>\n <circle cx=\"50\" cy=\"50\" r=\"42\" fill=\"none\" stroke=\"#30363d\" stroke-width=\"8\"\n stroke-dasharray=\"264\" stroke-dashoffset=\"264\" stroke-linecap=\"round\"\n transform=\"rotate(-90 50 50)\" id=\"gaugeArc\"/>\n <text x=\"50\" y=\"46\" text-anchor=\"middle\" fill=\"#f0f6fc\" font-size=\"22\" font-weight=\"700\" id=\"gaugeText\">--</text>\n <text x=\"50\" y=\"62\" text-anchor=\"middle\" fill=\"#8b949e\" font-size=\"9\">SCORE</text>\n </svg>\n </div>\n <div class=\"severity-wrap\" id=\"severityWrap\">\n <div class=\"sev-row\"><span class=\"sev-dot sev-critical\"></span><span class=\"sev-count\" id=\"sevCritical\">0</span>critical</div>\n <div class=\"sev-row\"><span class=\"sev-dot sev-high\"></span><span class=\"sev-count\" id=\"sevHigh\">0</span>high</div>\n <div class=\"sev-row\"><span class=\"sev-dot sev-medium\"></span><span class=\"sev-count\" id=\"sevMedium\">0</span>medium</div>\n <div class=\"sev-row\"><span class=\"sev-dot sev-low\"></span><span class=\"sev-count\" id=\"sevLow\">0</span>low</div>\n </div>\n</div>\n\n<div class=\"section-title\">Activity</div>\n<div class=\"timeline\" id=\"timeline\">\n <div class=\"empty\">Waiting for agent activity...</div>\n</div>\n\n<div class=\"brain\" id=\"brainSection\">\n <span class=\"brain-icon\">🧠</span>\n <span class=\"brain-text\" id=\"brainText\">Knowledge: waiting for the first tool call</span>\n <span class=\"brain-trend\" id=\"brainTrend\"></span>\n</div>\n\n<script>\nconst state = JSON.parse('__INITIAL_STATE__');\n\nfunction scoreColor(s) {\n if (s === null) return '#30363d';\n if (s < 50) return '#da3633';\n if (s < 80) return '#d29922';\n return '#3fb950';\n}\n\nfunction updateGauge(score) {\n const arc = document.getElementById('gaugeArc');\n const text = document.getElementById('gaugeText');\n if (score === null) {\n arc.setAttribute('stroke-dashoffset', '264');\n arc.setAttribute('stroke', '#30363d');\n text.textContent = '--';\n return;\n }\n const offset = 264 - (264 * Math.min(score, 100) / 100);\n arc.setAttribute('stroke-dashoffset', String(offset));\n arc.setAttribute('stroke', scoreColor(score));\n text.textContent = String(Math.round(score));\n}\n\nfunction updateBadge(status, source) {\n const badge = document.getElementById('statusBadge');\n badge.className = 'badge badge-' + (status || 'idle');\n const labels = {pass:'PASS',fail:'FAIL',scanning:'SCANNING'};\n badge.textContent = (labels[status] || 'IDLE') + (source === 'last-report' && status !== 'scanning' ? ' \u00B7 LAST CHECK' : '');\n}\n\nfunction updateSeverity(sev) {\n document.getElementById('sevCritical').textContent = sev.critical || 0;\n document.getElementById('sevHigh').textContent = sev.high || 0;\n document.getElementById('sevMedium').textContent = sev.medium || 0;\n document.getElementById('sevLow').textContent = sev.low || 0;\n}\n\nfunction formatTime(iso) {\n const d = new Date(iso);\n return d.toLocaleTimeString('en-US', {hour12:false,hour:'2-digit',minute:'2-digit',second:'2-digit'});\n}\n\nfunction renderTimeline(entries) {\n const el = document.getElementById('timeline');\n if (!entries.length) {\n el.innerHTML = '<div class=\"empty\">Waiting for agent activity...</div>';\n return;\n }\n el.innerHTML = entries.map(e => {\n const cls = e.status === 'success' ? 'tl-status-success' : e.status === 'error' ? 'tl-status-error' : 'tl-status-warning';\n return '<div class=\"tl-entry ' + cls + '\">' +\n '<span class=\"tl-time\">' + formatTime(e.timestamp) + '</span>' +\n '<span class=\"tl-tool\">' + e.tool + '</span>' +\n '<span class=\"tl-arrow\">\u2192</span>' +\n '<span class=\"tl-detail\">' + e.details + '</span></div>';\n }).join('');\n el.scrollTop = el.scrollHeight;\n}\n\nfunction updateBrain(k) {\n const text = document.getElementById('brainText');\n const detail = document.getElementById('brainTrend');\n if (!k) { text.textContent = 'Knowledge: waiting for the first tool call'; detail.textContent = ''; return; }\n const parts = [];\n if (k.memories) parts.push(k.memories + (k.memories === 1 ? ' memory' : ' memories'));\n if (k.lessons) parts.push(k.lessons + (k.lessons === 1 ? ' lesson' : ' lessons') + ' (' + k.trustedLessons + ' trusted)');\n if (k.learnedRules) parts.push(k.learnedRules + ' learned ' + (k.learnedRules === 1 ? 'rule' : 'rules'));\n if (k.indexedPatterns) parts.push(k.indexedPatterns + ' patterns indexed');\n text.textContent = parts.length ? 'Knows: ' + parts.join(' \u00B7 ') : 'Nothing learned yet';\n detail.textContent = k.mutedChecks ? k.mutedChecks + ' noisy check(s) muted' : parts.length ? '' : 'learns from fixes, dismissals and rigour_remember';\n detail.className = 'brain-trend';\n}\n\nfunction render() {\n updateGauge(state.currentScore);\n updateBadge(state.status, state.scoreSource);\n updateSeverity(state.severityBreakdown || {});\n renderTimeline(state.timeline || []);\n updateBrain(state.knowledge);\n}\n\nrender();\n</script>\n</body>\n</html>";
|
package/dist/dashboard/html.js
CHANGED
|
@@ -92,7 +92,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;b
|
|
|
92
92
|
|
|
93
93
|
<div class="brain" id="brainSection">
|
|
94
94
|
<span class="brain-icon">🧠</span>
|
|
95
|
-
<span class="brain-text" id="brainText">
|
|
95
|
+
<span class="brain-text" id="brainText">Knowledge: waiting for the first tool call</span>
|
|
96
96
|
<span class="brain-trend" id="brainTrend"></span>
|
|
97
97
|
</div>
|
|
98
98
|
|
|
@@ -121,11 +121,11 @@ function updateGauge(score) {
|
|
|
121
121
|
text.textContent = String(Math.round(score));
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
function updateBadge(status) {
|
|
124
|
+
function updateBadge(status, source) {
|
|
125
125
|
const badge = document.getElementById('statusBadge');
|
|
126
126
|
badge.className = 'badge badge-' + (status || 'idle');
|
|
127
127
|
const labels = {pass:'PASS',fail:'FAIL',scanning:'SCANNING'};
|
|
128
|
-
badge.textContent = labels[status] || 'IDLE';
|
|
128
|
+
badge.textContent = (labels[status] || 'IDLE') + (source === 'last-report' && status !== 'scanning' ? ' \u00b7 LAST CHECK' : '');
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
function updateSeverity(sev) {
|
|
@@ -157,23 +157,26 @@ function renderTimeline(entries) {
|
|
|
157
157
|
el.scrollTop = el.scrollHeight;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
function updateBrain(
|
|
160
|
+
function updateBrain(k) {
|
|
161
161
|
const text = document.getElementById('brainText');
|
|
162
|
-
const
|
|
163
|
-
text.textContent = '
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
const detail = document.getElementById('brainTrend');
|
|
163
|
+
if (!k) { text.textContent = 'Knowledge: waiting for the first tool call'; detail.textContent = ''; return; }
|
|
164
|
+
const parts = [];
|
|
165
|
+
if (k.memories) parts.push(k.memories + (k.memories === 1 ? ' memory' : ' memories'));
|
|
166
|
+
if (k.lessons) parts.push(k.lessons + (k.lessons === 1 ? ' lesson' : ' lessons') + ' (' + k.trustedLessons + ' trusted)');
|
|
167
|
+
if (k.learnedRules) parts.push(k.learnedRules + ' learned ' + (k.learnedRules === 1 ? 'rule' : 'rules'));
|
|
168
|
+
if (k.indexedPatterns) parts.push(k.indexedPatterns + ' patterns indexed');
|
|
169
|
+
text.textContent = parts.length ? 'Knows: ' + parts.join(' \u00b7 ') : 'Nothing learned yet';
|
|
170
|
+
detail.textContent = k.mutedChecks ? k.mutedChecks + ' noisy check(s) muted' : parts.length ? '' : 'learns from fixes, dismissals and rigour_remember';
|
|
171
|
+
detail.className = 'brain-trend';
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
function render() {
|
|
172
175
|
updateGauge(state.currentScore);
|
|
173
|
-
updateBadge(state.status);
|
|
176
|
+
updateBadge(state.status, state.scoreSource);
|
|
174
177
|
updateSeverity(state.severityBreakdown || {});
|
|
175
178
|
renderTimeline(state.timeline || []);
|
|
176
|
-
updateBrain(state.
|
|
179
|
+
updateBrain(state.knowledge);
|
|
177
180
|
}
|
|
178
181
|
|
|
179
182
|
render();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const DASHBOARD_URI = "ui://rigour/dashboard";
|
|
2
2
|
/** Get dashboard HTML with current state injected. */
|
|
3
3
|
export declare function getDashboardHtml(): string;
|
|
4
|
-
export { getState, pushTimelineEntry, updateScore,
|
|
4
|
+
export { getState, pushTimelineEntry, updateScore, updateKnowledge, seedFromLastReport, setScanning } from './state.js';
|
|
5
|
+
export { summarizeKnowledge, LEARNING_TOOLS, type KnowledgeSummary } from './knowledge.js';
|
package/dist/dashboard/index.js
CHANGED
|
@@ -13,4 +13,5 @@ export function getDashboardHtml() {
|
|
|
13
13
|
const stateJson = JSON.stringify(getState()).replace(/'/g, "\\'");
|
|
14
14
|
return DASHBOARD_HTML.replace('__INITIAL_STATE__', stateJson);
|
|
15
15
|
}
|
|
16
|
-
export { getState, pushTimelineEntry, updateScore,
|
|
16
|
+
export { getState, pushTimelineEntry, updateScore, updateKnowledge, seedFromLastReport, setScanning } from './state.js';
|
|
17
|
+
export { summarizeKnowledge, LEARNING_TOOLS } from './knowledge.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface KnowledgeSummary {
|
|
2
|
+
memories: number;
|
|
3
|
+
lessons: number;
|
|
4
|
+
/** Lessons agents may act on: validated by repeated fixes, or promoted by a person. */
|
|
5
|
+
trustedLessons: number;
|
|
6
|
+
learnedRules: number;
|
|
7
|
+
indexedPatterns: number;
|
|
8
|
+
mutedChecks: number;
|
|
9
|
+
}
|
|
10
|
+
/** Tools that change what Rigour knows: after them the summary is recomputed, never served from cache. */
|
|
11
|
+
export declare const LEARNING_TOOLS: Set<string>;
|
|
12
|
+
export declare function summarizeKnowledge(cwd: string, options?: {
|
|
13
|
+
fresh?: boolean;
|
|
14
|
+
now?: number;
|
|
15
|
+
}): Promise<KnowledgeSummary>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What Rigour knows about this repository, for the dashboard's knowledge line:
|
|
3
|
+
* read from the stores the learning features write, after every tool call.
|
|
4
|
+
* Each count is cheap (small JSON files, one local lesson query, the index
|
|
5
|
+
* stats) and any store that cannot be read counts as zero.
|
|
6
|
+
*/
|
|
7
|
+
import { checkPrecisions, listKnowledgeLessons, loadLearnedRules } from '@rigour-labs/core';
|
|
8
|
+
import { getDefaultIndexPath, loadPatternIndex } from '@rigour-labs/core/pattern-index';
|
|
9
|
+
import { loadMemory } from '../utils/config.js';
|
|
10
|
+
/** Summaries per repository for a short while: tool calls come in bursts and the counts change slowly. */
|
|
11
|
+
const SUMMARY_TTL_MS = 30_000;
|
|
12
|
+
const summaries = new Map();
|
|
13
|
+
/** Tools that change what Rigour knows: after them the summary is recomputed, never served from cache. */
|
|
14
|
+
export const LEARNING_TOOLS = new Set(['rigour_remember', 'rigour_forget', 'rigour_index', 'rigour_review', 'rigour_review_ack']);
|
|
15
|
+
export async function summarizeKnowledge(cwd, options = {}) {
|
|
16
|
+
const now = options.now ?? Date.now();
|
|
17
|
+
const cached = summaries.get(cwd);
|
|
18
|
+
if (!options.fresh && cached && now - cached.at < SUMMARY_TTL_MS)
|
|
19
|
+
return cached.summary;
|
|
20
|
+
const summary = await computeSummary(cwd);
|
|
21
|
+
summaries.set(cwd, { at: now, summary });
|
|
22
|
+
return summary;
|
|
23
|
+
}
|
|
24
|
+
async function computeSummary(cwd) {
|
|
25
|
+
const [repo, user, lessons, index] = await Promise.all([
|
|
26
|
+
loadMemory(cwd, 'repo').catch(() => ({ memories: {} })),
|
|
27
|
+
loadMemory(cwd, 'user').catch(() => ({ memories: {} })),
|
|
28
|
+
listKnowledgeLessons(cwd).catch(() => []),
|
|
29
|
+
loadPatternIndex(getDefaultIndexPath(cwd)).catch(() => null),
|
|
30
|
+
]);
|
|
31
|
+
return {
|
|
32
|
+
memories: new Set([...Object.keys(repo.memories), ...Object.keys(user.memories)]).size,
|
|
33
|
+
lessons: lessons.length,
|
|
34
|
+
trustedLessons: lessons.filter(l => l.state === 'validated' || l.state === 'promoted').length,
|
|
35
|
+
learnedRules: safeCount(() => loadLearnedRules(cwd).length),
|
|
36
|
+
indexedPatterns: index?.stats.totalPatterns ?? 0,
|
|
37
|
+
mutedChecks: safeCount(() => checkPrecisions(cwd).filter(c => c.muted).length),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function safeCount(count) {
|
|
41
|
+
try {
|
|
42
|
+
return count();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* the MCP App dashboard HTML on each resource fetch.
|
|
6
6
|
* Single-threaded Node.js — no locking needed.
|
|
7
7
|
*/
|
|
8
|
+
import type { KnowledgeSummary } from './knowledge.js';
|
|
8
9
|
export interface TimelineEntry {
|
|
9
10
|
timestamp: string;
|
|
10
11
|
tool: string;
|
|
@@ -14,13 +15,26 @@ export interface TimelineEntry {
|
|
|
14
15
|
export interface DashboardState {
|
|
15
16
|
currentScore: number | null;
|
|
16
17
|
status: "pass" | "fail" | "scanning" | null;
|
|
18
|
+
/** Where the score came from: a check in this session, or the last report on disk. */
|
|
19
|
+
scoreSource: "session" | "last-report" | null;
|
|
17
20
|
timeline: TimelineEntry[];
|
|
18
21
|
severityBreakdown: Record<string, number>;
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
/** What Rigour knows about this repository (knowledge.ts); null until the first tool call. */
|
|
23
|
+
knowledge: KnowledgeSummary | null;
|
|
21
24
|
}
|
|
22
25
|
export declare function getState(): DashboardState;
|
|
23
26
|
export declare function pushTimelineEntry(tool: string, status: string, details: string): void;
|
|
24
27
|
export declare function updateScore(score: number, status: "pass" | "fail", severity?: Record<string, number>): void;
|
|
25
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Start from the last check run anywhere (CLI, hook, CI) while this session has not run one:
|
|
30
|
+
* otherwise the dashboard shows "--" next to a fix packet that came from that very report.
|
|
31
|
+
*/
|
|
32
|
+
export declare function seedFromLastReport(report: {
|
|
33
|
+
status?: string;
|
|
34
|
+
stats?: {
|
|
35
|
+
score?: number;
|
|
36
|
+
severity_breakdown?: Record<string, number>;
|
|
37
|
+
};
|
|
38
|
+
} | null): void;
|
|
39
|
+
export declare function updateKnowledge(knowledge: KnowledgeSummary | null): void;
|
|
26
40
|
export declare function setScanning(): void;
|
package/dist/dashboard/state.js
CHANGED
|
@@ -9,10 +9,10 @@ const MAX_TIMELINE = 50;
|
|
|
9
9
|
const state = {
|
|
10
10
|
currentScore: null,
|
|
11
11
|
status: null,
|
|
12
|
+
scoreSource: null,
|
|
12
13
|
timeline: [],
|
|
13
14
|
severityBreakdown: {},
|
|
14
|
-
|
|
15
|
-
brainTrend: null,
|
|
15
|
+
knowledge: null,
|
|
16
16
|
};
|
|
17
17
|
export function getState() {
|
|
18
18
|
return state;
|
|
@@ -31,13 +31,26 @@ export function pushTimelineEntry(tool, status, details) {
|
|
|
31
31
|
export function updateScore(score, status, severity) {
|
|
32
32
|
state.currentScore = score;
|
|
33
33
|
state.status = status;
|
|
34
|
+
state.scoreSource = "session";
|
|
34
35
|
if (severity)
|
|
35
36
|
state.severityBreakdown = severity;
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Start from the last check run anywhere (CLI, hook, CI) while this session has not run one:
|
|
40
|
+
* otherwise the dashboard shows "--" next to a fix packet that came from that very report.
|
|
41
|
+
*/
|
|
42
|
+
export function seedFromLastReport(report) {
|
|
43
|
+
if (state.scoreSource === "session" || typeof report?.stats?.score !== "number")
|
|
44
|
+
return;
|
|
45
|
+
state.currentScore = report.stats.score;
|
|
46
|
+
state.status = report.status === "PASS" ? "pass" : "fail";
|
|
47
|
+
state.scoreSource = "last-report";
|
|
48
|
+
if (report.stats.severity_breakdown)
|
|
49
|
+
state.severityBreakdown = report.stats.severity_breakdown;
|
|
50
|
+
}
|
|
51
|
+
export function updateKnowledge(knowledge) {
|
|
52
|
+
if (knowledge)
|
|
53
|
+
state.knowledge = knowledge;
|
|
41
54
|
}
|
|
42
55
|
export function setScanning() {
|
|
43
56
|
state.status = "scanning";
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @since v2.17.0 — refactored from 1,487-line monolith
|
|
9
9
|
*/
|
|
10
|
+
import fs from 'fs-extra';
|
|
11
|
+
import path from 'path';
|
|
10
12
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
13
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
14
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -18,12 +20,13 @@ import { bindServer } from './utils/notifications.js';
|
|
|
18
20
|
import { getMcpVersion } from './utils/package-version.js';
|
|
19
21
|
import { buildMcpResultMeta, buildStudioImpact } from './utils/impact-receipt.js';
|
|
20
22
|
// Dashboard (MCP App)
|
|
21
|
-
import { DASHBOARD_URI, getDashboardHtml, pushTimelineEntry, updateScore } from './dashboard/index.js';
|
|
23
|
+
import { DASHBOARD_URI, getDashboardHtml, LEARNING_TOOLS, pushTimelineEntry, seedFromLastReport, summarizeKnowledge, updateKnowledge, updateScore } from './dashboard/index.js';
|
|
22
24
|
// Tool definitions & advertised registry
|
|
23
25
|
import { getAdvertisedToolDefinitions } from './advertised-tools.js';
|
|
24
26
|
// Tool handlers
|
|
25
27
|
import { handleCheck, handleExplain, handleStatus, handleGetFixPacket, handleListGates, handleGetConfig } from './tools/quality-handlers.js';
|
|
26
|
-
import { handleRemember,
|
|
28
|
+
import { handleRemember, handleForget } from './tools/memory-handlers.js';
|
|
29
|
+
import { handleRecall } from './tools/memory-recall.js';
|
|
27
30
|
import { handleCheckPattern, handleSecurityAudit } from './tools/pattern-handlers.js';
|
|
28
31
|
import { handleRun, handleRunSupervised } from './tools/execution-handlers.js';
|
|
29
32
|
import { handleAgentRegister, handleCheckpoint, handleHandoff, handleAgentDeregister, handleHandoffAccept } from './tools/agent-handlers.js';
|
|
@@ -33,7 +36,7 @@ import { handleCheckDeep, handleDeepStats } from './tools/deep-handlers.js';
|
|
|
33
36
|
import { handleMcpGetSettings, handleMcpSetSettings } from './tools/mcp-settings-handler.js';
|
|
34
37
|
import { handleContextStats, handleTaskCost, handleCacheStats, handleContextExplain, handleContextScope } from './tools/context-handlers.js';
|
|
35
38
|
import { handleIndex } from './tools/index-handlers.js';
|
|
36
|
-
import { recordContextEvent, recordInteractionEvidence,
|
|
39
|
+
import { recordContextEvent, recordInteractionEvidence, syncTeamOutbox, estimateTokenCount } from '@rigour-labs/core';
|
|
37
40
|
// ─── Server Setup ─────────────────────────────────────────────────
|
|
38
41
|
const server = new Server({ name: "rigour-mcp", version: getMcpVersion('5.5.0') }, { capabilities: { tools: {}, prompts: {}, logging: {}, resources: {} } });
|
|
39
42
|
function interactionMetadata(args) {
|
|
@@ -144,17 +147,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
144
147
|
break;
|
|
145
148
|
// Memory
|
|
146
149
|
case "rigour_remember":
|
|
147
|
-
result = await handleRemember(cwd, args.key, args.value || args.content);
|
|
150
|
+
result = await handleRemember(cwd, args.key, args.value || args.content, args.scope);
|
|
148
151
|
break;
|
|
149
152
|
case "rigour_recall":
|
|
150
|
-
result = await handleRecall(cwd, args.key);
|
|
153
|
+
result = await handleRecall(cwd, { key: args.key, query: args.query });
|
|
151
154
|
break;
|
|
152
155
|
case "rigour_forget":
|
|
153
|
-
result = await handleForget(cwd, args.key);
|
|
156
|
+
result = await handleForget(cwd, args.key, args.scope);
|
|
154
157
|
break;
|
|
155
158
|
// Pattern intelligence
|
|
156
159
|
case "rigour_check_pattern":
|
|
157
|
-
result = await handleCheckPattern(cwd, args.name, args.type, args.intent, args.file);
|
|
160
|
+
result = await handleCheckPattern(cwd, args.name, args.type, args.intent, args.file, args.signature, args.keywords);
|
|
158
161
|
break;
|
|
159
162
|
case "rigour_security_audit":
|
|
160
163
|
result = await handleSecurityAudit(cwd);
|
|
@@ -286,15 +289,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
286
289
|
summary: result?._guidance?.recommendation,
|
|
287
290
|
...interactionMetadata(args),
|
|
288
291
|
});
|
|
289
|
-
await recordInteractionLesson(cwd, {
|
|
290
|
-
tool: name,
|
|
291
|
-
outcome,
|
|
292
|
-
requestId,
|
|
293
|
-
deterministic,
|
|
294
|
-
verifiedOutcome: deterministic,
|
|
295
|
-
summary: result?._guidance?.recommendation,
|
|
296
|
-
...interactionMetadata(args),
|
|
297
|
-
});
|
|
298
292
|
void syncTeamOutbox().catch(() => undefined);
|
|
299
293
|
}
|
|
300
294
|
catch {
|
|
@@ -320,6 +314,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
320
314
|
? `${report.status.toUpperCase()} — Score: ${report.stats?.score ?? '?'}/100`
|
|
321
315
|
: "completed";
|
|
322
316
|
pushTimelineEntry(name, result.isError ? "error" : "success", details);
|
|
317
|
+
updateKnowledge(await summarizeKnowledge(cwd, { fresh: LEARNING_TOOLS.has(name) }).catch(() => null));
|
|
318
|
+
seedFromLastReport(await readLastReport(cwd));
|
|
323
319
|
if (report?.stats) {
|
|
324
320
|
updateScore(report.stats.score ?? 0, report.status === "PASS" ? "pass" : "fail", report.stats.severity_breakdown);
|
|
325
321
|
}
|
|
@@ -470,6 +466,16 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
470
466
|
throw new Error(`Unknown prompt: ${name}`);
|
|
471
467
|
}
|
|
472
468
|
});
|
|
469
|
+
/** The last report `rigour check` wrote here (output.report_path), or null. */
|
|
470
|
+
async function readLastReport(cwd) {
|
|
471
|
+
try {
|
|
472
|
+
const config = await loadConfig(cwd);
|
|
473
|
+
return await fs.readJson(path.join(cwd, config.output?.report_path ?? 'rigour-report.json'));
|
|
474
|
+
}
|
|
475
|
+
catch {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
473
479
|
// ─── Start ────────────────────────────────────────────────────────
|
|
474
480
|
async function main() {
|
|
475
481
|
if (process.argv.includes('--gateway')) {
|
|
@@ -482,7 +488,7 @@ async function main() {
|
|
|
482
488
|
const transport = new StdioServerTransport();
|
|
483
489
|
await server.connect(transport);
|
|
484
490
|
void flushDailyUsage(); // a day's agent activity, if a day has passed; never awaited by the agent
|
|
485
|
-
console.error(
|
|
491
|
+
console.error(`Rigour MCP server v${getMcpVersion('unknown')} running on stdio`);
|
|
486
492
|
}
|
|
487
493
|
main().catch((error) => {
|
|
488
494
|
console.error("Fatal error in Rigour MCP server:", error);
|
|
@@ -157,6 +157,11 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
157
157
|
type: string;
|
|
158
158
|
description: string;
|
|
159
159
|
};
|
|
160
|
+
scope: {
|
|
161
|
+
type: string;
|
|
162
|
+
enum: string[];
|
|
163
|
+
description: string;
|
|
164
|
+
};
|
|
160
165
|
cwd: {
|
|
161
166
|
type: "string";
|
|
162
167
|
description: string;
|
|
@@ -181,6 +186,39 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
181
186
|
type: string;
|
|
182
187
|
description: string;
|
|
183
188
|
};
|
|
189
|
+
query: {
|
|
190
|
+
type: string;
|
|
191
|
+
description: string;
|
|
192
|
+
};
|
|
193
|
+
cwd: {
|
|
194
|
+
type: "string";
|
|
195
|
+
description: string;
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
required: string[];
|
|
199
|
+
};
|
|
200
|
+
annotations: {
|
|
201
|
+
title: string;
|
|
202
|
+
readOnlyHint: boolean;
|
|
203
|
+
destructiveHint: boolean;
|
|
204
|
+
idempotentHint: boolean;
|
|
205
|
+
openWorldHint: boolean;
|
|
206
|
+
};
|
|
207
|
+
} | {
|
|
208
|
+
name: string;
|
|
209
|
+
description: string;
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: string;
|
|
212
|
+
properties: {
|
|
213
|
+
key: {
|
|
214
|
+
type: string;
|
|
215
|
+
description: string;
|
|
216
|
+
};
|
|
217
|
+
scope: {
|
|
218
|
+
type: string;
|
|
219
|
+
enum: string[];
|
|
220
|
+
description: string;
|
|
221
|
+
};
|
|
184
222
|
cwd: {
|
|
185
223
|
type: "string";
|
|
186
224
|
description: string;
|
|
@@ -213,6 +251,17 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
213
251
|
type: string;
|
|
214
252
|
description: string;
|
|
215
253
|
};
|
|
254
|
+
signature: {
|
|
255
|
+
type: string;
|
|
256
|
+
description: string;
|
|
257
|
+
};
|
|
258
|
+
keywords: {
|
|
259
|
+
type: string;
|
|
260
|
+
items: {
|
|
261
|
+
type: string;
|
|
262
|
+
};
|
|
263
|
+
description: string;
|
|
264
|
+
};
|
|
216
265
|
file: {
|
|
217
266
|
type: string;
|
|
218
267
|
description: string;
|
|
@@ -176,13 +176,14 @@ export const TOOL_DEFINITIONS = [
|
|
|
176
176
|
// ─── Memory Persistence ───────────────────────────────
|
|
177
177
|
{
|
|
178
178
|
name: "rigour_remember",
|
|
179
|
-
description: "Store
|
|
179
|
+
description: "Store an instruction or convention to remember across sessions. Provide 'key' (short snake_case) and 'value' (the full text). scope: 'repo' (default, this repository), 'user' (all your repositories), or 'team' (this repository, and shared as a team candidate that teammates' agents receive once a person promotes it). Values containing credentials are refused.",
|
|
180
180
|
inputSchema: {
|
|
181
181
|
type: "object",
|
|
182
182
|
properties: {
|
|
183
183
|
...cwdParam(),
|
|
184
184
|
key: { type: "string", description: "A short snake_case identifier for this memory, e.g. 'api_response_format', 'naming_convention', 'testing_strategy'. This is used to retrieve the memory later." },
|
|
185
185
|
value: { type: "string", description: "The full instruction or convention text to persist. This is the content that will be recalled in future sessions." },
|
|
186
|
+
scope: { type: "string", enum: ["repo", "user", "team"], description: "Where the memory applies. Default: repo." },
|
|
186
187
|
},
|
|
187
188
|
required: ["cwd", "key", "value"],
|
|
188
189
|
},
|
|
@@ -196,12 +197,13 @@ export const TOOL_DEFINITIONS = [
|
|
|
196
197
|
},
|
|
197
198
|
{
|
|
198
199
|
name: "rigour_recall",
|
|
199
|
-
description: "Load
|
|
200
|
+
description: "Load stored conventions. At the START of a task, call it with 'query' describing the task to get the few memories that match by meaning, plus promoted team knowledge when team mode is on. With 'key' it returns that memory; with neither, every repository and user memory.",
|
|
200
201
|
inputSchema: {
|
|
201
202
|
type: "object",
|
|
202
203
|
properties: {
|
|
203
204
|
...cwdParam(),
|
|
204
205
|
key: { type: "string", description: "Optional. Key of specific memory to retrieve." },
|
|
206
|
+
query: { type: "string", description: "Optional. What you are about to do, e.g. 'add retry to the payments client'. Returns the closest memories by meaning." },
|
|
205
207
|
},
|
|
206
208
|
required: ["cwd"],
|
|
207
209
|
},
|
|
@@ -221,6 +223,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
221
223
|
properties: {
|
|
222
224
|
...cwdParam(),
|
|
223
225
|
key: { type: "string", description: "Key of the memory to remove." },
|
|
226
|
+
scope: { type: "string", enum: ["repo", "user"], description: "Which memory to remove it from. Default: repo." },
|
|
224
227
|
},
|
|
225
228
|
required: ["cwd", "key"],
|
|
226
229
|
},
|
|
@@ -243,6 +246,8 @@ export const TOOL_DEFINITIONS = [
|
|
|
243
246
|
name: { type: "string", description: "The name of the function, class, or component you want to create." },
|
|
244
247
|
type: { type: "string", description: "The type of pattern (e.g., 'function', 'component', 'hook', 'type')." },
|
|
245
248
|
intent: { type: "string", description: "What the code is for (e.g., 'format dates', 'user authentication')." },
|
|
249
|
+
signature: { type: "string", description: "Optional. The signature you plan to write, e.g. '(items: T[], size: number) => T[][]'. Matches existing code by shape, not only by name." },
|
|
250
|
+
keywords: { type: "array", items: { type: "string" }, description: "Optional. Words for what it does, e.g. ['retry', 'backoff']." },
|
|
246
251
|
file: { type: "string", description: "Target file path (relative to cwd) where the code will be written. Used to enforce protected path rules — writes to .github/, rigour.yml, etc. will be BLOCKED." },
|
|
247
252
|
},
|
|
248
253
|
required: ["cwd", "name"],
|
|
@@ -633,12 +638,12 @@ export const TOOL_DEFINITIONS = [
|
|
|
633
638
|
// ─── Pattern Index & Scoped Context ──────────────────
|
|
634
639
|
{
|
|
635
640
|
name: "rigour_index",
|
|
636
|
-
description: "Build or update the Rigour pattern index (.rigour/patterns.json). CALL THIS when the index is missing or stale — before rigour_context_scope or rigour_check_pattern. One AST pass extracts functions, classes, routes, and signatures for reuse
|
|
641
|
+
description: "Build or update the Rigour pattern index (.rigour/patterns.json). CALL THIS when the index is missing or stale — before rigour_context_scope or rigour_check_pattern. One AST pass extracts functions, classes, routes, and signatures for reuse, embedded locally so rigour_check_pattern can match by intent; semantic=false skips the embeddings.",
|
|
637
642
|
inputSchema: {
|
|
638
643
|
type: "object",
|
|
639
644
|
properties: {
|
|
640
645
|
...cwdParam(),
|
|
641
|
-
semantic: { type: "boolean", description: "
|
|
646
|
+
semantic: { type: "boolean", description: "Embed patterns so an intent can find them (local Transformers.js model). Default: true; false records an explicit opt-out." },
|
|
642
647
|
force: { type: "boolean", description: "Force a full rebuild instead of incremental update. Default: false." },
|
|
643
648
|
output: { type: "string", description: "Custom path for the index file." },
|
|
644
649
|
},
|