@opensip-cli/mcp 0.1.15
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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +33 -0
- package/dist/__tests__/command-transport.test.d.ts +13 -0
- package/dist/__tests__/command-transport.test.d.ts.map +1 -0
- package/dist/__tests__/command-transport.test.js +63 -0
- package/dist/__tests__/command-transport.test.js.map +1 -0
- package/dist/__tests__/e2e-stdio.test.d.ts +16 -0
- package/dist/__tests__/e2e-stdio.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-stdio.test.js +271 -0
- package/dist/__tests__/e2e-stdio.test.js.map +1 -0
- package/dist/__tests__/freshness.test.d.ts +9 -0
- package/dist/__tests__/freshness.test.d.ts.map +1 -0
- package/dist/__tests__/freshness.test.js +78 -0
- package/dist/__tests__/freshness.test.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +20 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +178 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/__tests__/register-mcp-graph-adapters.test.d.ts +12 -0
- package/dist/__tests__/register-mcp-graph-adapters.test.d.ts.map +1 -0
- package/dist/__tests__/register-mcp-graph-adapters.test.js +47 -0
- package/dist/__tests__/register-mcp-graph-adapters.test.js.map +1 -0
- package/dist/__tests__/session-results-read-port.test.d.ts +13 -0
- package/dist/__tests__/session-results-read-port.test.d.ts.map +1 -0
- package/dist/__tests__/session-results-read-port.test.js +151 -0
- package/dist/__tests__/session-results-read-port.test.js.map +1 -0
- package/dist/__tests__/sqlite-graph-read-port.test.d.ts +12 -0
- package/dist/__tests__/sqlite-graph-read-port.test.d.ts.map +1 -0
- package/dist/__tests__/sqlite-graph-read-port.test.js +322 -0
- package/dist/__tests__/sqlite-graph-read-port.test.js.map +1 -0
- package/dist/__tests__/tool-descriptor.test.d.ts +9 -0
- package/dist/__tests__/tool-descriptor.test.d.ts.map +1 -0
- package/dist/__tests__/tool-descriptor.test.js +55 -0
- package/dist/__tests__/tool-descriptor.test.js.map +1 -0
- package/dist/catalog-generation.d.ts +22 -0
- package/dist/catalog-generation.d.ts.map +1 -0
- package/dist/catalog-generation.js +21 -0
- package/dist/catalog-generation.js.map +1 -0
- package/dist/command.d.ts +3 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +111 -0
- package/dist/command.js.map +1 -0
- package/dist/freshness.d.ts +50 -0
- package/dist/freshness.d.ts.map +1 -0
- package/dist/freshness.js +96 -0
- package/dist/freshness.js.map +1 -0
- package/dist/graph-read-port.d.ts +111 -0
- package/dist/graph-read-port.d.ts.map +1 -0
- package/dist/graph-read-port.js +16 -0
- package/dist/graph-read-port.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-error.d.ts +15 -0
- package/dist/mcp-error.d.ts.map +1 -0
- package/dist/mcp-error.js +5 -0
- package/dist/mcp-error.js.map +1 -0
- package/dist/register-mcp-graph-adapters.d.ts +3 -0
- package/dist/register-mcp-graph-adapters.d.ts.map +1 -0
- package/dist/register-mcp-graph-adapters.js +21 -0
- package/dist/register-mcp-graph-adapters.js.map +1 -0
- package/dist/result-dto.d.ts +63 -0
- package/dist/result-dto.d.ts.map +1 -0
- package/dist/result-dto.js +11 -0
- package/dist/result-dto.js.map +1 -0
- package/dist/results-read-port.d.ts +43 -0
- package/dist/results-read-port.d.ts.map +1 -0
- package/dist/results-read-port.js +13 -0
- package/dist/results-read-port.js.map +1 -0
- package/dist/server.d.ts +84 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +153 -0
- package/dist/server.js.map +1 -0
- package/dist/session-results-read-port.d.ts +42 -0
- package/dist/session-results-read-port.d.ts.map +1 -0
- package/dist/session-results-read-port.js +147 -0
- package/dist/session-results-read-port.js.map +1 -0
- package/dist/sqlite-graph-read-port.d.ts +88 -0
- package/dist/sqlite-graph-read-port.d.ts.map +1 -0
- package/dist/sqlite-graph-read-port.js +304 -0
- package/dist/sqlite-graph-read-port.js.map +1 -0
- package/dist/symbol-dto.d.ts +58 -0
- package/dist/symbol-dto.d.ts.map +1 -0
- package/dist/symbol-dto.js +12 -0
- package/dist/symbol-dto.js.map +1 -0
- package/dist/tool.d.ts +6 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +33 -0
- package/dist/tool.js.map +1 -0
- package/dist/tools/__tests__/graph-handlers.test.d.ts +11 -0
- package/dist/tools/__tests__/graph-handlers.test.d.ts.map +1 -0
- package/dist/tools/__tests__/graph-handlers.test.js +415 -0
- package/dist/tools/__tests__/graph-handlers.test.js.map +1 -0
- package/dist/tools/__tests__/graph-walk.test.d.ts +9 -0
- package/dist/tools/__tests__/graph-walk.test.d.ts.map +1 -0
- package/dist/tools/__tests__/graph-walk.test.js +72 -0
- package/dist/tools/__tests__/graph-walk.test.js.map +1 -0
- package/dist/tools/__tests__/refresh-graph.test.d.ts +11 -0
- package/dist/tools/__tests__/refresh-graph.test.d.ts.map +1 -0
- package/dist/tools/__tests__/refresh-graph.test.js +100 -0
- package/dist/tools/__tests__/refresh-graph.test.js.map +1 -0
- package/dist/tools/__tests__/result-handlers.test.d.ts +9 -0
- package/dist/tools/__tests__/result-handlers.test.d.ts.map +1 -0
- package/dist/tools/__tests__/result-handlers.test.js +194 -0
- package/dist/tools/__tests__/result-handlers.test.js.map +1 -0
- package/dist/tools/__tests__/schemas.test.d.ts +10 -0
- package/dist/tools/__tests__/schemas.test.d.ts.map +1 -0
- package/dist/tools/__tests__/schemas.test.js +73 -0
- package/dist/tools/__tests__/schemas.test.js.map +1 -0
- package/dist/tools/blast-radius.d.ts +12 -0
- package/dist/tools/blast-radius.d.ts.map +1 -0
- package/dist/tools/blast-radius.js +33 -0
- package/dist/tools/blast-radius.js.map +1 -0
- package/dist/tools/call-walk-tool.d.ts +17 -0
- package/dist/tools/call-walk-tool.d.ts.map +1 -0
- package/dist/tools/call-walk-tool.js +46 -0
- package/dist/tools/call-walk-tool.js.map +1 -0
- package/dist/tools/callees-of.d.ts +12 -0
- package/dist/tools/callees-of.d.ts.map +1 -0
- package/dist/tools/callees-of.js +20 -0
- package/dist/tools/callees-of.js.map +1 -0
- package/dist/tools/find-dead-code.d.ts +11 -0
- package/dist/tools/find-dead-code.d.ts.map +1 -0
- package/dist/tools/find-dead-code.js +26 -0
- package/dist/tools/find-dead-code.js.map +1 -0
- package/dist/tools/get-agent-catalog.d.ts +12 -0
- package/dist/tools/get-agent-catalog.d.ts.map +1 -0
- package/dist/tools/get-agent-catalog.js +23 -0
- package/dist/tools/get-agent-catalog.js.map +1 -0
- package/dist/tools/get-architecture.d.ts +11 -0
- package/dist/tools/get-architecture.d.ts.map +1 -0
- package/dist/tools/get-architecture.js +26 -0
- package/dist/tools/get-architecture.js.map +1 -0
- package/dist/tools/get-latest-findings.d.ts +13 -0
- package/dist/tools/get-latest-findings.d.ts.map +1 -0
- package/dist/tools/get-latest-findings.js +38 -0
- package/dist/tools/get-latest-findings.js.map +1 -0
- package/dist/tools/get-symbol.d.ts +18 -0
- package/dist/tools/get-symbol.d.ts.map +1 -0
- package/dist/tools/get-symbol.js +44 -0
- package/dist/tools/get-symbol.js.map +1 -0
- package/dist/tools/graph-walk.d.ts +50 -0
- package/dist/tools/graph-walk.d.ts.map +1 -0
- package/dist/tools/graph-walk.js +89 -0
- package/dist/tools/graph-walk.js.map +1 -0
- package/dist/tools/list-runs.d.ts +11 -0
- package/dist/tools/list-runs.d.ts.map +1 -0
- package/dist/tools/list-runs.js +37 -0
- package/dist/tools/list-runs.js.map +1 -0
- package/dist/tools/refresh-graph.d.ts +22 -0
- package/dist/tools/refresh-graph.d.ts.map +1 -0
- package/dist/tools/refresh-graph.js +75 -0
- package/dist/tools/refresh-graph.js.map +1 -0
- package/dist/tools/register.d.ts +13 -0
- package/dist/tools/register.d.ts.map +1 -0
- package/dist/tools/register.js +40 -0
- package/dist/tools/register.js.map +1 -0
- package/dist/tools/schemas.d.ts +54 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +59 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools/search-symbols.d.ts +12 -0
- package/dist/tools/search-symbols.d.ts.map +1 -0
- package/dist/tools/search-symbols.js +37 -0
- package/dist/tools/search-symbols.js.map +1 -0
- package/dist/tools/show-run.d.ts +12 -0
- package/dist/tools/show-run.d.ts.map +1 -0
- package/dist/tools/show-run.js +40 -0
- package/dist/tools/show-run.js.map +1 -0
- package/dist/tools/tool-result.d.ts +29 -0
- package/dist/tools/tool-result.d.ts.map +1 -0
- package/dist/tools/tool-result.js +39 -0
- package/dist/tools/tool-result.js.map +1 -0
- package/dist/tools/trace-path.d.ts +12 -0
- package/dist/tools/trace-path.d.ts.map +1 -0
- package/dist/tools/trace-path.js +57 -0
- package/dist/tools/trace-path.js.map +1 -0
- package/dist/tools/types.d.ts +20 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +11 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/who-calls.d.ts +12 -0
- package/dist/tools/who-calls.d.ts.map +1 -0
- package/dist/tools/who-calls.js +21 -0
- package/dist/tools/who-calls.js.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite-backed {@link GraphReadPort} (ADR-0084).
|
|
3
|
+
*
|
|
4
|
+
* Reads the persisted catalog through the graph engine's `CatalogRepo`
|
|
5
|
+
* (internal surface) and derives adjacency via `buildIndexes` — it NEVER invents
|
|
6
|
+
* a parallel catalog table or raw-queries `DataStore.db`. Freshness reuses
|
|
7
|
+
* `classifyCatalog`; dead code reuses `orphanSubtreeRule`; blast reuses the
|
|
8
|
+
* single canonical `buildFeatures(['blast'])` scoring site (no ad-hoc BFS). The
|
|
9
|
+
* generic bounded adjacency walks for callers/callees/trace are MCP-local.
|
|
10
|
+
*
|
|
11
|
+
* Constructed from an injected `DataStore` (+ optional freshness-context and
|
|
12
|
+
* rebuild providers, wired in Phases 3/4) — it NEVER reads `currentScope()`.
|
|
13
|
+
* Reads return `Result<McpToolResult<T>, McpReadError>`; a missing catalog is
|
|
14
|
+
* NOT an error — it surfaces as `freshness.fresh === false` with empty data and
|
|
15
|
+
* no auto-build. `throw` is reserved for the SQLite/Drizzle boundary (a failing
|
|
16
|
+
* `CatalogRepo.loadFullCatalog`) and the `runGraph` rebuild.
|
|
17
|
+
*/
|
|
18
|
+
import { err, ok } from '@opensip-cli/core';
|
|
19
|
+
import { buildFeatures, CatalogRepo, orphanSubtreeRule } from '@opensip-cli/graph/internal';
|
|
20
|
+
import { createGeneration } from './catalog-generation.js';
|
|
21
|
+
import { classifyFreshness, missingFreshness, unverifiedFreshness } from './freshness.js';
|
|
22
|
+
import { readError } from './mcp-error.js';
|
|
23
|
+
/** Default search-result cap. */
|
|
24
|
+
const DEFAULT_SEARCH_LIMIT = 50;
|
|
25
|
+
/** Shared empty adjacency for the no-catalog case (avoids per-call allocation). */
|
|
26
|
+
const EMPTY_EDGES = new Map();
|
|
27
|
+
/** Default architecture package-row cap. */
|
|
28
|
+
const DEFAULT_ARCH_LIMIT = 25;
|
|
29
|
+
export class SqliteGraphReadPort {
|
|
30
|
+
deps;
|
|
31
|
+
store;
|
|
32
|
+
config;
|
|
33
|
+
generation;
|
|
34
|
+
loaded = false;
|
|
35
|
+
// Per-generation memoized derivations (reset on (re)load / refresh). Freshness
|
|
36
|
+
// is deliberately NOT memoized: a long-lived server must re-verify the working
|
|
37
|
+
// tree on each read so a mid-session file mutation flips `fresh` to false.
|
|
38
|
+
blastCache;
|
|
39
|
+
/** In-flight rebuild — serializes concurrent `refresh()` to a single build. */
|
|
40
|
+
inFlightRefresh;
|
|
41
|
+
constructor(deps) {
|
|
42
|
+
this.deps = deps;
|
|
43
|
+
this.store = deps.store;
|
|
44
|
+
this.config = deps.config ?? {};
|
|
45
|
+
}
|
|
46
|
+
// ── generation lifecycle ──────────────────────────────────────────
|
|
47
|
+
/** Lazily load + pin the current generation from the persisted catalog. */
|
|
48
|
+
current() {
|
|
49
|
+
if (!this.loaded) {
|
|
50
|
+
// CatalogRepo throws only on a genuine SQLite/Drizzle failure (sanctioned
|
|
51
|
+
// infra boundary); a missing catalog returns null → no generation.
|
|
52
|
+
const catalog = new CatalogRepo(this.store).loadFullCatalog();
|
|
53
|
+
this.generation = catalog === null ? undefined : createGeneration(catalog);
|
|
54
|
+
this.loaded = true;
|
|
55
|
+
this.invalidateDerived();
|
|
56
|
+
}
|
|
57
|
+
return this.generation;
|
|
58
|
+
}
|
|
59
|
+
invalidateDerived() {
|
|
60
|
+
this.blastCache = undefined;
|
|
61
|
+
}
|
|
62
|
+
freshness() {
|
|
63
|
+
const gen = this.current();
|
|
64
|
+
return gen === undefined ? missingFreshness() : this.classify(gen);
|
|
65
|
+
}
|
|
66
|
+
classify(gen) {
|
|
67
|
+
const ctx = this.deps.freshnessContext?.(gen.catalog);
|
|
68
|
+
if (ctx === undefined)
|
|
69
|
+
return unverifiedFreshness(gen.builtAt);
|
|
70
|
+
return classifyFreshness(gen.catalog, ctx);
|
|
71
|
+
}
|
|
72
|
+
/** Wrap data in the shared `{ data, freshness, truncated? }` envelope. */
|
|
73
|
+
wrap(data, truncated) {
|
|
74
|
+
return {
|
|
75
|
+
data,
|
|
76
|
+
freshness: this.freshness(),
|
|
77
|
+
...(truncated ? { truncated: true } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** The empty (no-data) envelope for an absent catalog / unresolved symbol. */
|
|
81
|
+
empty() {
|
|
82
|
+
return { data: undefined, freshness: this.freshness() };
|
|
83
|
+
}
|
|
84
|
+
// ── reads ─────────────────────────────────────────────────────────
|
|
85
|
+
getGeneration() {
|
|
86
|
+
const gen = this.current();
|
|
87
|
+
return ok(this.wrap(gen === undefined ? undefined : { builtAt: gen.builtAt }));
|
|
88
|
+
}
|
|
89
|
+
resolveSymbolId(symbolId) {
|
|
90
|
+
const gen = this.current();
|
|
91
|
+
if (gen === undefined)
|
|
92
|
+
return ok(this.empty());
|
|
93
|
+
const occ = gen.indexes.byOccId.get(symbolId);
|
|
94
|
+
return ok(this.wrap(occ === undefined ? undefined : toSymbolRef(occ)));
|
|
95
|
+
}
|
|
96
|
+
searchSymbols(query, opts) {
|
|
97
|
+
const gen = this.current();
|
|
98
|
+
if (gen === undefined)
|
|
99
|
+
return ok(this.wrap([]));
|
|
100
|
+
const limit = clampLimit(opts?.limit, DEFAULT_SEARCH_LIMIT);
|
|
101
|
+
const needle = query.toLowerCase();
|
|
102
|
+
const matches = [];
|
|
103
|
+
let truncated = false;
|
|
104
|
+
for (const occ of gen.indexes.byOccId.values()) {
|
|
105
|
+
if (occ.kind === 'module-init')
|
|
106
|
+
continue;
|
|
107
|
+
if (!occ.simpleName.toLowerCase().includes(needle))
|
|
108
|
+
continue;
|
|
109
|
+
if (matches.length >= limit) {
|
|
110
|
+
truncated = true;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
matches.push(toSymbolRef(occ));
|
|
114
|
+
}
|
|
115
|
+
return ok(this.wrap(matches, truncated));
|
|
116
|
+
}
|
|
117
|
+
findBySpan(file, line) {
|
|
118
|
+
const gen = this.current();
|
|
119
|
+
if (gen === undefined)
|
|
120
|
+
return ok(this.wrap([]));
|
|
121
|
+
const out = [];
|
|
122
|
+
for (const occ of gen.indexes.byOccId.values()) {
|
|
123
|
+
if (occ.filePath === file && occ.line <= line && line <= occ.endLine) {
|
|
124
|
+
out.push(toSymbolRef(occ));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return ok(this.wrap(out));
|
|
128
|
+
}
|
|
129
|
+
callerGraph() {
|
|
130
|
+
return ok(this.wrap(this.adjacency((gen) => gen.indexes.callers)));
|
|
131
|
+
}
|
|
132
|
+
calleeGraph() {
|
|
133
|
+
return ok(this.wrap(this.adjacency((gen) => gen.indexes.callees)));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Project one direction's body-hash adjacency into a walkable
|
|
137
|
+
* {@link AdjacencySnapshot}. The map IS the engine's `Indexes.callers`/
|
|
138
|
+
* `callees` (no copy); the resolver closes over `byBodyHash`. The bounded
|
|
139
|
+
* walk itself lives in MCP's `boundedBfs` (rule of three) — the port never
|
|
140
|
+
* re-implements a BFS.
|
|
141
|
+
*/
|
|
142
|
+
adjacency(pick) {
|
|
143
|
+
const gen = this.current();
|
|
144
|
+
const edges = gen === undefined ? EMPTY_EDGES : pick(gen);
|
|
145
|
+
const byBodyHash = gen?.indexes.byBodyHash;
|
|
146
|
+
return {
|
|
147
|
+
edges,
|
|
148
|
+
resolve: (bodyHash) => {
|
|
149
|
+
const occ = byBodyHash?.get(bodyHash);
|
|
150
|
+
return occ === undefined ? undefined : toSymbolRef(occ);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
blast(symbolId) {
|
|
155
|
+
const gen = this.current();
|
|
156
|
+
if (gen === undefined)
|
|
157
|
+
return ok(this.empty());
|
|
158
|
+
const occ = gen.indexes.byOccId.get(symbolId);
|
|
159
|
+
if (occ === undefined)
|
|
160
|
+
return ok(this.empty());
|
|
161
|
+
const score = this.blastScores(gen).get(occ.bodyHash);
|
|
162
|
+
if (score === undefined)
|
|
163
|
+
return ok(this.empty());
|
|
164
|
+
return ok(this.wrap({ symbol: toSymbolRef(occ), ...score }));
|
|
165
|
+
}
|
|
166
|
+
/** Memoized blast table — the canonical `buildFeatures(['blast'])` scoring. */
|
|
167
|
+
blastScores(gen) {
|
|
168
|
+
if (this.blastCache !== undefined)
|
|
169
|
+
return this.blastCache;
|
|
170
|
+
const columns = ['blast'];
|
|
171
|
+
const features = buildFeatures(gen.catalog, gen.indexes, this.config, columns);
|
|
172
|
+
const out = new Map();
|
|
173
|
+
for (const [hash, row] of features.function) {
|
|
174
|
+
if (row.blast !== undefined) {
|
|
175
|
+
out.set(hash, {
|
|
176
|
+
direct: row.blast.direct,
|
|
177
|
+
transitive: row.blast.transitive,
|
|
178
|
+
score: row.blast.score,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
this.blastCache = out;
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
deadCode(limit) {
|
|
186
|
+
const gen = this.current();
|
|
187
|
+
if (gen === undefined)
|
|
188
|
+
return ok(this.wrap([]));
|
|
189
|
+
const columns = ['reachableFromEntry'];
|
|
190
|
+
const features = buildFeatures(gen.catalog, gen.indexes, this.config, columns);
|
|
191
|
+
const signals = orphanSubtreeRule.evaluate(gen.catalog, gen.indexes, this.config, undefined, features);
|
|
192
|
+
const entries = [];
|
|
193
|
+
let truncated = false;
|
|
194
|
+
for (const signal of signals) {
|
|
195
|
+
if (limit !== undefined && entries.length >= limit) {
|
|
196
|
+
truncated = true;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
const dto = toDeadCodeDto(signal, gen.indexes);
|
|
200
|
+
if (dto !== undefined)
|
|
201
|
+
entries.push(dto);
|
|
202
|
+
}
|
|
203
|
+
return ok(this.wrap(entries, truncated));
|
|
204
|
+
}
|
|
205
|
+
architectureSummary(limit) {
|
|
206
|
+
const gen = this.current();
|
|
207
|
+
if (gen === undefined) {
|
|
208
|
+
return ok(this.wrap({ functionCount: 0, edgeCount: 0, languages: [], packages: [], hotspots: [] }));
|
|
209
|
+
}
|
|
210
|
+
const columns = ['packageCoupling'];
|
|
211
|
+
const features = buildFeatures(gen.catalog, gen.indexes, this.config, columns);
|
|
212
|
+
const cap = clampLimit(limit, DEFAULT_ARCH_LIMIT);
|
|
213
|
+
const rows = [];
|
|
214
|
+
for (const [name, row] of features.package) {
|
|
215
|
+
rows.push({ name, couplingOut: row.couplingOut, couplingIn: row.couplingIn });
|
|
216
|
+
}
|
|
217
|
+
rows.sort((a, b) => b.couplingOut + b.couplingIn - (a.couplingOut + a.couplingIn));
|
|
218
|
+
const packages = rows.slice(0, cap);
|
|
219
|
+
const hotspots = this.topHotspots(gen, cap);
|
|
220
|
+
return ok(this.wrap({
|
|
221
|
+
functionCount: gen.indexes.byBodyHash.size,
|
|
222
|
+
edgeCount: edgeCount(gen.indexes),
|
|
223
|
+
languages: [gen.catalog.language],
|
|
224
|
+
packages,
|
|
225
|
+
hotspots,
|
|
226
|
+
}, packages.length < rows.length));
|
|
227
|
+
}
|
|
228
|
+
/** The `cap` highest-blast symbols (graph's canonical scoring; reused, not reinvented). */
|
|
229
|
+
topHotspots(gen, cap) {
|
|
230
|
+
const scores = this.blastScores(gen);
|
|
231
|
+
const ranked = [];
|
|
232
|
+
for (const [hash, score] of scores) {
|
|
233
|
+
const occ = gen.indexes.byBodyHash.get(hash);
|
|
234
|
+
if (occ !== undefined)
|
|
235
|
+
ranked.push({ symbol: toSymbolRef(occ), ...score });
|
|
236
|
+
}
|
|
237
|
+
ranked.sort((a, b) => b.score - a.score);
|
|
238
|
+
return ranked.slice(0, cap);
|
|
239
|
+
}
|
|
240
|
+
async refresh() {
|
|
241
|
+
const rebuild = this.deps.rebuild;
|
|
242
|
+
if (rebuild === undefined) {
|
|
243
|
+
return err(readError('refresh-unavailable', 'graph refresh is not wired (the rebuild provider is supplied by the host command).'));
|
|
244
|
+
}
|
|
245
|
+
// Serialize concurrent refreshes to ONE rebuild: a second caller awaits the
|
|
246
|
+
// in-flight build rather than launching a duplicate. In-flight reads keep the
|
|
247
|
+
// prior generation until the swap completes (TOCTOU-safe; catalog-generation.ts).
|
|
248
|
+
this.inFlightRefresh ??= this.runRebuild(rebuild);
|
|
249
|
+
try {
|
|
250
|
+
return await this.inFlightRefresh;
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
this.inFlightRefresh = undefined;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/** One rebuild: runs the provider, then swaps the generation atomically on success. */
|
|
257
|
+
async runRebuild(rebuild) {
|
|
258
|
+
// The rebuild runs `runGraph` at a genuine infra boundary; its throw (child
|
|
259
|
+
// build failure) propagates to the caller (the tool logs the decision point).
|
|
260
|
+
const catalog = await rebuild();
|
|
261
|
+
this.generation = createGeneration(catalog);
|
|
262
|
+
this.loaded = true;
|
|
263
|
+
this.invalidateDerived();
|
|
264
|
+
return ok(this.wrap({ builtAt: this.generation.builtAt }));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// ── pure helpers ────────────────────────────────────────────────────
|
|
268
|
+
function toSymbolRef(occ) {
|
|
269
|
+
return {
|
|
270
|
+
symbolId: `${occ.filePath}:${String(occ.line)}:${String(occ.column)}`,
|
|
271
|
+
bodyHash: occ.bodyHash,
|
|
272
|
+
qualifiedName: occ.qualifiedName,
|
|
273
|
+
filePath: occ.filePath,
|
|
274
|
+
line: occ.line,
|
|
275
|
+
column: occ.column,
|
|
276
|
+
kind: occ.kind,
|
|
277
|
+
visibility: occ.visibility,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/** Map an `graph:orphan-subtree` signal to a {@link DeadCodeDto} (no FS reads). */
|
|
281
|
+
function toDeadCodeDto(signal, indexes) {
|
|
282
|
+
const code = signal.code;
|
|
283
|
+
if (code?.file === undefined || code.line === undefined || code.column === undefined) {
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|
|
286
|
+
const occ = indexes.byOccId.get(`${code.file}:${String(code.line)}:${String(code.column)}`);
|
|
287
|
+
if (occ === undefined)
|
|
288
|
+
return undefined;
|
|
289
|
+
return { symbol: toSymbolRef(occ), message: signal.message };
|
|
290
|
+
}
|
|
291
|
+
/** Total out-edge count across the callees adjacency. */
|
|
292
|
+
function edgeCount(indexes) {
|
|
293
|
+
let total = 0;
|
|
294
|
+
for (const targets of indexes.callees.values())
|
|
295
|
+
total += targets.length;
|
|
296
|
+
return total;
|
|
297
|
+
}
|
|
298
|
+
/** Clamp a caller-supplied limit to a positive integer, defaulting when absent. */
|
|
299
|
+
function clampLimit(limit, fallback) {
|
|
300
|
+
if (limit === undefined || !Number.isFinite(limit) || limit <= 0)
|
|
301
|
+
return fallback;
|
|
302
|
+
return Math.trunc(limit);
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=sqlite-graph-read-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-graph-read-port.js","sourceRoot":"","sources":["../src/sqlite-graph-read-port.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbol + freshness DTOs for the MCP read ports (ADR-0084).
|
|
3
|
+
*
|
|
4
|
+
* These are the *only* graph shapes that cross the {@link GraphReadPort}
|
|
5
|
+
* boundary — the SQLite impl never leaks `Catalog` / `Indexes` to handlers
|
|
6
|
+
* (SaaS parity: an alternate storage backend can substitute behind the same
|
|
7
|
+
* narrow port). DTOs carry symbol METADATA only (qualified name, path, span,
|
|
8
|
+
* kind, visibility, `bodyHash`) — never raw file bodies (`bodyHash` is a hash,
|
|
9
|
+
* not source).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* A single resolved symbol occurrence. `symbolId` is the stable identity
|
|
13
|
+
* downstream tools accept (never a bare name): `"${filePath}:${line}:${column}"`.
|
|
14
|
+
*/
|
|
15
|
+
export interface SymbolRef {
|
|
16
|
+
/** Stable identity: `"${filePath}:${line}:${column}"`. */
|
|
17
|
+
readonly symbolId: string;
|
|
18
|
+
/** sha256(normalized body) — the graph's content identifier. */
|
|
19
|
+
readonly bodyHash: string;
|
|
20
|
+
/** Human-display qualified name (e.g. `"fitness/engine/src/gate.saveBaseline"`). */
|
|
21
|
+
readonly qualifiedName: string;
|
|
22
|
+
/** Project-relative path. */
|
|
23
|
+
readonly filePath: string;
|
|
24
|
+
/** 1-based line where the declaration begins. */
|
|
25
|
+
readonly line: number;
|
|
26
|
+
/** 0-based column. */
|
|
27
|
+
readonly column: number;
|
|
28
|
+
/** Function kind (`'function'`, `'method'`, `'arrow'`, …). */
|
|
29
|
+
readonly kind: string;
|
|
30
|
+
/** Visibility (`'exported'`, `'private'`, …). */
|
|
31
|
+
readonly visibility: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Freshness verdict for the served catalog generation. Derived from the graph
|
|
35
|
+
* engine's `classifyCatalog` (never a filesystem mtime heuristic outside the
|
|
36
|
+
* engine). A missing catalog ⇒ `fresh: false` with empty data — never a silent
|
|
37
|
+
* auto-build.
|
|
38
|
+
*/
|
|
39
|
+
export interface Freshness {
|
|
40
|
+
/** `true` only when the persisted catalog matches the current file set. */
|
|
41
|
+
readonly fresh: boolean;
|
|
42
|
+
/** ISO timestamp the served generation was built at (absent when missing). */
|
|
43
|
+
readonly builtAt?: string;
|
|
44
|
+
/** Why the catalog is stale/missing (`'missing'`, `'language-changed'`, …). */
|
|
45
|
+
readonly reason?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The shared graph-read envelope: every {@link GraphReadPort} read carries
|
|
49
|
+
* `{ data, freshness }` so an agent always sees whether the answer came from a
|
|
50
|
+
* fresh, stale, or missing catalog. `truncated` is set when a bounded walk or
|
|
51
|
+
* search hit its node/result cap.
|
|
52
|
+
*/
|
|
53
|
+
export interface McpToolResult<T> {
|
|
54
|
+
readonly data: T;
|
|
55
|
+
readonly freshness: Freshness;
|
|
56
|
+
readonly truncated?: boolean;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=symbol-dto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbol-dto.d.ts","sourceRoot":"","sources":["../src/symbol-dto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,6BAA6B;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbol + freshness DTOs for the MCP read ports (ADR-0084).
|
|
3
|
+
*
|
|
4
|
+
* These are the *only* graph shapes that cross the {@link GraphReadPort}
|
|
5
|
+
* boundary — the SQLite impl never leaks `Catalog` / `Indexes` to handlers
|
|
6
|
+
* (SaaS parity: an alternate storage backend can substitute behind the same
|
|
7
|
+
* narrow port). DTOs carry symbol METADATA only (qualified name, path, span,
|
|
8
|
+
* kind, visibility, `bodyHash`) — never raw file bodies (`bodyHash` is a hash,
|
|
9
|
+
* not source).
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=symbol-dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbol-dto.js","sourceRoot":"","sources":["../src/symbol-dto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
package/dist/tool.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Tool, ToolIdentity } from '@opensip-cli/core';
|
|
2
|
+
export declare const MCP_IDENTITY: ToolIdentity;
|
|
3
|
+
/** Stable UUID identity (ADR-0048); mirrors `opensipTools.stableId` in package.json. */
|
|
4
|
+
export declare const MCP_STABLE_ID = "f313c020-5b48-4e17-a579-e303907b6392";
|
|
5
|
+
export declare const mcpTool: Tool;
|
|
6
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE5D,eAAO,MAAM,YAAY,EAAE,YAE1B,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,aAAa,yCAAyC,CAAC;AAEpE,eAAO,MAAM,OAAO,EAAE,IAWpB,CAAC"}
|
package/dist/tool.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@opensip-cli/mcp` Tool descriptor (ADR-0084).
|
|
3
|
+
*
|
|
4
|
+
* A bundled, first-party tool that serves the OpenSIP call graph + stored run
|
|
5
|
+
* results to MCP-capable coding agents over stdio. The single `mcp` command is
|
|
6
|
+
* declarative and mounted by the host (added in plan Phase 3); this descriptor
|
|
7
|
+
* also declares the `mcp-graph-adapter` capability domain so the bundled `graph-*`
|
|
8
|
+
* adapter packs load under `opensip mcp` and route through MCP's own registrar.
|
|
9
|
+
*
|
|
10
|
+
* This module does NOT import from `@opensip-cli/cli` — a tool engine (layer 4)
|
|
11
|
+
* never depends on the composition root.
|
|
12
|
+
*/
|
|
13
|
+
import { defineTool, readPackageVersion } from '@opensip-cli/core';
|
|
14
|
+
import { mcpCommandSpec } from './command.js';
|
|
15
|
+
import { registerMcpGraphAdapter } from './register-mcp-graph-adapters.js';
|
|
16
|
+
export const MCP_IDENTITY = {
|
|
17
|
+
name: 'mcp',
|
|
18
|
+
};
|
|
19
|
+
/** Stable UUID identity (ADR-0048); mirrors `opensipTools.stableId` in package.json. */
|
|
20
|
+
export const MCP_STABLE_ID = 'f313c020-5b48-4e17-a579-e303907b6392';
|
|
21
|
+
export const mcpTool = defineTool({
|
|
22
|
+
identity: MCP_IDENTITY,
|
|
23
|
+
metadata: {
|
|
24
|
+
id: MCP_STABLE_ID,
|
|
25
|
+
version: readPackageVersion(import.meta.url),
|
|
26
|
+
description: 'MCP server for the OpenSIP call graph and stored results',
|
|
27
|
+
},
|
|
28
|
+
commandSpecs: [mcpCommandSpec],
|
|
29
|
+
extensionPoints: {
|
|
30
|
+
capabilityRegistrars: { 'mcp-graph-adapter': registerMcpGraphAdapter },
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=tool.js.map
|
package/dist/tool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAI3E,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC,IAAI,EAAE,KAAK;CACZ,CAAC;AAEF,wFAAwF;AACxF,MAAM,CAAC,MAAM,aAAa,GAAG,sCAAsC,CAAC;AAEpE,MAAM,CAAC,MAAM,OAAO,GAAS,UAAU,CAAC;IACtC,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE;QACR,EAAE,EAAE,aAAa;QACjB,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAC5C,WAAW,EAAE,0DAA0D;KACxE;IACD,YAAY,EAAE,CAAC,cAAc,CAAC;IAC9B,eAAe,EAAE;QACf,oBAAoB,EAAE,EAAE,mBAAmB,EAAE,uBAAuB,EAAE;KACvE;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph tool handlers vs. a FAKE `GraphReadPort` (Task 6.1 steps 1–3).
|
|
3
|
+
*
|
|
4
|
+
* Each handler is registered through a capturing fake server, then invoked
|
|
5
|
+
* directly with already-valid args (Zod boundary validation is covered in
|
|
6
|
+
* schemas.test.ts). Asserts freshness stamping, `truncated` metadata, symbolId
|
|
7
|
+
* resolution errors (unknown id → structured error), `get_symbol` span/ambiguity
|
|
8
|
+
* behavior, and that no DTO carries a raw file body (metadata + bodyHash only).
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=graph-handlers.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-handlers.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/graph-handlers.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|