@minhpnq1807/contextos 0.1.6 → 0.1.8
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/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/plugins/ctx/lib/analyzer.js +46 -0
- package/plugins/ctx/lib/mcp-proxy-install.js +32 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.8
|
|
4
|
+
|
|
5
|
+
- Limits automatic MCP telemetry wrapping to `code-review-graph` only.
|
|
6
|
+
- Restores older ContextOS proxy wrappers on non-target MCP servers such as `agentmemory`.
|
|
7
|
+
- Skips RTK-managed MCP commands instead of replacing their command entry with the ContextOS proxy.
|
|
8
|
+
|
|
9
|
+
## 0.1.7
|
|
10
|
+
|
|
11
|
+
- Filters documentation-only AGENTS entries such as MCP tool headings, HTML comments, generic "Key Tools" headings, and tool reference tables before scoring.
|
|
12
|
+
- Keeps actionable tool instructions, for example `Use detect_changes for code review`, measurable through MCP telemetry.
|
|
13
|
+
|
|
3
14
|
## 0.1.6
|
|
4
15
|
|
|
5
16
|
- Adds a transparent stdio MCP telemetry proxy that records `tools/call` events while forwarding requests to the original MCP server.
|
package/package.json
CHANGED
|
@@ -62,6 +62,25 @@ const SYSTEM_USER_RULE_PATTERNS = [
|
|
|
62
62
|
/\bminh_dev\b/i
|
|
63
63
|
];
|
|
64
64
|
|
|
65
|
+
const DOCUMENTATION_HEADING_PATTERNS = [
|
|
66
|
+
/^mcp\s+tools?\s*:/i,
|
|
67
|
+
/^key\s+tools?$/i,
|
|
68
|
+
/^workflow$/i,
|
|
69
|
+
/^tools?$/i
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const TOOL_REFERENCE_TOKENS = new Set([
|
|
73
|
+
"detect_changes",
|
|
74
|
+
"get_review_context",
|
|
75
|
+
"get_impact_radius",
|
|
76
|
+
"get_affected_flows",
|
|
77
|
+
"query_graph",
|
|
78
|
+
"semantic_search_nodes",
|
|
79
|
+
"get_architecture_overview",
|
|
80
|
+
"refactor_tool",
|
|
81
|
+
"list_communities"
|
|
82
|
+
]);
|
|
83
|
+
|
|
65
84
|
export function tokenize(value) {
|
|
66
85
|
const normalized = String(value || "")
|
|
67
86
|
.toLowerCase()
|
|
@@ -155,6 +174,7 @@ export function parseRules(markdown) {
|
|
|
155
174
|
export function filterActionableRules(rules = []) {
|
|
156
175
|
return rules
|
|
157
176
|
.filter((rule) => !isSystemUserRule(rule))
|
|
177
|
+
.filter((rule) => !isDocumentationOnlyRule(rule))
|
|
158
178
|
.map((rule, index) => ({ ...rule, id: `r${index + 1}`, originalOrder: index }));
|
|
159
179
|
}
|
|
160
180
|
|
|
@@ -163,6 +183,32 @@ export function isSystemUserRule(rule) {
|
|
|
163
183
|
return SYSTEM_USER_RULE_PATTERNS.some((pattern) => pattern.test(String(content || "")));
|
|
164
184
|
}
|
|
165
185
|
|
|
186
|
+
export function isDocumentationOnlyRule(rule) {
|
|
187
|
+
const content = String(typeof rule === "string" ? rule : rule?.content || "").trim();
|
|
188
|
+
const normalized = stripMarkdownEmphasis(content);
|
|
189
|
+
if (!normalized) return true;
|
|
190
|
+
if (/^<!--.*-->$/.test(normalized)) return true;
|
|
191
|
+
if (DOCUMENTATION_HEADING_PATTERNS.some((pattern) => pattern.test(normalized))) return true;
|
|
192
|
+
if (isMarkdownTableRule(normalized)) return true;
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function stripMarkdownEmphasis(content) {
|
|
197
|
+
return String(content || "")
|
|
198
|
+
.replace(/^#+\s+/, "")
|
|
199
|
+
.replace(/^\*\*(.*)\*\*$/, "$1")
|
|
200
|
+
.trim();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function isMarkdownTableRule(content) {
|
|
204
|
+
if (!content.includes("|")) return false;
|
|
205
|
+
const pipeCount = (content.match(/\|/g) || []).length;
|
|
206
|
+
if (pipeCount < 4) return false;
|
|
207
|
+
const lower = content.toLowerCase();
|
|
208
|
+
const toolReferenceCount = [...TOOL_REFERENCE_TOKENS].filter((token) => lower.includes(token)).length;
|
|
209
|
+
return /\btool\b/.test(lower) && /\buse\s+when\b/.test(lower) && toolReferenceCount >= 2;
|
|
210
|
+
}
|
|
211
|
+
|
|
166
212
|
function dedupeRules(rules) {
|
|
167
213
|
const seen = new Set();
|
|
168
214
|
return rules.filter((rule) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
const DEFAULT_TARGETS = new Set(["code-review-graph"
|
|
4
|
+
const DEFAULT_TARGETS = new Set(["code-review-graph"]);
|
|
5
5
|
|
|
6
6
|
export function installMcpTelemetryProxies({ codexHome, marketplaceRoot, targets = DEFAULT_TARGETS } = {}) {
|
|
7
7
|
const configPath = path.join(codexHome, "config.toml");
|
|
@@ -23,14 +23,29 @@ export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = DEFAULT_
|
|
|
23
23
|
const skipped = [];
|
|
24
24
|
|
|
25
25
|
for (const section of sections.reverse()) {
|
|
26
|
+
const body = lines.slice(section.start + 1, section.end);
|
|
27
|
+
const command = findStringValue(body, "command");
|
|
28
|
+
const args = findArrayValue(body, "args") || [];
|
|
29
|
+
|
|
30
|
+
if (command === "node" && args[0] === proxyPath && !targets.has(section.name)) {
|
|
31
|
+
const original = unwrapProxyArgs(args);
|
|
32
|
+
if (original) {
|
|
33
|
+
const nextBody = replaceOrInsertServerField(
|
|
34
|
+
replaceOrInsertServerField(body, "command", tomlString(original.command)),
|
|
35
|
+
"args",
|
|
36
|
+
tomlArray(original.args)
|
|
37
|
+
);
|
|
38
|
+
lines.splice(section.start + 1, section.end - section.start - 1, ...nextBody);
|
|
39
|
+
skipped.push({ name: section.name, reason: "unwrapped-non-target" });
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
26
44
|
if (!targets.has(section.name)) {
|
|
27
45
|
skipped.push({ name: section.name, reason: "not-targeted" });
|
|
28
46
|
continue;
|
|
29
47
|
}
|
|
30
48
|
|
|
31
|
-
const body = lines.slice(section.start + 1, section.end);
|
|
32
|
-
const command = findStringValue(body, "command");
|
|
33
|
-
const args = findArrayValue(body, "args") || [];
|
|
34
49
|
if (!command) {
|
|
35
50
|
skipped.push({ name: section.name, reason: "missing-command" });
|
|
36
51
|
continue;
|
|
@@ -39,6 +54,10 @@ export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = DEFAULT_
|
|
|
39
54
|
skipped.push({ name: section.name, reason: "already-wrapped" });
|
|
40
55
|
continue;
|
|
41
56
|
}
|
|
57
|
+
if (command === "rtk") {
|
|
58
|
+
skipped.push({ name: section.name, reason: "rtk-managed" });
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
42
61
|
|
|
43
62
|
const nextBody = replaceOrInsertServerField(
|
|
44
63
|
replaceOrInsertServerField(body, "command", tomlString("node")),
|
|
@@ -52,6 +71,15 @@ export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = DEFAULT_
|
|
|
52
71
|
return { content: lines.join("\n"), wrapped: wrapped.reverse(), skipped: skipped.reverse() };
|
|
53
72
|
}
|
|
54
73
|
|
|
74
|
+
function unwrapProxyArgs(args) {
|
|
75
|
+
const separator = args.indexOf("--");
|
|
76
|
+
if (separator < 0 || separator >= args.length - 1) return null;
|
|
77
|
+
return {
|
|
78
|
+
command: args[separator + 1],
|
|
79
|
+
args: args.slice(separator + 2)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
55
83
|
function findMcpServerSections(lines) {
|
|
56
84
|
const sections = [];
|
|
57
85
|
for (let index = 0; index < lines.length; index += 1) {
|