@shrkcrft/mcp-server 0.1.0-alpha.16 → 0.1.0-alpha.18
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/dist/server/fit-array-to-budget.d.ts +6 -2
- package/dist/server/fit-array-to-budget.d.ts.map +1 -1
- package/dist/server/fit-array-to-budget.js +45 -13
- package/dist/tools/all-tools.d.ts.map +1 -1
- package/dist/tools/all-tools.js +6 -0
- package/dist/tools/code-find-usages.tool.d.ts.map +1 -1
- package/dist/tools/code-find-usages.tool.js +44 -6
- package/dist/tools/compress-context.tool.d.ts.map +1 -1
- package/dist/tools/compress-context.tool.js +3 -2
- package/dist/tools/delegate-task.tool.d.ts +3 -0
- package/dist/tools/delegate-task.tool.d.ts.map +1 -0
- package/dist/tools/delegate-task.tool.js +94 -0
- package/dist/tools/deps-audit.tool.js +8 -4
- package/dist/tools/get-graph-callers.tool.d.ts.map +1 -1
- package/dist/tools/get-graph-callers.tool.js +19 -6
- package/dist/tools/get-graph-context.tool.d.ts.map +1 -1
- package/dist/tools/get-graph-context.tool.js +49 -15
- package/dist/tools/get-graph-cycles.tool.js +2 -2
- package/dist/tools/get-graph-deps.tool.js +2 -2
- package/dist/tools/get-graph-hubs.tool.d.ts +3 -0
- package/dist/tools/get-graph-hubs.tool.d.ts.map +1 -0
- package/dist/tools/get-graph-hubs.tool.js +61 -0
- package/dist/tools/get-graph-impact.tool.d.ts.map +1 -1
- package/dist/tools/get-graph-impact.tool.js +36 -14
- package/dist/tools/get-graph-path.tool.d.ts +3 -0
- package/dist/tools/get-graph-path.tool.d.ts.map +1 -0
- package/dist/tools/get-graph-path.tool.js +144 -0
- package/dist/tools/get-graph-search.tool.d.ts.map +1 -1
- package/dist/tools/get-graph-search.tool.js +22 -3
- package/dist/tools/get-graph-status.tool.d.ts +5 -3
- package/dist/tools/get-graph-status.tool.d.ts.map +1 -1
- package/dist/tools/get-graph-status.tool.js +15 -6
- package/dist/tools/get-knowledge-graph.tool.js +1 -1
- package/dist/tools/graph-staleness.d.ts +34 -0
- package/dist/tools/graph-staleness.d.ts.map +1 -0
- package/dist/tools/graph-staleness.js +36 -0
- package/dist/tools/primary-tools.d.ts +1 -1
- package/dist/tools/primary-tools.d.ts.map +1 -1
- package/dist/tools/primary-tools.js +12 -1
- package/dist/tools/start-here.tool.js +2 -2
- package/package.json +27 -27
- package/dist/tools/r22-extras.tool.d.ts +0 -4
- package/dist/tools/r22-extras.tool.d.ts.map +0 -1
- package/dist/tools/r22-extras.tool.js +0 -42
- package/dist/tools/r26-ingest.tool.d.ts +0 -10
- package/dist/tools/r26-ingest.tool.d.ts.map +0 -1
- package/dist/tools/r26-ingest.tool.js +0 -174
- package/dist/tools/r34-search-unified.tool.d.ts +0 -3
- package/dist/tools/r34-search-unified.tool.d.ts.map +0 -1
- package/dist/tools/r34-search-unified.tool.js +0 -38
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { GraphQueryApi, GraphStore, loadGraphApiCached } from '@shrkcrft/graph';
|
|
2
|
+
import { FORMAT_INPUT_PROPERTY, formatObjectArrays } from "../server/columnar-format.js";
|
|
3
|
+
const NEXT = 'shrk graph index';
|
|
4
|
+
export const getGraphHubsTool = {
|
|
5
|
+
name: 'get_graph_hubs',
|
|
6
|
+
description: 'The most-depended-on code: symbols ranked by how many DISTINCT files reference them, files by how many import them. The "load-bearing code" to change most carefully (biggest blast radius) and understand first when onboarding — the companion to get_graph_impact. Pass `path` (e.g. "packages/foo") to scope to one subsystem. Read-only; needs `shrk graph index`.',
|
|
7
|
+
cliCommand: 'graph hubs',
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
limit: { type: 'number' },
|
|
12
|
+
path: { type: 'string' },
|
|
13
|
+
...FORMAT_INPUT_PROPERTY,
|
|
14
|
+
},
|
|
15
|
+
additionalProperties: false,
|
|
16
|
+
},
|
|
17
|
+
handler(input, ctx) {
|
|
18
|
+
const args = input;
|
|
19
|
+
const limit = clampLimit(args.limit);
|
|
20
|
+
const projectRoot = ctx.inspection.projectRoot;
|
|
21
|
+
const store = new GraphStore(projectRoot);
|
|
22
|
+
if (!store.exists()) {
|
|
23
|
+
return {
|
|
24
|
+
isError: true,
|
|
25
|
+
error: {
|
|
26
|
+
code: 'graph-missing',
|
|
27
|
+
message: `Code-intelligence index is missing. Run '${NEXT}'.`,
|
|
28
|
+
details: { nextCommand: NEXT },
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const api = loadGraphApiCached(projectRoot) ?? GraphQueryApi.fromStore(projectRoot);
|
|
33
|
+
const pathScope = typeof args.path === 'string' && args.path.trim().length > 0 ? args.path.trim() : undefined;
|
|
34
|
+
const hubs = api.topHubs(limit, pathScope);
|
|
35
|
+
const row = (h) => ({
|
|
36
|
+
...summarise(h.node),
|
|
37
|
+
inDegree: h.inDegree,
|
|
38
|
+
});
|
|
39
|
+
const data = {
|
|
40
|
+
schema: 'sharkcraft.graph-hubs/v1',
|
|
41
|
+
...(pathScope ? { path: pathScope } : {}),
|
|
42
|
+
symbols: hubs.symbols.map(row),
|
|
43
|
+
files: hubs.files.map(row),
|
|
44
|
+
};
|
|
45
|
+
return { data: formatObjectArrays(data, input) };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
function clampLimit(raw) {
|
|
49
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw))
|
|
50
|
+
return 15;
|
|
51
|
+
return Math.max(1, Math.min(100, Math.floor(raw)));
|
|
52
|
+
}
|
|
53
|
+
function summarise(n) {
|
|
54
|
+
return {
|
|
55
|
+
id: n.id,
|
|
56
|
+
kind: n.kind,
|
|
57
|
+
label: n.label,
|
|
58
|
+
...(n.path ? { path: n.path } : {}),
|
|
59
|
+
...(n.line ? { line: n.line } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-graph-impact.tool.d.ts","sourceRoot":"","sources":["../../src/tools/get-graph-impact.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"get-graph-impact.tool.d.ts","sourceRoot":"","sources":["../../src/tools/get-graph-impact.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAYpE,eAAO,MAAM,kBAAkB,EAAE,eA4EhC,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { GraphQueryApi, GraphStore } from '@shrkcrft/graph';
|
|
1
|
+
import { GraphQueryApi, GraphStore, loadGraphApiCached } from '@shrkcrft/graph';
|
|
2
2
|
import { FORMAT_INPUT_PROPERTY, formatObjectArrays } from "../server/columnar-format.js";
|
|
3
|
+
import { dropDeleted, graphResultStaleness } from "./graph-staleness.js";
|
|
3
4
|
const NEXT = 'shrk graph index';
|
|
4
5
|
export const getGraphImpactTool = {
|
|
5
6
|
name: 'get_graph_impact',
|
|
@@ -38,7 +39,7 @@ export const getGraphImpactTool = {
|
|
|
38
39
|
},
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
|
-
const api = GraphQueryApi.fromStore(ctx.inspection.projectRoot);
|
|
42
|
+
const api = loadGraphApiCached(ctx.inspection.projectRoot) ?? GraphQueryApi.fromStore(ctx.inspection.projectRoot);
|
|
42
43
|
const anchor = resolveAnchor(api, target);
|
|
43
44
|
if (!anchor) {
|
|
44
45
|
return {
|
|
@@ -50,20 +51,29 @@ export const getGraphImpactTool = {
|
|
|
50
51
|
},
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
|
-
const closure = reverseClosure(api, anchor
|
|
54
|
+
const closure = reverseClosure(api, anchor, maxDepth, limit);
|
|
54
55
|
const direct = closure.layer[1] ?? [];
|
|
55
56
|
const transitive = closure.all.filter((id) => id !== anchor.id && !direct.includes(id));
|
|
57
|
+
const directNodes = direct.map((id) => summarise(api.neighbours(id).node));
|
|
58
|
+
const transitiveNodes = transitive.slice(0, limit).map((id) => summarise(api.neighbours(id).node));
|
|
59
|
+
// Targeted staleness over the blast-radius files: drop dependents whose
|
|
60
|
+
// file was deleted (they can't break), flag those whose content changed —
|
|
61
|
+
// so a stale index never misroutes which tests/files the agent trusts.
|
|
62
|
+
const fresh = graphResultStaleness(api, ctx.inspection.projectRoot, [
|
|
63
|
+
anchor.path,
|
|
64
|
+
...directNodes.map((n) => n.path),
|
|
65
|
+
...transitiveNodes.map((n) => n.path),
|
|
66
|
+
]);
|
|
56
67
|
const data = {
|
|
57
68
|
schema: 'sharkcraft.graph-impact/v1',
|
|
58
69
|
anchor: summarise(anchor),
|
|
59
70
|
maxDepth,
|
|
60
71
|
limit,
|
|
61
72
|
truncated: closure.truncated,
|
|
62
|
-
directDependents:
|
|
63
|
-
transitiveDependents:
|
|
64
|
-
.slice(0, limit)
|
|
65
|
-
.map((id) => summarise(api.neighbours(id).node)),
|
|
73
|
+
directDependents: dropDeleted(directNodes, fresh.deletedSet),
|
|
74
|
+
transitiveDependents: dropDeleted(transitiveNodes, fresh.deletedSet),
|
|
66
75
|
totalReached: closure.all.length - 1,
|
|
76
|
+
...(fresh.field ?? {}),
|
|
67
77
|
};
|
|
68
78
|
return { data: formatObjectArrays(data, input) };
|
|
69
79
|
},
|
|
@@ -83,13 +93,23 @@ function resolveAnchor(api, target) {
|
|
|
83
93
|
return syms[0];
|
|
84
94
|
return undefined;
|
|
85
95
|
}
|
|
86
|
-
function reverseClosure(api,
|
|
87
|
-
const seen = new Set([
|
|
96
|
+
function reverseClosure(api, anchor, maxDepth, limit) {
|
|
97
|
+
const seen = new Set([anchor.id]);
|
|
88
98
|
const layer = {};
|
|
89
|
-
let frontier = [startId];
|
|
90
|
-
let depth = 1;
|
|
91
99
|
let truncated = false;
|
|
92
|
-
|
|
100
|
+
// Layer 1 uses the anchor-kind-aware direct dependents (importersOf alone
|
|
101
|
+
// returns NOTHING for a symbol anchor — symbols have no import edges).
|
|
102
|
+
let frontier = directDependents(api, anchor).filter((id) => !seen.has(id));
|
|
103
|
+
if (frontier.length > limit) {
|
|
104
|
+
frontier = frontier.slice(0, limit);
|
|
105
|
+
truncated = true;
|
|
106
|
+
}
|
|
107
|
+
for (const id of frontier)
|
|
108
|
+
seen.add(id);
|
|
109
|
+
if (frontier.length > 0)
|
|
110
|
+
layer[1] = frontier;
|
|
111
|
+
let depth = 2;
|
|
112
|
+
while (depth <= maxDepth && frontier.length > 0 && !truncated) {
|
|
93
113
|
const next = [];
|
|
94
114
|
for (const id of frontier) {
|
|
95
115
|
for (const imp of api.importersOf(id)) {
|
|
@@ -109,11 +129,13 @@ function reverseClosure(api, startId, maxDepth, limit) {
|
|
|
109
129
|
layer[depth] = next;
|
|
110
130
|
frontier = next;
|
|
111
131
|
depth += 1;
|
|
112
|
-
if (truncated)
|
|
113
|
-
break;
|
|
114
132
|
}
|
|
115
133
|
return { all: [...seen], layer, truncated };
|
|
116
134
|
}
|
|
135
|
+
/** Kind-aware direct dependents — the shared `GraphQueryApi` implementation. */
|
|
136
|
+
function directDependents(api, anchor) {
|
|
137
|
+
return api.directDependentsOf(anchor).map((n) => n.id);
|
|
138
|
+
}
|
|
117
139
|
function summarise(n) {
|
|
118
140
|
return {
|
|
119
141
|
id: n.id,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-graph-path.tool.d.ts","sourceRoot":"","sources":["../../src/tools/get-graph-path.tool.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAYpE,eAAO,MAAM,gBAAgB,EAAE,eAgG9B,CAAC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { EdgeKind, GraphQueryApi, GraphStore, loadGraphApiCached, NodeKind, } from '@shrkcrft/graph';
|
|
2
|
+
import { FORMAT_INPUT_PROPERTY, formatObjectArrays } from "../server/columnar-format.js";
|
|
3
|
+
import { callGraphLanguageNote, graphResultStaleness } from "./graph-staleness.js";
|
|
4
|
+
const NEXT = 'shrk graph index';
|
|
5
|
+
export const getGraphPathTool = {
|
|
6
|
+
name: 'get_graph_path',
|
|
7
|
+
description: 'Is code A actually wired to code B? Returns the shortest directed CODE path (import/call/reference/declare/re-export/extends/implements edges) from `from` to `to`, hop by hop with edge kind and call-site line — the deterministic answer to "is X wired to Y" that grep cannot give. If A does not reach B it also checks B→A and reports the direction. Each endpoint is a file path or a symbol name. Read-only; needs `shrk graph index`.',
|
|
8
|
+
cliCommand: 'graph path',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
from: { type: 'string' },
|
|
13
|
+
to: { type: 'string' },
|
|
14
|
+
maxDepth: { type: 'number' },
|
|
15
|
+
...FORMAT_INPUT_PROPERTY,
|
|
16
|
+
},
|
|
17
|
+
required: ['from', 'to'],
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
},
|
|
20
|
+
handler(input, ctx) {
|
|
21
|
+
const args = input;
|
|
22
|
+
const fromArg = (args.from ?? '').trim();
|
|
23
|
+
const toArg = (args.to ?? '').trim();
|
|
24
|
+
if (!fromArg || !toArg) {
|
|
25
|
+
return { isError: true, error: { code: 'invalid-input', message: 'from and to are required' } };
|
|
26
|
+
}
|
|
27
|
+
const maxDepth = clampDepth(args.maxDepth);
|
|
28
|
+
const cwd = ctx.inspection.projectRoot;
|
|
29
|
+
const store = new GraphStore(cwd);
|
|
30
|
+
if (!store.exists()) {
|
|
31
|
+
return {
|
|
32
|
+
isError: true,
|
|
33
|
+
error: {
|
|
34
|
+
code: 'graph-missing',
|
|
35
|
+
message: `Code-intelligence index is missing. Run '${NEXT}'.`,
|
|
36
|
+
details: { nextCommand: NEXT },
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const api = loadGraphApiCached(cwd) ?? GraphQueryApi.fromStore(cwd);
|
|
41
|
+
const from = resolveAnchor(api, fromArg);
|
|
42
|
+
const to = resolveAnchor(api, toArg);
|
|
43
|
+
if (!from || !to) {
|
|
44
|
+
const missing = !from ? fromArg : toArg;
|
|
45
|
+
return {
|
|
46
|
+
isError: true,
|
|
47
|
+
error: { code: 'not-found', message: `No graph node matched "${missing}".`, details: { target: missing } },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// A symbol has no OUTGOING code edges (references are recorded file→symbol),
|
|
51
|
+
// so trace from its declaring file. The target may stay a symbol.
|
|
52
|
+
const fromStart = bfsStartNode(api, from);
|
|
53
|
+
const toStart = bfsStartNode(api, to);
|
|
54
|
+
const forward = api.pathBetween(fromStart.id, to.id, { maxDepth });
|
|
55
|
+
const reverse = forward.found ? null : api.pathBetween(toStart.id, from.id, { maxDepth });
|
|
56
|
+
const direction = forward.found
|
|
57
|
+
? 'forward'
|
|
58
|
+
: reverse?.found
|
|
59
|
+
? 'reverse'
|
|
60
|
+
: 'none';
|
|
61
|
+
const chosen = forward.found ? forward : reverse?.found ? reverse : forward;
|
|
62
|
+
const startEndpoint = direction === 'reverse' ? to : from;
|
|
63
|
+
const startFile = direction === 'reverse' ? toStart : fromStart;
|
|
64
|
+
const startNote = direction !== 'none' && startFile.id !== startEndpoint.id && startEndpoint.kind === NodeKind.Symbol
|
|
65
|
+
? `\`${startEndpoint.label}\` is declared in ${startFile.path ?? startFile.id}; path traced from that file (per-symbol out-edges are not tracked).`
|
|
66
|
+
: undefined;
|
|
67
|
+
const hops = chosen.hops.map((h) => ({
|
|
68
|
+
from: h.from.path ?? h.from.id,
|
|
69
|
+
to: h.to.path ?? h.to.id,
|
|
70
|
+
kind: h.kind,
|
|
71
|
+
label: h.to.label,
|
|
72
|
+
...(h.line ? { line: h.line } : {}),
|
|
73
|
+
}));
|
|
74
|
+
const fresh = graphResultStaleness(api, cwd, [
|
|
75
|
+
from.path,
|
|
76
|
+
to.path,
|
|
77
|
+
...chosen.hops.map((h) => h.from.path),
|
|
78
|
+
...chosen.hops.map((h) => h.to.path),
|
|
79
|
+
]);
|
|
80
|
+
// A no-path answer between non-TS endpoints may just be missing call edges.
|
|
81
|
+
const langNote = direction === 'none' ? callGraphLanguageNote(api, from) ?? callGraphLanguageNote(api, to) : undefined;
|
|
82
|
+
const data = {
|
|
83
|
+
schema: 'sharkcraft.graph-path/v1',
|
|
84
|
+
from: summarise(from),
|
|
85
|
+
to: summarise(to),
|
|
86
|
+
found: direction !== 'none',
|
|
87
|
+
direction,
|
|
88
|
+
...(direction !== 'none' && startFile.id !== startEndpoint.id ? { tracedFrom: summarise(startFile) } : {}),
|
|
89
|
+
hops,
|
|
90
|
+
hopCount: hops.length,
|
|
91
|
+
explored: forward.found ? forward.explored : reverse?.explored ?? forward.explored,
|
|
92
|
+
...(direction === 'none' && chosen.reason ? { reason: chosen.reason } : {}),
|
|
93
|
+
...(startNote ?? langNote ? { note: startNote ?? langNote } : {}),
|
|
94
|
+
...(fresh.field ?? {}),
|
|
95
|
+
};
|
|
96
|
+
return { data: formatObjectArrays(data, input) };
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
function clampDepth(raw) {
|
|
100
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw))
|
|
101
|
+
return 16;
|
|
102
|
+
return Math.max(1, Math.min(32, Math.floor(raw)));
|
|
103
|
+
}
|
|
104
|
+
function resolveAnchor(api, target) {
|
|
105
|
+
const direct = api.neighbours(target);
|
|
106
|
+
if (direct)
|
|
107
|
+
return direct.node;
|
|
108
|
+
if (target.startsWith('file:') || target.startsWith('symbol:') || target.startsWith('package:')) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const f = api.findFile(target);
|
|
112
|
+
if (f)
|
|
113
|
+
return f;
|
|
114
|
+
const syms = api.findSymbol(target, { exact: true, limit: 1 });
|
|
115
|
+
if (syms.length > 0)
|
|
116
|
+
return syms[0];
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
/** A file is its own BFS start; a symbol resolves to its declaring file. */
|
|
120
|
+
function bfsStartNode(api, node) {
|
|
121
|
+
if (node.kind !== NodeKind.Symbol)
|
|
122
|
+
return node;
|
|
123
|
+
const neighbours = api.neighbours(node.id);
|
|
124
|
+
if (neighbours) {
|
|
125
|
+
for (const incoming of neighbours.in) {
|
|
126
|
+
if (incoming.edge.kind !== EdgeKind.DeclaresSymbol)
|
|
127
|
+
continue;
|
|
128
|
+
if ('resolved' in incoming.source)
|
|
129
|
+
continue;
|
|
130
|
+
if (incoming.source.kind === NodeKind.File)
|
|
131
|
+
return incoming.source;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return (node.path ? api.findFile(node.path) : undefined) ?? node;
|
|
135
|
+
}
|
|
136
|
+
function summarise(n) {
|
|
137
|
+
return {
|
|
138
|
+
id: n.id,
|
|
139
|
+
kind: n.kind,
|
|
140
|
+
label: n.label,
|
|
141
|
+
...(n.path ? { path: n.path } : {}),
|
|
142
|
+
...(n.line ? { line: n.line } : {}),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-graph-search.tool.d.ts","sourceRoot":"","sources":["../../src/tools/get-graph-search.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAYpE,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"get-graph-search.tool.d.ts","sourceRoot":"","sources":["../../src/tools/get-graph-search.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAYpE,eAAO,MAAM,kBAAkB,EAAE,eA8EhC,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GraphQueryApi, GraphStore } from '@shrkcrft/graph';
|
|
1
|
+
import { GraphQueryApi, GraphStore, loadGraphApiCached } from '@shrkcrft/graph';
|
|
2
2
|
import { FORMAT_INPUT_PROPERTY, formatObjectArrays } from "../server/columnar-format.js";
|
|
3
3
|
const NEXT = 'shrk graph index';
|
|
4
4
|
export const getGraphSearchTool = {
|
|
@@ -38,15 +38,34 @@ export const getGraphSearchTool = {
|
|
|
38
38
|
},
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
const api = GraphQueryApi.fromStore(ctx.inspection.projectRoot);
|
|
41
|
+
const api = loadGraphApiCached(ctx.inspection.projectRoot) ?? GraphQueryApi.fromStore(ctx.inspection.projectRoot);
|
|
42
|
+
const exact = args.exact ?? false;
|
|
42
43
|
const matches = [];
|
|
43
44
|
if (!args.kind || args.kind === 'file') {
|
|
44
45
|
const f = api.findFile(query);
|
|
45
46
|
if (f)
|
|
46
47
|
matches.push(f);
|
|
48
|
+
// Fuzzy fallback (mirrors the CLI): substring match on path/basename so a
|
|
49
|
+
// bare name like `Foo` finds `packages/x/Foo.ts` without the full path —
|
|
50
|
+
// otherwise the MCP returned an empty list where the CLI found the file.
|
|
51
|
+
if (!exact && matches.length < limit) {
|
|
52
|
+
const q = query.toLowerCase();
|
|
53
|
+
const seen = new Set(matches.map((n) => n.id));
|
|
54
|
+
for (const node of api.allFiles()) {
|
|
55
|
+
if (seen.has(node.id))
|
|
56
|
+
continue;
|
|
57
|
+
const p = node.path?.toLowerCase() ?? '';
|
|
58
|
+
const base = p.includes('/') ? p.slice(p.lastIndexOf('/') + 1) : p;
|
|
59
|
+
if (base.includes(q) || p.includes(q)) {
|
|
60
|
+
matches.push(node);
|
|
61
|
+
seen.add(node.id);
|
|
62
|
+
if (matches.length >= limit)
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
47
67
|
}
|
|
48
68
|
if (!args.kind || args.kind === 'symbol') {
|
|
49
|
-
const exact = args.exact ?? false;
|
|
50
69
|
for (const s of api.findSymbol(query, { exact, limit }))
|
|
51
70
|
matches.push(s);
|
|
52
71
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { IToolDefinition } from '../server/tool-definition.js';
|
|
2
2
|
/**
|
|
3
3
|
* Read-only status for the on-disk code graph. Returns
|
|
4
|
-
* { state: 'fresh' | 'corrupt' | 'missing' } and counters.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* { state: 'fresh' | 'stale' | 'corrupt' | 'missing' } and counters.
|
|
5
|
+
* `corrupt` (store self-integrity) and `stale` (files changed on disk since
|
|
6
|
+
* indexing) are orthogonal — a store can be digest-valid yet stale — so
|
|
7
|
+
* precedence is corrupt > stale > fresh. On 'missing', `isError` +
|
|
8
|
+
* `nextCommand` direct the caller to refresh.
|
|
7
9
|
*/
|
|
8
10
|
export declare const getGraphStatusTool: IToolDefinition;
|
|
9
11
|
//# sourceMappingURL=get-graph-status.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-graph-status.tool.d.ts","sourceRoot":"","sources":["../../src/tools/get-graph-status.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAKpE
|
|
1
|
+
{"version":3,"file":"get-graph-status.tool.d.ts","sourceRoot":"","sources":["../../src/tools/get-graph-status.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAKpE;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,eA4ChC,CAAC"}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { GraphStore } from '@shrkcrft/graph';
|
|
1
|
+
import { detectGraphFreshness, GraphStore } from '@shrkcrft/graph';
|
|
2
2
|
const NEXT = 'shrk graph index';
|
|
3
3
|
const STALE_HINT = `Code-intelligence index is missing or stale. Run '${NEXT}' to build it.`;
|
|
4
4
|
/**
|
|
5
5
|
* Read-only status for the on-disk code graph. Returns
|
|
6
|
-
* { state: 'fresh' | 'corrupt' | 'missing' } and counters.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* { state: 'fresh' | 'stale' | 'corrupt' | 'missing' } and counters.
|
|
7
|
+
* `corrupt` (store self-integrity) and `stale` (files changed on disk since
|
|
8
|
+
* indexing) are orthogonal — a store can be digest-valid yet stale — so
|
|
9
|
+
* precedence is corrupt > stale > fresh. On 'missing', `isError` +
|
|
10
|
+
* `nextCommand` direct the caller to refresh.
|
|
9
11
|
*/
|
|
10
12
|
export const getGraphStatusTool = {
|
|
11
13
|
name: 'get_graph_status',
|
|
12
|
-
description: 'Read-only status of the SharkCraft code-intelligence graph: file/node/edge counts,
|
|
14
|
+
description: 'Read-only status of the SharkCraft code-intelligence graph: state (fresh/stale/corrupt/missing), file/node/edge counts, and how many files changed/added/deleted since indexing. Returns nextCommand when stale or missing so the agent knows to refresh before trusting graph answers.',
|
|
13
15
|
cliCommand: 'graph status',
|
|
14
16
|
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
|
|
15
17
|
handler(_input, ctx) {
|
|
@@ -26,10 +28,13 @@ export const getGraphStatusTool = {
|
|
|
26
28
|
}
|
|
27
29
|
const verify = store.verifyDigest();
|
|
28
30
|
const snap = store.loadSnapshot();
|
|
31
|
+
const fresh = detectGraphFreshness(ctx.inspection.projectRoot);
|
|
32
|
+
const behind = fresh.modified.length + fresh.added.length + fresh.deleted.length;
|
|
33
|
+
const state = !verify.ok ? 'corrupt' : behind > 0 ? 'stale' : 'fresh';
|
|
29
34
|
return {
|
|
30
35
|
data: {
|
|
31
36
|
schema: snap.manifest.schema,
|
|
32
|
-
state
|
|
37
|
+
state,
|
|
33
38
|
digestOk: verify.ok,
|
|
34
39
|
fileCount: snap.manifest.filesIndexed,
|
|
35
40
|
nodeCount: snap.nodes.size,
|
|
@@ -39,6 +44,10 @@ export const getGraphStatusTool = {
|
|
|
39
44
|
workspacePackages: snap.manifest.workspacePackages,
|
|
40
45
|
lastIndexedAt: snap.manifest.lastIndexedAt,
|
|
41
46
|
lastIndexDurationMs: snap.manifest.lastIndexDurationMs,
|
|
47
|
+
modifiedSinceIndex: fresh.modified.length,
|
|
48
|
+
newSinceIndex: fresh.added.length,
|
|
49
|
+
deletedSinceIndex: fresh.deleted.length,
|
|
50
|
+
...(behind > 0 ? { nextCommand: 'shrk graph index --changed' } : {}),
|
|
42
51
|
...(verify.ok ? {} : { expectedDigest: verify.expected, actualDigest: verify.actual }),
|
|
43
52
|
},
|
|
44
53
|
};
|
|
@@ -21,7 +21,7 @@ export const getKnowledgeGraphTool = {
|
|
|
21
21
|
description: 'json (default): explicit node/edge object arrays. table: columnar encoding (schema hoisted, keys deduped) — fewer tokens for large graphs.',
|
|
22
22
|
},
|
|
23
23
|
maxTokens: {
|
|
24
|
-
type: '
|
|
24
|
+
type: 'integer',
|
|
25
25
|
minimum: 1,
|
|
26
26
|
description: 'Token budget for the table. When set and the lossless columnar form still exceeds it, falls back to the lossy SmartCrusher row-sampler (representative rows kept; full original cached — retrieve via the returned ccrKey).',
|
|
27
27
|
},
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type GraphQueryApi, type INode } from '@shrkcrft/graph';
|
|
2
|
+
/**
|
|
3
|
+
* A note when a symbol's file language has no call-graph extraction (Go/Python/
|
|
4
|
+
* Java/…) — only TS/JS build call/reference edges — so an empty caller/usage
|
|
5
|
+
* result isn't read as "nothing calls it". Returns undefined for TS/JS.
|
|
6
|
+
*/
|
|
7
|
+
export declare function callGraphLanguageNote(api: GraphQueryApi, sym: INode): string | undefined;
|
|
8
|
+
export declare const GRAPH_STALE_HINT = "Result files changed since indexing \u2014 run `shrk graph index --changed` for fresh results.";
|
|
9
|
+
export interface IGraphStaleSurface {
|
|
10
|
+
/** Result file paths deleted on disk — drop entries whose `path` is in this set. */
|
|
11
|
+
deletedSet: ReadonlySet<string>;
|
|
12
|
+
/** Spread into the tool `data` object; null when every result file is fresh. */
|
|
13
|
+
field: {
|
|
14
|
+
stale: {
|
|
15
|
+
modified: readonly string[];
|
|
16
|
+
deleted: readonly string[];
|
|
17
|
+
};
|
|
18
|
+
staleHint: string;
|
|
19
|
+
} | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Targeted, read-only staleness over a query's result file paths. The graph
|
|
23
|
+
* MCP tools use it to DROP deleted result files and FLAG modified ones, so a
|
|
24
|
+
* stale index never silently serves a wrong/dead answer for a file the agent
|
|
25
|
+
* just edited. Cheap: stats only the handful of result files (mtime+size gate,
|
|
26
|
+
* sha1 only on mismatch) — never a whole-tree walk.
|
|
27
|
+
*/
|
|
28
|
+
export declare function graphResultStaleness(api: GraphQueryApi, cwd: string, paths: ReadonlyArray<string | undefined>): IGraphStaleSurface;
|
|
29
|
+
/** Filter out result entries whose file path was deleted on disk. */
|
|
30
|
+
export declare function dropDeleted<T extends {
|
|
31
|
+
id: string;
|
|
32
|
+
path?: string;
|
|
33
|
+
}>(rows: readonly T[], deletedSet: ReadonlySet<string>): T[];
|
|
34
|
+
//# sourceMappingURL=graph-staleness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-staleness.d.ts","sourceRoot":"","sources":["../../src/tools/graph-staleness.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAEzF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAKxF;AAED,eAAO,MAAM,gBAAgB,mGACgE,CAAC;AAE9F,MAAM,WAAW,kBAAkB;IACjC,oFAAoF;IACpF,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,gFAAgF;IAChF,KAAK,EACD;QAAE,KAAK,EAAE;YAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;YAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GACzF,IAAI,CAAC;CACV;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,GACvC,kBAAkB,CAUpB;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,GAC9B,CAAC,EAAE,CAEL"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { hasCallGraphReferences } from '@shrkcrft/graph';
|
|
2
|
+
/**
|
|
3
|
+
* A note when a symbol's file language has no call-graph extraction (Go/Python/
|
|
4
|
+
* Java/…) — only TS/JS build call/reference edges — so an empty caller/usage
|
|
5
|
+
* result isn't read as "nothing calls it". Returns undefined for TS/JS.
|
|
6
|
+
*/
|
|
7
|
+
export function callGraphLanguageNote(api, sym) {
|
|
8
|
+
const file = sym.path ? api.findFile(sym.path) : undefined;
|
|
9
|
+
const lang = file?.data?.['language'];
|
|
10
|
+
if (hasCallGraphReferences(lang))
|
|
11
|
+
return undefined;
|
|
12
|
+
return `Call/reference edges are extracted for TS/JS only — \`${sym.label}\` is in a ${lang} file, so callers/usages are not tracked here (an empty result does NOT mean none).`;
|
|
13
|
+
}
|
|
14
|
+
export const GRAPH_STALE_HINT = 'Result files changed since indexing — run `shrk graph index --changed` for fresh results.';
|
|
15
|
+
/**
|
|
16
|
+
* Targeted, read-only staleness over a query's result file paths. The graph
|
|
17
|
+
* MCP tools use it to DROP deleted result files and FLAG modified ones, so a
|
|
18
|
+
* stale index never silently serves a wrong/dead answer for a file the agent
|
|
19
|
+
* just edited. Cheap: stats only the handful of result files (mtime+size gate,
|
|
20
|
+
* sha1 only on mismatch) — never a whole-tree walk.
|
|
21
|
+
*/
|
|
22
|
+
export function graphResultStaleness(api, cwd, paths) {
|
|
23
|
+
const rel = paths.filter((p) => !!p);
|
|
24
|
+
const stale = api.staleFilesAmong(cwd, rel);
|
|
25
|
+
const has = stale.modified.length > 0 || stale.deleted.length > 0;
|
|
26
|
+
return {
|
|
27
|
+
deletedSet: new Set(stale.deleted),
|
|
28
|
+
field: has
|
|
29
|
+
? { stale: { modified: stale.modified, deleted: stale.deleted }, staleHint: GRAPH_STALE_HINT }
|
|
30
|
+
: null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Filter out result entries whose file path was deleted on disk. */
|
|
34
|
+
export function dropDeleted(rows, deletedSet) {
|
|
35
|
+
return rows.filter((r) => !r.path || !deletedSet.has(r.path));
|
|
36
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Primary MCP tools — the
|
|
2
|
+
* Primary MCP tools — the core set advertised to a connected agent
|
|
3
3
|
* by default. Every tool in {@link ALL_TOOLS} stays callable (so an
|
|
4
4
|
* agent that already knows the name can use it), but `tools/list`
|
|
5
5
|
* only advertises the primary set. Smaller surface = better
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primary-tools.d.ts","sourceRoot":"","sources":["../../src/tools/primary-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"primary-tools.d.ts","sourceRoot":"","sources":["../../src/tools/primary-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CA4DhD,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAGpD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Primary MCP tools — the
|
|
2
|
+
* Primary MCP tools — the core set advertised to a connected agent
|
|
3
3
|
* by default. Every tool in {@link ALL_TOOLS} stays callable (so an
|
|
4
4
|
* agent that already knows the name can use it), but `tools/list`
|
|
5
5
|
* only advertises the primary set. Smaller surface = better
|
|
@@ -54,6 +54,17 @@ export const PRIMARY_MCP_TOOLS = new Set([
|
|
|
54
54
|
// Doctor / readiness
|
|
55
55
|
'get_ai_readiness_report',
|
|
56
56
|
'doctor_packs',
|
|
57
|
+
// Code-intelligence graph — the agent's grep replacement for understanding
|
|
58
|
+
// existing code: who calls X, where is X used (path:line), what breaks if I
|
|
59
|
+
// change X, is X wired. Verifiable file:line truth from the indexed graph.
|
|
60
|
+
'get_graph_callers',
|
|
61
|
+
'code_find_usages',
|
|
62
|
+
'get_graph_impact',
|
|
63
|
+
'get_graph_path',
|
|
64
|
+
'get_graph_hubs',
|
|
65
|
+
'graph_why',
|
|
66
|
+
'get_graph_node',
|
|
67
|
+
'get_graph_search',
|
|
57
68
|
// Search
|
|
58
69
|
'search_all',
|
|
59
70
|
'search_knowledge',
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { buildStartHereReport, buildPrimaryCommandsReport, } from '@shrkcrft/inspector';
|
|
2
2
|
export const getStartHereTool = {
|
|
3
3
|
name: 'get_start_here',
|
|
4
|
-
description: 'Return the SharkCraft start-here flow list (30-second explanation +
|
|
4
|
+
description: 'Return the SharkCraft start-here flow list (30-second explanation + primary flows incl. "investigate existing code" + safety pledge). Read-only.',
|
|
5
5
|
inputSchema: {
|
|
6
6
|
type: 'object',
|
|
7
7
|
properties: {
|
|
8
8
|
flow: {
|
|
9
9
|
type: 'string',
|
|
10
|
-
enum: ['onboard', 'brief', 'dev', 'review', 'governance', 'packs', 'release'],
|
|
10
|
+
enum: ['onboard', 'investigate', 'brief', 'dev', 'review', 'governance', 'packs', 'release'],
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
13
|
additionalProperties: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/mcp-server",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.18",
|
|
4
4
|
"description": "SharkCraft MCP server: 25 tools over @modelcontextprotocol/sdk's stdio transport.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -44,32 +44,32 @@
|
|
|
44
44
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
48
|
-
"@shrkcrft/compress": "^0.1.0-alpha.
|
|
49
|
-
"@shrkcrft/config": "^0.1.0-alpha.
|
|
50
|
-
"@shrkcrft/workspace": "^0.1.0-alpha.
|
|
51
|
-
"@shrkcrft/knowledge": "^0.1.0-alpha.
|
|
52
|
-
"@shrkcrft/context": "^0.1.0-alpha.
|
|
53
|
-
"@shrkcrft/rules": "^0.1.0-alpha.
|
|
54
|
-
"@shrkcrft/paths": "^0.1.0-alpha.
|
|
55
|
-
"@shrkcrft/templates": "^0.1.0-alpha.
|
|
56
|
-
"@shrkcrft/pipelines": "^0.1.0-alpha.
|
|
57
|
-
"@shrkcrft/presets": "^0.1.0-alpha.
|
|
58
|
-
"@shrkcrft/boundaries": "^0.1.0-alpha.
|
|
59
|
-
"@shrkcrft/graph": "^0.1.0-alpha.
|
|
60
|
-
"@shrkcrft/rule-graph": "^0.1.0-alpha.
|
|
61
|
-
"@shrkcrft/structural-search": "^0.1.0-alpha.
|
|
62
|
-
"@shrkcrft/impact-engine": "^0.1.0-alpha.
|
|
63
|
-
"@shrkcrft/context-planner": "^0.1.0-alpha.
|
|
64
|
-
"@shrkcrft/architecture-guard": "^0.1.0-alpha.
|
|
65
|
-
"@shrkcrft/framework-scanners": "^0.1.0-alpha.
|
|
66
|
-
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.
|
|
67
|
-
"@shrkcrft/quality-gates": "^0.1.0-alpha.
|
|
68
|
-
"@shrkcrft/migrate": "^0.1.0-alpha.
|
|
69
|
-
"@shrkcrft/packs": "^0.1.0-alpha.
|
|
70
|
-
"@shrkcrft/generator": "^0.1.0-alpha.
|
|
71
|
-
"@shrkcrft/inspector": "^0.1.0-alpha.
|
|
72
|
-
"@shrkcrft/embeddings": "^0.1.0-alpha.
|
|
47
|
+
"@shrkcrft/core": "^0.1.0-alpha.18",
|
|
48
|
+
"@shrkcrft/compress": "^0.1.0-alpha.18",
|
|
49
|
+
"@shrkcrft/config": "^0.1.0-alpha.18",
|
|
50
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.18",
|
|
51
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.18",
|
|
52
|
+
"@shrkcrft/context": "^0.1.0-alpha.18",
|
|
53
|
+
"@shrkcrft/rules": "^0.1.0-alpha.18",
|
|
54
|
+
"@shrkcrft/paths": "^0.1.0-alpha.18",
|
|
55
|
+
"@shrkcrft/templates": "^0.1.0-alpha.18",
|
|
56
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.18",
|
|
57
|
+
"@shrkcrft/presets": "^0.1.0-alpha.18",
|
|
58
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.18",
|
|
59
|
+
"@shrkcrft/graph": "^0.1.0-alpha.18",
|
|
60
|
+
"@shrkcrft/rule-graph": "^0.1.0-alpha.18",
|
|
61
|
+
"@shrkcrft/structural-search": "^0.1.0-alpha.18",
|
|
62
|
+
"@shrkcrft/impact-engine": "^0.1.0-alpha.18",
|
|
63
|
+
"@shrkcrft/context-planner": "^0.1.0-alpha.18",
|
|
64
|
+
"@shrkcrft/architecture-guard": "^0.1.0-alpha.18",
|
|
65
|
+
"@shrkcrft/framework-scanners": "^0.1.0-alpha.18",
|
|
66
|
+
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.18",
|
|
67
|
+
"@shrkcrft/quality-gates": "^0.1.0-alpha.18",
|
|
68
|
+
"@shrkcrft/migrate": "^0.1.0-alpha.18",
|
|
69
|
+
"@shrkcrft/packs": "^0.1.0-alpha.18",
|
|
70
|
+
"@shrkcrft/generator": "^0.1.0-alpha.18",
|
|
71
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.18",
|
|
72
|
+
"@shrkcrft/embeddings": "^0.1.0-alpha.18",
|
|
73
73
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
74
74
|
"zod": "^3.25.0 || ^4.0.0"
|
|
75
75
|
},
|