@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,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `refresh_graph` handler — observability (Task 6.1 step 5, §Observability).
|
|
3
|
+
*
|
|
4
|
+
* Asserts the rebuild-latency metric is recorded on the shared meter with
|
|
5
|
+
* BOUNDED-cardinality labels only (`{ command, op, outcome }` — never a path /
|
|
6
|
+
* symbol / id), via an in-memory meter provider; and that the handler logs its
|
|
7
|
+
* decision points (`mcp.refresh.run.ok` / `.error`) through the structured
|
|
8
|
+
* logger (the stderr sink during serve — never stdout).
|
|
9
|
+
*/
|
|
10
|
+
import { err, logger, ok } from '@opensip-cli/core';
|
|
11
|
+
import { metrics } from '@opentelemetry/api';
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
13
|
+
import { registerRefreshGraph } from '../refresh-graph.js';
|
|
14
|
+
const recorded = [];
|
|
15
|
+
/** Install a minimal in-memory meter provider that captures every histogram record. */
|
|
16
|
+
function installFakeMeter() {
|
|
17
|
+
recorded.length = 0;
|
|
18
|
+
metrics.disable();
|
|
19
|
+
const provider = {
|
|
20
|
+
getMeter: () => ({
|
|
21
|
+
createHistogram: (name) => ({
|
|
22
|
+
record: (value, attributes) => recorded.push({ name, value, attributes: attributes ?? {} }),
|
|
23
|
+
}),
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
metrics.setGlobalMeterProvider(provider);
|
|
27
|
+
}
|
|
28
|
+
function captureServer() {
|
|
29
|
+
const handlers = new Map();
|
|
30
|
+
const server = {
|
|
31
|
+
register: (name, _config, cb) => {
|
|
32
|
+
handlers.set(name, cb);
|
|
33
|
+
return undefined;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
return { handlers, server };
|
|
37
|
+
}
|
|
38
|
+
const FRESH = { fresh: true, builtAt: '2026-05-22T00:00:00.000Z' };
|
|
39
|
+
function gen() {
|
|
40
|
+
return { data: { builtAt: FRESH.builtAt ?? '' }, freshness: FRESH };
|
|
41
|
+
}
|
|
42
|
+
function fakeGraph(refresh) {
|
|
43
|
+
return {
|
|
44
|
+
refresh,
|
|
45
|
+
freshness: () => FRESH,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function deps(graph) {
|
|
49
|
+
return { graph, results: {}, validToolIds: new Set() };
|
|
50
|
+
}
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
installFakeMeter();
|
|
53
|
+
});
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
metrics.disable();
|
|
56
|
+
vi.restoreAllMocks();
|
|
57
|
+
});
|
|
58
|
+
describe('refresh_graph observability', () => {
|
|
59
|
+
it('records rebuild latency with bounded { command, op, outcome:ok } labels and logs the ok decision point', async () => {
|
|
60
|
+
const info = vi.spyOn(logger, 'info').mockImplementation(() => undefined);
|
|
61
|
+
const { server, handlers } = captureServer();
|
|
62
|
+
registerRefreshGraph(server, deps(fakeGraph(() => Promise.resolve(ok(gen())))));
|
|
63
|
+
const result = await handlers.get('refresh_graph')({});
|
|
64
|
+
const body = JSON.parse(result.content[0]?.type === 'text' ? result.content[0].text : '{}');
|
|
65
|
+
expect(body.builtAt).toBe(FRESH.builtAt);
|
|
66
|
+
expect(typeof body.durationMs).toBe('number');
|
|
67
|
+
expect(recorded).toHaveLength(1);
|
|
68
|
+
expect(recorded[0]?.name).toBe('opensip_cli.mcp.refresh.duration_ms');
|
|
69
|
+
// Bounded cardinality: EXACTLY these three label keys, no path/symbol/id.
|
|
70
|
+
expect(recorded[0]?.attributes).toEqual({ command: 'mcp', op: 'refresh', outcome: 'ok' });
|
|
71
|
+
expect(info).toHaveBeenCalledWith(expect.objectContaining({ evt: 'mcp.refresh.run.ok', module: 'mcp:refresh' }));
|
|
72
|
+
});
|
|
73
|
+
it('records outcome:error and logs the error decision point when refresh returns an err', async () => {
|
|
74
|
+
const error = vi.spyOn(logger, 'error').mockImplementation(() => undefined);
|
|
75
|
+
const { server, handlers } = captureServer();
|
|
76
|
+
registerRefreshGraph(server, deps(fakeGraph(() => Promise.resolve(err({ code: 'refresh-unavailable', message: 'not wired' })))));
|
|
77
|
+
const result = await handlers.get('refresh_graph')({});
|
|
78
|
+
expect(result.isError).toBe(true);
|
|
79
|
+
expect(recorded[0]?.attributes.outcome).toBe('error');
|
|
80
|
+
expect(error).toHaveBeenCalledWith(expect.objectContaining({ evt: 'mcp.refresh.run.error', code: 'refresh-unavailable' }));
|
|
81
|
+
});
|
|
82
|
+
it('records outcome:error and re-throws when the rebuild throws at the infra boundary', async () => {
|
|
83
|
+
const error = vi.spyOn(logger, 'error').mockImplementation(() => undefined);
|
|
84
|
+
const { server, handlers } = captureServer();
|
|
85
|
+
registerRefreshGraph(server, deps(fakeGraph(() => Promise.reject(new Error('child build blew up')))));
|
|
86
|
+
await expect(handlers.get('refresh_graph')({})).rejects.toThrow('child build blew up');
|
|
87
|
+
expect(recorded[0]?.attributes.outcome).toBe('error');
|
|
88
|
+
expect(error).toHaveBeenCalledWith(expect.objectContaining({ evt: 'mcp.refresh.run.error' }));
|
|
89
|
+
});
|
|
90
|
+
it('coerces a non-Error throwable in the error log (records outcome:error, re-throws)', async () => {
|
|
91
|
+
vi.spyOn(logger, 'error').mockImplementation(() => undefined);
|
|
92
|
+
const { server, handlers } = captureServer();
|
|
93
|
+
registerRefreshGraph(server,
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- deliberately a non-Error throwable to exercise the String(error) coercion branch
|
|
95
|
+
deps(fakeGraph(() => Promise.reject('bare string failure'))));
|
|
96
|
+
await expect(handlers.get('refresh_graph')({})).rejects.toBe('bare string failure');
|
|
97
|
+
expect(recorded[0]?.attributes.outcome).toBe('error');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=refresh-graph.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-graph.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/refresh-graph.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result/history tool handlers vs. a FAKE `ResultsReadPort` (Task 6.1 step 5).
|
|
3
|
+
*
|
|
4
|
+
* The result tools replay persisted sessions only — they NEVER re-run a tool.
|
|
5
|
+
* Asserts each handler forwards its args to the port, validates `tool` against
|
|
6
|
+
* the live registry (unknown → structured error), and surfaces the err arm.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=result-handlers.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-handlers.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/result-handlers.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result/history tool handlers vs. a FAKE `ResultsReadPort` (Task 6.1 step 5).
|
|
3
|
+
*
|
|
4
|
+
* The result tools replay persisted sessions only — they NEVER re-run a tool.
|
|
5
|
+
* Asserts each handler forwards its args to the port, validates `tool` against
|
|
6
|
+
* the live registry (unknown → structured error), and surfaces the err arm.
|
|
7
|
+
*/
|
|
8
|
+
import { err, ok } from '@opensip-cli/core';
|
|
9
|
+
import { describe, expect, it } from 'vitest';
|
|
10
|
+
import { registerGetAgentCatalog } from '../get-agent-catalog.js';
|
|
11
|
+
import { registerGetLatestFindings } from '../get-latest-findings.js';
|
|
12
|
+
import { registerListRuns } from '../list-runs.js';
|
|
13
|
+
import { registerShowRun } from '../show-run.js';
|
|
14
|
+
function captureServer() {
|
|
15
|
+
const handlers = new Map();
|
|
16
|
+
const server = {
|
|
17
|
+
register: (name, _config, cb) => {
|
|
18
|
+
handlers.set(name, cb);
|
|
19
|
+
return undefined;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
return { handlers, server };
|
|
23
|
+
}
|
|
24
|
+
function parseResult(result) {
|
|
25
|
+
const first = result.content[0];
|
|
26
|
+
const text = first?.type === 'text' ? first.text : '';
|
|
27
|
+
return { isError: result.isError === true, body: JSON.parse(text) };
|
|
28
|
+
}
|
|
29
|
+
function fakeResults(over) {
|
|
30
|
+
const base = {
|
|
31
|
+
agentCatalog: () => ok({ commands: [] }),
|
|
32
|
+
listRuns: () => ok([]),
|
|
33
|
+
showRun: () => Promise.resolve(err({ code: 'x', message: 'x' })),
|
|
34
|
+
latestFindings: () => Promise.resolve(err({ code: 'x', message: 'x' })),
|
|
35
|
+
};
|
|
36
|
+
return { ...base, ...over };
|
|
37
|
+
}
|
|
38
|
+
function deps(results, validToolIds = new Set(['fit', 'graph'])) {
|
|
39
|
+
return { graph: {}, results, validToolIds };
|
|
40
|
+
}
|
|
41
|
+
// ── get_latest_findings ──────────────────────────────────────────────
|
|
42
|
+
describe('get_latest_findings handler', () => {
|
|
43
|
+
it('forwards tool/severity/limit to the port and returns the replay', async () => {
|
|
44
|
+
let seen;
|
|
45
|
+
const replay = {
|
|
46
|
+
data: [{ ruleId: 'r', message: 'm', severity: 'high' }],
|
|
47
|
+
filtersApplied: ['errors-only', 'top:3'],
|
|
48
|
+
};
|
|
49
|
+
const { server, handlers } = captureServer();
|
|
50
|
+
registerGetLatestFindings(server, deps(fakeResults({
|
|
51
|
+
latestFindings: (opts) => {
|
|
52
|
+
seen = opts;
|
|
53
|
+
return Promise.resolve(ok(replay));
|
|
54
|
+
},
|
|
55
|
+
})));
|
|
56
|
+
const out = parseResult(await handlers.get('get_latest_findings')({
|
|
57
|
+
tool: 'fit',
|
|
58
|
+
severity: 'errors',
|
|
59
|
+
limit: 3,
|
|
60
|
+
}));
|
|
61
|
+
expect(seen).toEqual({ tool: 'fit', severity: 'errors', limit: 3 });
|
|
62
|
+
expect(out.body.data[0]?.ruleId).toBe('r');
|
|
63
|
+
expect(out.body.filtersApplied).toEqual(['errors-only', 'top:3']);
|
|
64
|
+
});
|
|
65
|
+
it('rejects an unknown tool with a structured unknown-tool error (no port call)', async () => {
|
|
66
|
+
let called = false;
|
|
67
|
+
const { server, handlers } = captureServer();
|
|
68
|
+
registerGetLatestFindings(server, deps(fakeResults({
|
|
69
|
+
latestFindings: () => {
|
|
70
|
+
called = true;
|
|
71
|
+
return Promise.resolve(ok({ data: [] }));
|
|
72
|
+
},
|
|
73
|
+
})));
|
|
74
|
+
const out = parseResult(await handlers.get('get_latest_findings')({ tool: 'nope' }));
|
|
75
|
+
expect(out.isError).toBe(true);
|
|
76
|
+
expect(out.body.error.code).toBe('unknown-tool');
|
|
77
|
+
expect(called).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
it('surfaces the port err arm', async () => {
|
|
80
|
+
const { server, handlers } = captureServer();
|
|
81
|
+
registerGetLatestFindings(server, deps(fakeResults({
|
|
82
|
+
latestFindings: () => Promise.resolve(err({ code: 'not-found', message: 'no runs' })),
|
|
83
|
+
})));
|
|
84
|
+
const out = parseResult(await handlers.get('get_latest_findings')({ tool: 'fit' }));
|
|
85
|
+
expect(out.isError).toBe(true);
|
|
86
|
+
expect(out.body.error.code).toBe('not-found');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
// ── list_runs ────────────────────────────────────────────────────────
|
|
90
|
+
describe('list_runs handler', () => {
|
|
91
|
+
it('forwards tool/limit/summaryOnly and wraps rows under { runs }', () => {
|
|
92
|
+
let seen;
|
|
93
|
+
const row = {
|
|
94
|
+
id: 's1',
|
|
95
|
+
tool: 'fit',
|
|
96
|
+
startedAt: 't',
|
|
97
|
+
completedAt: 't',
|
|
98
|
+
score: 90,
|
|
99
|
+
passed: true,
|
|
100
|
+
showCommand: 'opensip sessions show s1 --json',
|
|
101
|
+
};
|
|
102
|
+
const { server, handlers } = captureServer();
|
|
103
|
+
registerListRuns(server, deps(fakeResults({
|
|
104
|
+
listRuns: (opts) => {
|
|
105
|
+
seen = opts;
|
|
106
|
+
return ok([row]);
|
|
107
|
+
},
|
|
108
|
+
})));
|
|
109
|
+
const out = parseResult(handlers.get('list_runs')({ tool: 'fit', limit: 10, summaryOnly: true }));
|
|
110
|
+
expect(seen).toEqual({ tool: 'fit', limit: 10, summaryOnly: true });
|
|
111
|
+
expect(out.body.runs[0]?.id).toBe('s1');
|
|
112
|
+
});
|
|
113
|
+
it('lists with no arguments (all optional filters omitted)', () => {
|
|
114
|
+
let seen;
|
|
115
|
+
const { server, handlers } = captureServer();
|
|
116
|
+
registerListRuns(server, deps(fakeResults({
|
|
117
|
+
listRuns: (opts) => {
|
|
118
|
+
seen = opts;
|
|
119
|
+
return ok([]);
|
|
120
|
+
},
|
|
121
|
+
})));
|
|
122
|
+
const out = parseResult(handlers.get('list_runs')({}));
|
|
123
|
+
expect(out.isError).toBe(false);
|
|
124
|
+
expect(seen).toEqual({});
|
|
125
|
+
});
|
|
126
|
+
it('rejects an unknown tool filter, naming "(none registered)" when no tools exist', () => {
|
|
127
|
+
const { server, handlers } = captureServer();
|
|
128
|
+
registerListRuns(server, deps(fakeResults({ listRuns: () => ok([]) }), new Set()));
|
|
129
|
+
const out = parseResult(handlers.get('list_runs')({ tool: 'nope' }));
|
|
130
|
+
expect(out.isError).toBe(true);
|
|
131
|
+
expect(out.body.error.message).toContain('(none registered)');
|
|
132
|
+
});
|
|
133
|
+
it('surfaces a listRuns port error', () => {
|
|
134
|
+
const { server, handlers } = captureServer();
|
|
135
|
+
registerListRuns(server, deps(fakeResults({ listRuns: () => err({ code: 'boom', message: 'x' }) })));
|
|
136
|
+
const out = parseResult(handlers.get('list_runs')({}));
|
|
137
|
+
expect(out.isError).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
// ── show_run ─────────────────────────────────────────────────────────
|
|
141
|
+
describe('show_run handler', () => {
|
|
142
|
+
it('forwards ref/tool/filters/raw to the port', async () => {
|
|
143
|
+
let seen;
|
|
144
|
+
const { server, handlers } = captureServer();
|
|
145
|
+
registerShowRun(server, deps(fakeResults({
|
|
146
|
+
showRun: (opts) => {
|
|
147
|
+
seen = opts;
|
|
148
|
+
return Promise.resolve(ok({
|
|
149
|
+
data: { fidelity: 'projection' },
|
|
150
|
+
}));
|
|
151
|
+
},
|
|
152
|
+
})));
|
|
153
|
+
await handlers.get('show_run')({
|
|
154
|
+
ref: 'latest',
|
|
155
|
+
tool: 'fit',
|
|
156
|
+
filters: ['errors-only'],
|
|
157
|
+
raw: true,
|
|
158
|
+
});
|
|
159
|
+
expect(seen).toEqual({ ref: 'latest', tool: 'fit', filters: ['errors-only'], raw: true });
|
|
160
|
+
});
|
|
161
|
+
it('rejects an unknown tool sanity-check', async () => {
|
|
162
|
+
const { server, handlers } = captureServer();
|
|
163
|
+
registerShowRun(server, deps(fakeResults({})));
|
|
164
|
+
const out = parseResult(await handlers.get('show_run')({ ref: 'latest', tool: 'nope' }));
|
|
165
|
+
expect(out.isError).toBe(true);
|
|
166
|
+
expect(out.body.error.code).toBe('unknown-tool');
|
|
167
|
+
});
|
|
168
|
+
it('surfaces a not-found err arm', async () => {
|
|
169
|
+
const { server, handlers } = captureServer();
|
|
170
|
+
registerShowRun(server, deps(fakeResults({
|
|
171
|
+
showRun: () => Promise.resolve(err({ code: 'not-found', message: 'no session' })),
|
|
172
|
+
})));
|
|
173
|
+
const out = parseResult(await handlers.get('show_run')({ ref: 'nope' }));
|
|
174
|
+
expect(out.isError).toBe(true);
|
|
175
|
+
expect(out.body.error.code).toBe('not-found');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
// ── get_agent_catalog ────────────────────────────────────────────────
|
|
179
|
+
describe('get_agent_catalog handler', () => {
|
|
180
|
+
it('returns the agent catalog', () => {
|
|
181
|
+
const { server, handlers } = captureServer();
|
|
182
|
+
registerGetAgentCatalog(server, deps(fakeResults({ agentCatalog: () => ok({ commands: ['fit'] }) })));
|
|
183
|
+
const out = parseResult(handlers.get('get_agent_catalog')({}));
|
|
184
|
+
expect(out.isError).toBe(false);
|
|
185
|
+
expect(out.body.commands).toEqual(['fit']);
|
|
186
|
+
});
|
|
187
|
+
it('surfaces an err arm', () => {
|
|
188
|
+
const { server, handlers } = captureServer();
|
|
189
|
+
registerGetAgentCatalog(server, deps(fakeResults({ agentCatalog: () => err({ code: 'boom', message: 'x' }) })));
|
|
190
|
+
const out = parseResult(handlers.get('get_agent_catalog')({}));
|
|
191
|
+
expect(out.isError).toBe(true);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
//# sourceMappingURL=result-handlers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-handlers.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/result-handlers.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tool Zod boundary schemas (Task 6.1 §Hardening).
|
|
3
|
+
*
|
|
4
|
+
* Every MCP tool argument is validated by these field schemas BEFORE the handler
|
|
5
|
+
* runs, so hostile input is rejected at the trust boundary and never reaches a
|
|
6
|
+
* port: a malformed `symbolId`, a `..`-traversal / absolute `file`, an over-long
|
|
7
|
+
* `query`, and out-of-range `depth`/`limit`.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=schemas.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/schemas.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tool Zod boundary schemas (Task 6.1 §Hardening).
|
|
3
|
+
*
|
|
4
|
+
* Every MCP tool argument is validated by these field schemas BEFORE the handler
|
|
5
|
+
* runs, so hostile input is rejected at the trust boundary and never reaches a
|
|
6
|
+
* port: a malformed `symbolId`, a `..`-traversal / absolute `file`, an over-long
|
|
7
|
+
* `query`, and out-of-range `depth`/`limit`.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, expect, it } from 'vitest';
|
|
10
|
+
import { DEFAULT_DEPTH, MAX_DEPTH, MAX_LIMIT, MAX_QUERY_LEN, depth, filePath, limit, query, symbolId, } from '../schemas.js';
|
|
11
|
+
describe('symbolId schema', () => {
|
|
12
|
+
it('accepts the canonical "<filePath>:<line>:<column>" shape', () => {
|
|
13
|
+
expect(symbolId().safeParse('packages/core/src/a.ts:12:4').success).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
it('rejects a bare name (no line:col)', () => {
|
|
16
|
+
expect(symbolId().safeParse('saveBaseline').success).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
it('rejects a malformed id whose trailing groups are not integers', () => {
|
|
19
|
+
expect(symbolId().safeParse('a.ts:12:x').success).toBe(false);
|
|
20
|
+
expect(symbolId().safeParse('a.ts:line:col').success).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('filePath schema', () => {
|
|
24
|
+
it('accepts a project-relative path', () => {
|
|
25
|
+
expect(filePath().safeParse('packages/core/src/a.ts').success).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it('rejects an absolute POSIX path', () => {
|
|
28
|
+
expect(filePath().safeParse('/etc/passwd').success).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it('rejects a Windows drive-absolute path', () => {
|
|
31
|
+
expect(filePath().safeParse('C:\\windows\\system32').success).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
it('rejects a ".." traversal escaping the project root', () => {
|
|
34
|
+
expect(filePath().safeParse('../../etc/passwd').success).toBe(false);
|
|
35
|
+
expect(filePath().safeParse('src/../../secret').success).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('query schema', () => {
|
|
39
|
+
it('accepts a normal search term', () => {
|
|
40
|
+
expect(query().safeParse('saveBaseline').success).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
it('rejects an over-long (potential ReDoS-payload) query', () => {
|
|
43
|
+
expect(query().safeParse('x'.repeat(MAX_QUERY_LEN + 1)).success).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
it('rejects an empty query', () => {
|
|
46
|
+
expect(query().safeParse('').success).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('depth schema', () => {
|
|
50
|
+
it('defaults to DEFAULT_DEPTH when omitted', () => {
|
|
51
|
+
const parsed = depth().safeParse(undefined);
|
|
52
|
+
expect(parsed.success).toBe(true);
|
|
53
|
+
expect(parsed.success && parsed.data).toBe(DEFAULT_DEPTH);
|
|
54
|
+
});
|
|
55
|
+
it('rejects a depth above the maximum (not silently clamped through here)', () => {
|
|
56
|
+
expect(depth().safeParse(MAX_DEPTH + 1).success).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
it('rejects a zero / negative depth', () => {
|
|
59
|
+
expect(depth().safeParse(0).success).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('limit schema', () => {
|
|
63
|
+
it('rejects a limit above MAX_LIMIT', () => {
|
|
64
|
+
expect(limit().safeParse(MAX_LIMIT + 1).success).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
it('accepts the maximum limit', () => {
|
|
67
|
+
expect(limit().safeParse(MAX_LIMIT).success).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
it('is optional', () => {
|
|
70
|
+
expect(limit().safeParse(undefined).success).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=schemas.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/schemas.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `blast_radius` — change-impact score for a symbol (ADR-0084, Task 4.3).
|
|
3
|
+
*
|
|
4
|
+
* Delegates to `graphPort.blast()`, which reuses graph's single canonical
|
|
5
|
+
* `buildFeatures(['blast'])` scoring site — so the numbers never diverge from
|
|
6
|
+
* `opensip graph`. NOT a re-implemented BFS. Returns `{ data, freshness }` with
|
|
7
|
+
* direct/transitive caller counts + the composite score.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpToolDeps } from './types.js';
|
|
10
|
+
import type { McpStdioServer } from '../server.js';
|
|
11
|
+
export declare function registerBlastRadius(server: McpStdioServer, deps: McpToolDeps): void;
|
|
12
|
+
//# sourceMappingURL=blast-radius.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blast-radius.d.ts","sourceRoot":"","sources":["../../src/tools/blast-radius.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA4BnF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `blast_radius` — change-impact score for a symbol (ADR-0084, Task 4.3).
|
|
3
|
+
*
|
|
4
|
+
* Delegates to `graphPort.blast()`, which reuses graph's single canonical
|
|
5
|
+
* `buildFeatures(['blast'])` scoring site — so the numbers never diverge from
|
|
6
|
+
* `opensip graph`. NOT a re-implemented BFS. Returns `{ data, freshness }` with
|
|
7
|
+
* direct/transitive caller counts + the composite score.
|
|
8
|
+
*/
|
|
9
|
+
import { symbolId as symbolIdSchema } from './schemas.js';
|
|
10
|
+
import { errorResult, failure, jsonResult } from './tool-result.js';
|
|
11
|
+
export function registerBlastRadius(server, deps) {
|
|
12
|
+
server.register('blast_radius', {
|
|
13
|
+
title: 'Blast radius of a symbol',
|
|
14
|
+
description: 'Change-impact score for a symbol: direct (depth-1) callers, transitive callers, and a ' +
|
|
15
|
+
'composite blast score (direct + 0.5×transitive) — the same scoring `opensip graph` ' +
|
|
16
|
+
'uses. Pass a symbolId from search_symbols/get_symbol.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
symbolId: symbolIdSchema(),
|
|
19
|
+
},
|
|
20
|
+
}, ({ symbolId }) => {
|
|
21
|
+
const outcome = deps.graph.blast(symbolId);
|
|
22
|
+
if (!outcome.ok)
|
|
23
|
+
return errorResult(outcome.error);
|
|
24
|
+
const { data, freshness } = outcome.value;
|
|
25
|
+
if (data === undefined) {
|
|
26
|
+
return failure('blast-unavailable', freshness.fresh
|
|
27
|
+
? `No blast score for symbolId "${symbolId}" — check the id via search_symbols/get_symbol.`
|
|
28
|
+
: 'The catalog is stale/missing — run refresh_graph, then retry.');
|
|
29
|
+
}
|
|
30
|
+
return jsonResult({ data, freshness });
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=blast-radius.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blast-radius.js","sourceRoot":"","sources":["../../src/tools/blast-radius.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKpE,MAAM,UAAU,mBAAmB,CAAC,MAAsB,EAAE,IAAiB;IAC3E,MAAM,CAAC,QAAQ,CACb,cAAc,EACd;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,wFAAwF;YACxF,qFAAqF;YACrF,uDAAuD;QACzD,WAAW,EAAE;YACX,QAAQ,EAAE,cAAc,EAAE;SAC3B;KACF,EACD,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACnD,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAC1C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,OAAO,CACZ,mBAAmB,EACnB,SAAS,CAAC,KAAK;gBACb,CAAC,CAAC,gCAAgC,QAAQ,iDAAiD;gBAC3F,CAAC,CAAC,+DAA+D,CACpE,CAAC;QACJ,CAAC;QACD,OAAO,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared registration for bounded call-graph walk tools.
|
|
3
|
+
*
|
|
4
|
+
* `who_calls` and `callees_of` differ only by metadata and adjacency direction;
|
|
5
|
+
* resolving `symbolId`, enforcing the bounded BFS, freshness propagation, and
|
|
6
|
+
* `truncated` shaping belong in one implementation.
|
|
7
|
+
*/
|
|
8
|
+
import type { GraphReadPort } from '../graph-read-port.js';
|
|
9
|
+
import type { McpStdioServer } from '../server.js';
|
|
10
|
+
export interface CallWalkToolSpec {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly title: string;
|
|
13
|
+
readonly description: string;
|
|
14
|
+
readonly graph: (port: GraphReadPort) => ReturnType<GraphReadPort['callerGraph']>;
|
|
15
|
+
}
|
|
16
|
+
export declare function registerCallWalkTool(server: McpStdioServer, graphPort: GraphReadPort, spec: CallWalkToolSpec): void;
|
|
17
|
+
//# sourceMappingURL=call-walk-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-walk-tool.d.ts","sourceRoot":"","sources":["../../src/tools/call-walk-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;CACnF;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,gBAAgB,GACrB,IAAI,CAoCN"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared registration for bounded call-graph walk tools.
|
|
3
|
+
*
|
|
4
|
+
* `who_calls` and `callees_of` differ only by metadata and adjacency direction;
|
|
5
|
+
* resolving `symbolId`, enforcing the bounded BFS, freshness propagation, and
|
|
6
|
+
* `truncated` shaping belong in one implementation.
|
|
7
|
+
*/
|
|
8
|
+
import { boundedBfs, MAX_WALK_NODES } from './graph-walk.js';
|
|
9
|
+
import { depth as depthSchema, symbolId as symbolIdSchema } from './schemas.js';
|
|
10
|
+
import { errorResult, failure, jsonResult } from './tool-result.js';
|
|
11
|
+
export function registerCallWalkTool(server, graphPort, spec) {
|
|
12
|
+
server.register(spec.name, {
|
|
13
|
+
title: spec.title,
|
|
14
|
+
description: spec.description,
|
|
15
|
+
inputSchema: {
|
|
16
|
+
symbolId: symbolIdSchema(),
|
|
17
|
+
depth: depthSchema(),
|
|
18
|
+
},
|
|
19
|
+
}, ({ symbolId, depth }) => {
|
|
20
|
+
const resolved = graphPort.resolveSymbolId(symbolId);
|
|
21
|
+
if (!resolved.ok)
|
|
22
|
+
return errorResult(resolved.error);
|
|
23
|
+
const startRef = resolved.value.data;
|
|
24
|
+
if (startRef === undefined) {
|
|
25
|
+
return failure('symbol-not-found', `Unknown symbolId "${symbolId}". Obtain a valid symbolId from search_symbols or get_symbol.`);
|
|
26
|
+
}
|
|
27
|
+
const graph = spec.graph(graphPort);
|
|
28
|
+
if (!graph.ok)
|
|
29
|
+
return errorResult(graph.error);
|
|
30
|
+
const { data: snapshot, freshness } = graph.value;
|
|
31
|
+
const walk = boundedBfs(snapshot.edges, startRef.bodyHash, {
|
|
32
|
+
depth,
|
|
33
|
+
cap: MAX_WALK_NODES,
|
|
34
|
+
});
|
|
35
|
+
const data = walk.order.map((hash) => snapshot.resolve(hash)).filter(isSymbolRef);
|
|
36
|
+
return jsonResult({
|
|
37
|
+
data,
|
|
38
|
+
freshness,
|
|
39
|
+
...(walk.truncated ? { truncated: true } : {}),
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function isSymbolRef(ref) {
|
|
44
|
+
return ref !== undefined;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=call-walk-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-walk-tool.js","sourceRoot":"","sources":["../../src/tools/call-walk-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAapE,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,SAAwB,EACxB,IAAsB;IAEtB,MAAM,CAAC,QAAQ,CACb,IAAI,CAAC,IAAI,EACT;QACE,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE;YACX,QAAQ,EAAE,cAAc,EAAE;YAC1B,KAAK,EAAE,WAAW,EAAE;SACrB;KACF,EACD,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QACtB,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;QACrC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,OAAO,CACZ,kBAAkB,EAClB,qBAAqB,QAAQ,+DAA+D,CAC7F,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC;QAClD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE;YACzD,KAAK;YACL,GAAG,EAAE,cAAc;SACpB,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAClF,OAAO,UAAU,CAAC;YAChB,IAAI;YACJ,SAAS;YACT,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/C,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,GAA0B;IAC7C,OAAO,GAAG,KAAK,SAAS,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `callees_of` — bounded forward call walk (ADR-0084, Task 4.2).
|
|
3
|
+
*
|
|
4
|
+
* The forward twin of `who_calls`: resolves `symbolId` via the port, then runs
|
|
5
|
+
* the shared {@link boundedBfs} over the forward-call adjacency snapshot. Same
|
|
6
|
+
* bounds (depth default 5, max 5; node cap → `truncated`) and same
|
|
7
|
+
* `{ data, freshness, truncated? }` envelope.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpToolDeps } from './types.js';
|
|
10
|
+
import type { McpStdioServer } from '../server.js';
|
|
11
|
+
export declare function registerCalleesOf(server: McpStdioServer, deps: McpToolDeps): void;
|
|
12
|
+
//# sourceMappingURL=callees-of.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callees-of.d.ts","sourceRoot":"","sources":["../../src/tools/callees-of.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAUjF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `callees_of` — bounded forward call walk (ADR-0084, Task 4.2).
|
|
3
|
+
*
|
|
4
|
+
* The forward twin of `who_calls`: resolves `symbolId` via the port, then runs
|
|
5
|
+
* the shared {@link boundedBfs} over the forward-call adjacency snapshot. Same
|
|
6
|
+
* bounds (depth default 5, max 5; node cap → `truncated`) and same
|
|
7
|
+
* `{ data, freshness, truncated? }` envelope.
|
|
8
|
+
*/
|
|
9
|
+
import { registerCallWalkTool } from './call-walk-tool.js';
|
|
10
|
+
export function registerCalleesOf(server, deps) {
|
|
11
|
+
registerCallWalkTool(server, deps.graph, {
|
|
12
|
+
name: 'callees_of',
|
|
13
|
+
title: 'Callees of a symbol',
|
|
14
|
+
description: 'Find the symbols a symbol calls (forward call graph), out to `depth` levels (default 5, ' +
|
|
15
|
+
'max 5). Pass a symbolId from search_symbols/get_symbol. Edges are body-hash-union ' +
|
|
16
|
+
'(twin-aware). Large fan-out is node-capped with truncated:true.',
|
|
17
|
+
graph: (port) => port.calleeGraph(),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=callees-of.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callees-of.js","sourceRoot":"","sources":["../../src/tools/callees-of.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAK3D,MAAM,UAAU,iBAAiB,CAAC,MAAsB,EAAE,IAAiB;IACzE,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE;QACvC,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,0FAA0F;YAC1F,oFAAoF;YACpF,iEAAiE;QACnE,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `find_dead_code` — orphan (unreachable) symbols (ADR-0084, Task 4.3).
|
|
3
|
+
*
|
|
4
|
+
* Delegates to `graphPort.deadCode()`, backed by graph's `orphan-subtree` rule
|
|
5
|
+
* (reachability from entry points) — NOT ad-hoc filesystem reachability. Returns
|
|
6
|
+
* the `{ data, freshness, truncated? }` envelope; `limit` caps the result.
|
|
7
|
+
*/
|
|
8
|
+
import type { McpToolDeps } from './types.js';
|
|
9
|
+
import type { McpStdioServer } from '../server.js';
|
|
10
|
+
export declare function registerFindDeadCode(server: McpStdioServer, deps: McpToolDeps): void;
|
|
11
|
+
//# sourceMappingURL=find-dead-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-dead-code.d.ts","sourceRoot":"","sources":["../../src/tools/find-dead-code.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAmBpF"}
|