sigmap 8.34.0 → 8.35.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/CHANGELOG.md +13 -0
- package/README.md +9 -9
- package/gen-context.js +217 -69
- package/llms-full.txt +6 -6
- package/llms.txt +6 -6
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/src/extractors/cpp.js +8 -3
- package/src/extractors/csharp.js +8 -3
- package/src/extractors/css.js +1 -1
- package/src/extractors/dart.js +8 -3
- package/src/extractors/dockerfile.js +1 -1
- package/src/extractors/gdscript.js +2 -2
- package/src/extractors/go.js +13 -5
- package/src/extractors/html.js +1 -1
- package/src/extractors/javascript.js +7 -3
- package/src/extractors/kotlin.js +8 -3
- package/src/extractors/lua.js +1 -1
- package/src/extractors/markdown.js +1 -1
- package/src/extractors/php.js +8 -3
- package/src/extractors/properties.js +1 -1
- package/src/extractors/python.js +5 -2
- package/src/extractors/python_dataclass.js +3 -1
- package/src/extractors/r.js +1 -1
- package/src/extractors/ruby.js +1 -1
- package/src/extractors/rust.js +13 -5
- package/src/extractors/scala.js +8 -3
- package/src/extractors/shell.js +1 -1
- package/src/extractors/svelte.js +1 -1
- package/src/extractors/swift.js +8 -3
- package/src/extractors/toml.js +1 -1
- package/src/extractors/typescript.js +8 -4
- package/src/extractors/typescript_react.js +1 -1
- package/src/extractors/vue_sfc.js +3 -1
- package/src/extractors/xml.js +3 -1
- package/src/extractors/yaml.js +1 -1
- package/src/mcp/server.js +46 -4
- package/src/retrieval/ranker.js +14 -5
package/src/extractors/xml.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { capWithNotice } = require('../util/truncate');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Lightweight XML config extractor.
|
|
5
7
|
* Captures root tags, key config tags, and id/name/class attributes.
|
|
@@ -40,7 +42,7 @@ function extract(src) {
|
|
|
40
42
|
if (cls) sigs.push(`${tag} -> ${cls[1]}`);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
return Array.from(new Set(sigs))
|
|
45
|
+
return capWithNotice(Array.from(new Set(sigs)), 200, 'signatures');
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
module.exports = { extract };
|
package/src/extractors/yaml.js
CHANGED
|
@@ -4,7 +4,7 @@ const { capWithNotice } = require('../util/truncate');
|
|
|
4
4
|
|
|
5
5
|
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6
6
|
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
7
|
-
const PER_FILE_LIMIT =
|
|
7
|
+
const PER_FILE_LIMIT = 200;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Extract signatures from YAML configuration files.
|
package/src/mcp/server.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* One JSON object per line on both stdin and stdout.
|
|
8
8
|
*
|
|
9
9
|
* Supported methods:
|
|
10
|
-
* initialize → serverInfo + capabilities
|
|
11
|
-
* tools/list →
|
|
10
|
+
* initialize → serverInfo + capabilities + negotiated protocolVersion
|
|
11
|
+
* tools/list → 21 tool definitions
|
|
12
12
|
* tools/call → dispatch to handler, return result
|
|
13
13
|
*/
|
|
14
14
|
|
|
@@ -18,10 +18,22 @@ const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, exp
|
|
|
18
18
|
|
|
19
19
|
const SERVER_INFO = {
|
|
20
20
|
name: 'sigmap',
|
|
21
|
-
version: '8.
|
|
21
|
+
version: '8.35.0',
|
|
22
22
|
description: 'SigMap MCP server — code signatures on demand',
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
// Protocol revisions this server actually speaks. The tools-only surface —
|
|
26
|
+
// initialize / tools/list / tools/call plus the initialized/cancelled
|
|
27
|
+
// notifications — is identical across these revisions, and the
|
|
28
|
+
// @hasmcp/mcp-spec-test suite passes every applicable 2025-11-25 case against
|
|
29
|
+
// it. 2026-07-28 is deliberately absent: that revision requires
|
|
30
|
+
// server/discover, which is not implemented. Newest first: a client offering
|
|
31
|
+
// a version outside this list is downgraded to [0], never echoed back —
|
|
32
|
+
// echoing an unspeakable version is itself a spec violation (#544), and it
|
|
33
|
+
// made the conformance suite believe 2026-07-28 was supported, producing six
|
|
34
|
+
// phantom server/discover failures on a revision never really offered (#545).
|
|
35
|
+
const SUPPORTED_PROTOCOL_VERSIONS = ['2025-11-25', '2025-06-18', '2025-03-26', '2024-11-05'];
|
|
36
|
+
|
|
25
37
|
// ---------------------------------------------------------------------------
|
|
26
38
|
// JSON-RPC helpers
|
|
27
39
|
// ---------------------------------------------------------------------------
|
|
@@ -46,9 +58,32 @@ function dispatch(msg, cwd) {
|
|
|
46
58
|
return;
|
|
47
59
|
}
|
|
48
60
|
|
|
61
|
+
// server/discover (spec 2026-07-28) — session-less discovery, answerable
|
|
62
|
+
// before any handshake, so a client can learn the honest version list
|
|
63
|
+
// instead of offering versions and hoping. The response is a
|
|
64
|
+
// CacheableResult: deterministic, so the TTL promise of stability holds.
|
|
65
|
+
// Note supportedVersions does NOT include 2026-07-28 — answering discover
|
|
66
|
+
// is forward-compatible plumbing, not a claim to serve that revision's
|
|
67
|
+
// whole surface (per-result envelopes, inline _meta negotiation).
|
|
68
|
+
if (method === 'server/discover') {
|
|
69
|
+
respond(id, {
|
|
70
|
+
resultType: 'complete',
|
|
71
|
+
cacheScope: 'public',
|
|
72
|
+
ttlMs: 3600000,
|
|
73
|
+
supportedVersions: SUPPORTED_PROTOCOL_VERSIONS,
|
|
74
|
+
capabilities: { tools: {} },
|
|
75
|
+
serverInfo: SERVER_INFO,
|
|
76
|
+
instructions: 'SigMap serves code signatures for the working directory. Call query_context or search_signatures to rank and fetch signature blocks instead of reading whole files.',
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
49
81
|
if (method === 'initialize') {
|
|
82
|
+
const offered = params && params.protocolVersion;
|
|
50
83
|
respond(id, {
|
|
51
|
-
protocolVersion: (
|
|
84
|
+
protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.includes(offered)
|
|
85
|
+
? offered
|
|
86
|
+
: SUPPORTED_PROTOCOL_VERSIONS[0],
|
|
52
87
|
serverInfo: SERVER_INFO,
|
|
53
88
|
capabilities: { tools: {} },
|
|
54
89
|
});
|
|
@@ -56,6 +91,13 @@ function dispatch(msg, cwd) {
|
|
|
56
91
|
}
|
|
57
92
|
|
|
58
93
|
if (method === 'tools/list') {
|
|
94
|
+
// No pagination: the full list fits one page, so any cursor a client
|
|
95
|
+
// presents is one this server never issued — reject it (-32602, per the
|
|
96
|
+
// spec's SHOULD) rather than silently restarting from page one.
|
|
97
|
+
if (params && params.cursor !== undefined) {
|
|
98
|
+
respondError(id, -32602, `Invalid cursor: ${String(params.cursor)}`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
59
101
|
respond(id, { tools: TOOLS });
|
|
60
102
|
return;
|
|
61
103
|
}
|
package/src/retrieval/ranker.js
CHANGED
|
@@ -376,9 +376,15 @@ function rank(query, sigIndex, opts) {
|
|
|
376
376
|
const hop1Files = new Set(); // normalised keys that received a hop1 boost
|
|
377
377
|
const hop1Seeds = []; // original (un-normalised) paths, for hop-2 lookup
|
|
378
378
|
|
|
379
|
-
// Hop 1: direct neighbors of scored files
|
|
380
|
-
|
|
381
|
-
|
|
379
|
+
// Hop 1: direct neighbors of scored files. Seeds snapshotted BEFORE the
|
|
380
|
+
// loop (as the call-graph block below already does) so boosts never
|
|
381
|
+
// cascade: a file whose only score is a hop-1 boost must not become a seed
|
|
382
|
+
// itself mid-loop, or the effective seed set — and every boost total —
|
|
383
|
+
// depends on index insertion order, which git history changes via the
|
|
384
|
+
// recent-commits hoist. That made gate scores differ between a shallow CI
|
|
385
|
+
// checkout and a developer clone of the same commit (#596).
|
|
386
|
+
const hop1SeedEntries = scored.filter((e) => e.score > 0);
|
|
387
|
+
for (const entry of hop1SeedEntries) {
|
|
382
388
|
const neighbors = _graphGet(graph.forward, path.resolve(cwd, entry.file)) || [];
|
|
383
389
|
for (const neighborAbs of neighbors) {
|
|
384
390
|
const nk = path.normalize(neighborAbs);
|
|
@@ -393,7 +399,10 @@ function rank(query, sigIndex, opts) {
|
|
|
393
399
|
}
|
|
394
400
|
}
|
|
395
401
|
|
|
396
|
-
// Hop 2: neighbors of hop1 files (only if they didn't get a direct score)
|
|
402
|
+
// Hop 2: neighbors of hop1 files (only if they didn't get a direct score).
|
|
403
|
+
// Eligibility frozen after hop-1 for the same reason: a file whose first
|
|
404
|
+
// score is a hop-2 boost must not become hop-2-eligible mid-loop (#596).
|
|
405
|
+
const hop2Eligible = scored.map((e) => e.score > 0);
|
|
397
406
|
for (const hop1Key of hop1Seeds) {
|
|
398
407
|
if (_graphGet(keyToIdx, hop1Key) === undefined) continue; // skip files not in index
|
|
399
408
|
const neighbors = _graphGet(graph.forward, hop1Key) || [];
|
|
@@ -402,7 +411,7 @@ function rank(query, sigIndex, opts) {
|
|
|
402
411
|
if (_isHub(nk) || hubs.has(nk) || hubs.has(nk.toLowerCase())) continue;
|
|
403
412
|
if (hop1Files.has(nk)) continue; // skip already hop1-boosted
|
|
404
413
|
const idx = _graphGet(keyToIdx, nk);
|
|
405
|
-
if (idx !== undefined &&
|
|
414
|
+
if (idx !== undefined && hop2Eligible[idx]) {
|
|
406
415
|
// Only boost files that have some baseline score (not noise)
|
|
407
416
|
scored[idx].score += GRAPH_BOOST_AMOUNTS.hop2;
|
|
408
417
|
scored[idx].signals.graphBoost = (scored[idx].signals.graphBoost || 0) + GRAPH_BOOST_AMOUNTS.hop2;
|