@grafema/mcp 0.2.11 → 0.3.0-beta
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/analysis-worker.d.ts +4 -3
- package/dist/analysis-worker.d.ts.map +1 -1
- package/dist/analysis-worker.js +8 -203
- package/dist/analysis-worker.js.map +1 -1
- package/dist/analysis.d.ts +10 -3
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +130 -62
- package/dist/analysis.js.map +1 -1
- package/dist/config.d.ts +5 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -128
- package/dist/config.js.map +1 -1
- package/dist/definitions/analysis-tools.d.ts +6 -0
- package/dist/definitions/analysis-tools.d.ts.map +1 -0
- package/dist/definitions/analysis-tools.js +125 -0
- package/dist/definitions/analysis-tools.js.map +1 -0
- package/dist/definitions/context-tools.d.ts +6 -0
- package/dist/definitions/context-tools.d.ts.map +1 -0
- package/dist/definitions/context-tools.js +144 -0
- package/dist/definitions/context-tools.js.map +1 -0
- package/dist/definitions/graph-tools.d.ts +7 -0
- package/dist/definitions/graph-tools.d.ts.map +1 -0
- package/dist/definitions/graph-tools.js +124 -0
- package/dist/definitions/graph-tools.js.map +1 -0
- package/dist/definitions/graphql-tools.d.ts +6 -0
- package/dist/definitions/graphql-tools.d.ts.map +1 -0
- package/dist/definitions/graphql-tools.js +62 -0
- package/dist/definitions/graphql-tools.js.map +1 -0
- package/dist/definitions/guarantee-tools.d.ts +6 -0
- package/dist/definitions/guarantee-tools.d.ts.map +1 -0
- package/dist/definitions/guarantee-tools.js +136 -0
- package/dist/definitions/guarantee-tools.js.map +1 -0
- package/dist/definitions/index.d.ts +7 -0
- package/dist/definitions/index.d.ts.map +1 -0
- package/dist/definitions/index.js +24 -0
- package/dist/definitions/index.js.map +1 -0
- package/dist/definitions/knowledge-tools.d.ts +10 -0
- package/dist/definitions/knowledge-tools.d.ts.map +1 -0
- package/dist/definitions/knowledge-tools.js +300 -0
- package/dist/definitions/knowledge-tools.js.map +1 -0
- package/dist/definitions/notation-tools.d.ts +9 -0
- package/dist/definitions/notation-tools.d.ts.map +1 -0
- package/dist/definitions/notation-tools.js +62 -0
- package/dist/definitions/notation-tools.js.map +1 -0
- package/dist/definitions/project-tools.d.ts +6 -0
- package/dist/definitions/project-tools.d.ts.map +1 -0
- package/dist/definitions/project-tools.js +181 -0
- package/dist/definitions/project-tools.js.map +1 -0
- package/dist/definitions/query-tools.d.ts +6 -0
- package/dist/definitions/query-tools.d.ts.map +1 -0
- package/dist/definitions/query-tools.js +245 -0
- package/dist/definitions/query-tools.js.map +1 -0
- package/dist/definitions/types.d.ts +21 -0
- package/dist/definitions/types.d.ts.map +1 -0
- package/dist/definitions/types.js +5 -0
- package/dist/definitions/types.js.map +1 -0
- package/dist/dev-proxy.d.ts +29 -0
- package/dist/dev-proxy.d.ts.map +1 -0
- package/dist/dev-proxy.js +267 -0
- package/dist/dev-proxy.js.map +1 -0
- package/dist/handlers/analysis-handlers.d.ts.map +1 -1
- package/dist/handlers/analysis-handlers.js +34 -4
- package/dist/handlers/analysis-handlers.js.map +1 -1
- package/dist/handlers/context-handlers.d.ts +5 -6
- package/dist/handlers/context-handlers.d.ts.map +1 -1
- package/dist/handlers/context-handlers.js +19 -16
- package/dist/handlers/context-handlers.js.map +1 -1
- package/dist/handlers/coverage-handlers.js +1 -1
- package/dist/handlers/dataflow-handlers.d.ts +2 -0
- package/dist/handlers/dataflow-handlers.d.ts.map +1 -1
- package/dist/handlers/dataflow-handlers.js +68 -46
- package/dist/handlers/dataflow-handlers.js.map +1 -1
- package/dist/handlers/documentation-handlers.d.ts.map +1 -1
- package/dist/handlers/documentation-handlers.js +56 -2
- package/dist/handlers/documentation-handlers.js.map +1 -1
- package/dist/handlers/graph-handlers.d.ts +23 -0
- package/dist/handlers/graph-handlers.d.ts.map +1 -0
- package/dist/handlers/graph-handlers.js +155 -0
- package/dist/handlers/graph-handlers.js.map +1 -0
- package/dist/handlers/graphql-handlers.d.ts +9 -0
- package/dist/handlers/graphql-handlers.d.ts.map +1 -0
- package/dist/handlers/graphql-handlers.js +57 -0
- package/dist/handlers/graphql-handlers.js.map +1 -0
- package/dist/handlers/guarantee-handlers.js +1 -1
- package/dist/handlers/guard-handlers.d.ts.map +1 -1
- package/dist/handlers/guard-handlers.js +6 -3
- package/dist/handlers/guard-handlers.js.map +1 -1
- package/dist/handlers/index.d.ts +4 -0
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/index.js +6 -0
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/issue-handlers.d.ts.map +1 -1
- package/dist/handlers/issue-handlers.js +10 -15
- package/dist/handlers/issue-handlers.js.map +1 -1
- package/dist/handlers/knowledge-handlers.d.ts +25 -0
- package/dist/handlers/knowledge-handlers.d.ts.map +1 -0
- package/dist/handlers/knowledge-handlers.js +208 -0
- package/dist/handlers/knowledge-handlers.js.map +1 -0
- package/dist/handlers/notation-handlers.d.ts +6 -0
- package/dist/handlers/notation-handlers.d.ts.map +1 -0
- package/dist/handlers/notation-handlers.js +53 -0
- package/dist/handlers/notation-handlers.js.map +1 -0
- package/dist/handlers/project-handlers.js +1 -1
- package/dist/handlers/query-handlers.d.ts.map +1 -1
- package/dist/handlers/query-handlers.js +166 -20
- package/dist/handlers/query-handlers.js.map +1 -1
- package/dist/prompts.js +1 -1
- package/dist/server.d.ts +19 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +93 -3
- package/dist/server.js.map +1 -1
- package/dist/state.d.ts +10 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +61 -8
- package/dist/state.js.map +1 -1
- package/dist/types.d.ts +75 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +18 -1
- package/dist/utils.js.map +1 -1
- package/package.json +4 -3
- package/src/analysis-worker.ts +9 -301
- package/src/analysis.ts +151 -77
- package/src/config.ts +6 -193
- package/src/definitions/analysis-tools.ts +127 -0
- package/src/definitions/context-tools.ts +147 -0
- package/src/definitions/graph-tools.ts +126 -0
- package/src/definitions/graphql-tools.ts +64 -0
- package/src/definitions/guarantee-tools.ts +138 -0
- package/src/definitions/index.ts +28 -0
- package/src/definitions/knowledge-tools.ts +302 -0
- package/src/definitions/notation-tools.ts +64 -0
- package/src/definitions/project-tools.ts +183 -0
- package/src/definitions/query-tools.ts +247 -0
- package/src/definitions/types.ts +22 -0
- package/src/dev-proxy.ts +336 -0
- package/src/handlers/analysis-handlers.ts +35 -4
- package/src/handlers/context-handlers.ts +19 -15
- package/src/handlers/coverage-handlers.ts +1 -1
- package/src/handlers/dataflow-handlers.ts +74 -56
- package/src/handlers/documentation-handlers.ts +56 -2
- package/src/handlers/graph-handlers.ts +212 -0
- package/src/handlers/graphql-handlers.ts +70 -0
- package/src/handlers/guarantee-handlers.ts +1 -1
- package/src/handlers/guard-handlers.ts +7 -3
- package/src/handlers/index.ts +6 -0
- package/src/handlers/issue-handlers.ts +10 -15
- package/src/handlers/knowledge-handlers.ts +242 -0
- package/src/handlers/notation-handlers.ts +71 -0
- package/src/handlers/project-handlers.ts +1 -1
- package/src/handlers/query-handlers.ts +186 -22
- package/src/prompts.ts +1 -1
- package/src/server.ts +126 -2
- package/src/state.ts +68 -8
- package/src/types.ts +98 -3
- package/src/utils.ts +22 -1
- package/src/definitions.ts +0 -665
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Dataflow Handlers
|
|
3
|
+
*
|
|
4
|
+
* Delegates BFS tracing to @grafema/util's shared traceDataflow module.
|
|
3
5
|
*/
|
|
4
6
|
import { ensureAnalyzed } from '../analysis.js';
|
|
5
7
|
import { getProjectPath } from '../state.js';
|
|
6
8
|
import { serializeBigInt, textResult, errorResult, } from '../utils.js';
|
|
7
|
-
|
|
9
|
+
import { isGrafemaUri, toCompactSemanticId } from '@grafema/util';
|
|
10
|
+
import { traceDataflow, renderTraceNarrative, } from '@grafema/util';
|
|
11
|
+
// === TRACE ALIAS (unchanged) ===
|
|
8
12
|
export async function handleTraceAlias(args) {
|
|
9
13
|
const db = await ensureAnalyzed();
|
|
10
14
|
const { variableName, file } = args;
|
|
@@ -37,6 +41,15 @@ export async function handleTraceAlias(args) {
|
|
|
37
41
|
break;
|
|
38
42
|
}
|
|
39
43
|
visited.add(current.id);
|
|
44
|
+
// Resolve REFERENCE → declaration transparently (don't add to chain)
|
|
45
|
+
if (current.type === 'REFERENCE') {
|
|
46
|
+
const resolveEdges = await db.getOutgoingEdges(current.id, ['READS_FROM']);
|
|
47
|
+
if (resolveEdges.length > 0) {
|
|
48
|
+
current = await db.getNode(resolveEdges[0].dst);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
40
53
|
chain.push({
|
|
41
54
|
type: current.type,
|
|
42
55
|
name: current.name,
|
|
@@ -50,57 +63,59 @@ export async function handleTraceAlias(args) {
|
|
|
50
63
|
}
|
|
51
64
|
return textResult(`Alias chain for "${variableName}" (${chain.length} steps):\n\n${JSON.stringify(serializeBigInt(chain), null, 2)}`);
|
|
52
65
|
}
|
|
66
|
+
// === TRACE DATAFLOW ===
|
|
53
67
|
export async function handleTraceDataFlow(args) {
|
|
54
68
|
const db = await ensureAnalyzed();
|
|
55
|
-
const { source, direction = 'forward', max_depth = 10 } = args;
|
|
69
|
+
const { source, file, direction = 'forward', max_depth = 10, limit = 50, detail } = args;
|
|
56
70
|
// Find source node
|
|
57
|
-
let sourceNode =
|
|
58
|
-
// Try to find by ID first
|
|
59
|
-
sourceNode = await db.getNode(source);
|
|
60
|
-
// If not found, search by name
|
|
71
|
+
let sourceNode = await db.getNode(source);
|
|
61
72
|
if (!sourceNode) {
|
|
73
|
+
// Search by name, preferring nodes that match the file filter
|
|
74
|
+
let fallbackNode = null;
|
|
62
75
|
for await (const node of db.queryNodes({ name: source })) {
|
|
76
|
+
if (file && !node.file?.includes(file)) {
|
|
77
|
+
// Keep first match as fallback in case no file-matching node is found
|
|
78
|
+
if (!fallbackNode)
|
|
79
|
+
fallbackNode = node;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
63
82
|
sourceNode = node;
|
|
64
83
|
break;
|
|
65
84
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const newPath = [...path, nodeId];
|
|
77
|
-
if (direction === 'forward' || direction === 'both') {
|
|
78
|
-
const outEdges = await db.getOutgoingEdges(nodeId, [
|
|
79
|
-
'ASSIGNED_FROM',
|
|
80
|
-
'DERIVES_FROM',
|
|
81
|
-
'PASSES_ARGUMENT',
|
|
82
|
-
]);
|
|
83
|
-
for (const edge of outEdges) {
|
|
84
|
-
await trace(edge.dst, depth + 1, newPath);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (direction === 'backward' || direction === 'both') {
|
|
88
|
-
const inEdges = await db.getIncomingEdges(nodeId, [
|
|
89
|
-
'ASSIGNED_FROM',
|
|
90
|
-
'DERIVES_FROM',
|
|
91
|
-
'PASSES_ARGUMENT',
|
|
92
|
-
]);
|
|
93
|
-
for (const edge of inEdges) {
|
|
94
|
-
await trace(edge.src, depth + 1, newPath);
|
|
85
|
+
// Also try PARAMETER type nodes (often the real entry point for dataflow)
|
|
86
|
+
if (!sourceNode) {
|
|
87
|
+
for await (const node of db.queryNodes({ type: 'PARAMETER', name: source })) {
|
|
88
|
+
if (file && !node.file?.includes(file)) {
|
|
89
|
+
if (!fallbackNode)
|
|
90
|
+
fallbackNode = node;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
sourceNode = node;
|
|
94
|
+
break;
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
// Use fallback (first name match regardless of file) if no file-specific match
|
|
98
|
+
if (!sourceNode && fallbackNode) {
|
|
99
|
+
sourceNode = fallbackNode;
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
if (!sourceNode) {
|
|
103
|
+
const displaySource = isGrafemaUri(source) ? toCompactSemanticId(source) : source;
|
|
104
|
+
return errorResult(`Source "${displaySource}" not found`);
|
|
105
|
+
}
|
|
106
|
+
// Cast db to DataflowBackend — runtime types are compatible
|
|
107
|
+
const dfDb = db;
|
|
108
|
+
const traceResults = await traceDataflow(dfDb, sourceNode.id, {
|
|
109
|
+
direction: direction,
|
|
110
|
+
maxDepth: max_depth,
|
|
111
|
+
limit,
|
|
112
|
+
});
|
|
113
|
+
const sourceName = sourceNode.name || source;
|
|
114
|
+
return textResult(renderTraceNarrative(traceResults, sourceName, {
|
|
115
|
+
detail: detail || 'normal',
|
|
116
|
+
}));
|
|
103
117
|
}
|
|
118
|
+
// === CHECK INVARIANT (unchanged) ===
|
|
104
119
|
export async function handleCheckInvariant(args) {
|
|
105
120
|
const db = await ensureAnalyzed();
|
|
106
121
|
const { rule, name: description } = args;
|
|
@@ -109,28 +124,35 @@ export async function handleCheckInvariant(args) {
|
|
|
109
124
|
}
|
|
110
125
|
try {
|
|
111
126
|
const checkFn = db.checkGuarantee;
|
|
112
|
-
const violations = await checkFn(rule);
|
|
127
|
+
const violations = await checkFn.call(db, rule);
|
|
113
128
|
const total = violations.length;
|
|
114
129
|
if (total === 0) {
|
|
115
|
-
return textResult(
|
|
130
|
+
return textResult(`Invariant holds: ${description || 'No violations found'}`);
|
|
116
131
|
}
|
|
117
132
|
const enrichedViolations = [];
|
|
118
133
|
for (const v of violations.slice(0, 20)) {
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
const node = await db.getNode(
|
|
134
|
+
const xBinding = v.bindings?.find((b) => b.name === 'X');
|
|
135
|
+
if (xBinding) {
|
|
136
|
+
const node = await db.getNode(xBinding.value);
|
|
122
137
|
if (node) {
|
|
123
138
|
enrichedViolations.push({
|
|
124
|
-
id:
|
|
139
|
+
id: xBinding.value,
|
|
125
140
|
type: node.type,
|
|
126
141
|
name: node.name,
|
|
127
142
|
file: node.file,
|
|
128
143
|
line: node.line,
|
|
129
144
|
});
|
|
130
145
|
}
|
|
146
|
+
else {
|
|
147
|
+
const bindingsMap = {};
|
|
148
|
+
for (const b of v.bindings) {
|
|
149
|
+
bindingsMap[b.name] = b.value;
|
|
150
|
+
}
|
|
151
|
+
enrichedViolations.push(bindingsMap);
|
|
152
|
+
}
|
|
131
153
|
}
|
|
132
154
|
}
|
|
133
|
-
return textResult(
|
|
155
|
+
return textResult(`${total} violation(s) found:\n\n${JSON.stringify(serializeBigInt(enrichedViolations), null, 2)}${total > 20 ? `\n\n... and ${total - 20} more` : ''}`);
|
|
134
156
|
}
|
|
135
157
|
catch (error) {
|
|
136
158
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataflow-handlers.js","sourceRoot":"","sources":["../../src/handlers/dataflow-handlers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dataflow-handlers.js","sourceRoot":"","sources":["../../src/handlers/dataflow-handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentation-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/documentation-handlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAIrB,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"documentation-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/documentation-handlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAIrB,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,CA+H5F"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Documentation Handlers
|
|
3
3
|
*/
|
|
4
|
-
import { getOnboardingInstruction } from '@grafema/
|
|
4
|
+
import { getOnboardingInstruction } from '@grafema/util';
|
|
5
5
|
import { textResult, } from '../utils.js';
|
|
6
6
|
// === DOCUMENTATION ===
|
|
7
7
|
export async function handleGetDocumentation(args) {
|
|
@@ -31,7 +31,7 @@ Grafema is a static code analyzer that builds a graph of your codebase.
|
|
|
31
31
|
violation(X) :- node(X, "TYPE"), attr(X, "name", "value").
|
|
32
32
|
|
|
33
33
|
## Available Predicates
|
|
34
|
-
-
|
|
34
|
+
- type(Id, Type) - match nodes (alias: node)
|
|
35
35
|
- edge(Src, Dst, Type) - match edges
|
|
36
36
|
- attr(Id, Name, Value) - match attributes
|
|
37
37
|
- \\+ - negation (not)
|
|
@@ -71,6 +71,60 @@ Use check_guarantees to verify all guarantees.
|
|
|
71
71
|
## Example
|
|
72
72
|
Name: no-eval
|
|
73
73
|
Rule: violation(X) :- node(X, "CALL"), attr(X, "name", "eval").
|
|
74
|
+
`,
|
|
75
|
+
notation: `
|
|
76
|
+
# Grafema DSL — Compact Visual Notation
|
|
77
|
+
|
|
78
|
+
Grafema DSL renders graph structure as compact, readable notation.
|
|
79
|
+
Output-only — Datalog remains the query language.
|
|
80
|
+
|
|
81
|
+
## Archetypes & Operators
|
|
82
|
+
|
|
83
|
+
| Archetype | Op | Meaning | Example edge types |
|
|
84
|
+
|------------|-------|---------------------------|---------------------------------------|
|
|
85
|
+
| contains | (nest)| structural containment | CONTAINS, HAS_MEMBER, DECLARES |
|
|
86
|
+
| depends | o- | dependency / import | DEPENDS_ON, IMPORTS_FROM, USES |
|
|
87
|
+
| flow_out | > | outward call / data flow | CALLS, ROUTES_TO, PASSES_ARGUMENT |
|
|
88
|
+
| flow_in | < | inward data / type flow | READS_FROM, ASSIGNED_FROM, EXTENDS |
|
|
89
|
+
| write | => | persistent side effect | WRITES_TO, LOGS_TO |
|
|
90
|
+
| exception | >x | error / rejection | THROWS, REJECTS, CATCHES_FROM |
|
|
91
|
+
| publishes | ~>> | event / message | EMITS_EVENT, PUBLISHES_TO, EXPOSED_VIA|
|
|
92
|
+
| gates | ?| | conditional guard | HAS_CONDITION, HAS_CASE |
|
|
93
|
+
| governs | |= | governance / invariant | GOVERNS, VIOLATES, MONITORED_BY |
|
|
94
|
+
|
|
95
|
+
## LOD Levels (depth)
|
|
96
|
+
|
|
97
|
+
- **depth=0**: Node names only — minimal overview
|
|
98
|
+
- **depth=1** (default): Node + edges — shows all relationships with operators
|
|
99
|
+
- **depth=2**: Node + edges + nested children, **folded** — repetitive siblings compressed into exemplar + summary. Ideal for large modules (e.g., 36 handler imports → 1 exemplar + fold summary)
|
|
100
|
+
- **depth=3**: Node + edges + nested children, **exact** — every node expanded individually, no folding. Use when you need the precise bijective DSL output
|
|
101
|
+
|
|
102
|
+
## Perspective Presets
|
|
103
|
+
|
|
104
|
+
| Preset | Archetypes shown | Use case |
|
|
105
|
+
|----------|-------------------------------|---------------------------|
|
|
106
|
+
| security | write, exception | Audit side effects & errors|
|
|
107
|
+
| data | flow_out, flow_in, write | Trace data movement |
|
|
108
|
+
| errors | exception | Error handling review |
|
|
109
|
+
| api | flow_out, publishes, depends | API surface analysis |
|
|
110
|
+
| events | publishes | Event flow mapping |
|
|
111
|
+
|
|
112
|
+
## Special Modifiers
|
|
113
|
+
|
|
114
|
+
- \`??\` — uncertain/dynamic (unresolved call, dynamic import)
|
|
115
|
+
- \`[]\` — inside loop (edge occurs within iteration)
|
|
116
|
+
|
|
117
|
+
## Budget
|
|
118
|
+
|
|
119
|
+
Default budget: 7 items per group. When exceeded, remaining items are
|
|
120
|
+
summarized as \`+N more\`. Override with budget parameter.
|
|
121
|
+
|
|
122
|
+
## Usage
|
|
123
|
+
|
|
124
|
+
**MCP:** \`describe(target="src/app.ts->FUNCTION->main", depth=1, perspective="security")\`
|
|
125
|
+
**CLI:** \`grafema describe "src/app.ts->FUNCTION->main" -d 1 --perspective security\`
|
|
126
|
+
|
|
127
|
+
Target resolution order: semantic ID → file path (MODULE) → node name.
|
|
74
128
|
`,
|
|
75
129
|
};
|
|
76
130
|
const content = docs[topic] || docs.overview;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentation-handlers.js","sourceRoot":"","sources":["../../src/handlers/documentation-handlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EACL,UAAU,GACX,MAAM,aAAa,CAAC;AAMrB,wBAAwB;AAExB,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAA0B;IACrE,MAAM,EAAE,KAAK,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IAEpC,MAAM,IAAI,GAA2B;QACnC,UAAU,EAAE,wBAAwB,EAAE;QACtC,QAAQ,EAAE;;;;;;;;;;;;;;;CAeb;QACG,OAAO,EAAE;;;;;;;;;;;;;;;;;;CAkBZ;QACG,KAAK,EAAE;;;;;;;;;;;;;CAaV;QACG,UAAU,EAAE;;;;;;;;;;;;;;CAcf;KACE,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC7C,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"documentation-handlers.js","sourceRoot":"","sources":["../../src/handlers/documentation-handlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EACL,UAAU,GACX,MAAM,aAAa,CAAC;AAMrB,wBAAwB;AAExB,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAA0B;IACrE,MAAM,EAAE,KAAK,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IAEpC,MAAM,IAAI,GAA2B;QACnC,UAAU,EAAE,wBAAwB,EAAE;QACtC,QAAQ,EAAE;;;;;;;;;;;;;;;CAeb;QACG,OAAO,EAAE;;;;;;;;;;;;;;;;;;CAkBZ;QACG,KAAK,EAAE;;;;;;;;;;;;;CAaV;QACG,UAAU,EAAE;;;;;;;;;;;;;;CAcf;QACG,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDb;KACE,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC7C,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph traversal handlers: get_node, get_neighbors, traverse_graph
|
|
3
|
+
* REG-521: Add raw graph traversal primitives to MCP
|
|
4
|
+
*/
|
|
5
|
+
import type { ToolResult, GetNodeArgs, GetNeighborsArgs, TraverseGraphArgs } from '../types.js';
|
|
6
|
+
import type { EdgeType, EdgeRecord } from '@grafema/types';
|
|
7
|
+
/**
|
|
8
|
+
* Minimal backend interface for graph-handler logic functions.
|
|
9
|
+
* Allows testing with mock backends without importing full GraphBackend.
|
|
10
|
+
*/
|
|
11
|
+
interface GraphBackendLike {
|
|
12
|
+
getNode(id: string): Promise<Record<string, unknown> | null>;
|
|
13
|
+
getOutgoingEdges(nodeId: string, edgeTypes?: EdgeType[] | null): Promise<EdgeRecord[]>;
|
|
14
|
+
getIncomingEdges(nodeId: string, edgeTypes?: EdgeType[] | null): Promise<EdgeRecord[]>;
|
|
15
|
+
}
|
|
16
|
+
export declare function getNodeLogic(db: GraphBackendLike, args: GetNodeArgs): Promise<ToolResult>;
|
|
17
|
+
export declare function getNeighborsLogic(db: GraphBackendLike, args: GetNeighborsArgs): Promise<ToolResult>;
|
|
18
|
+
export declare function traverseGraphLogic(db: GraphBackendLike, args: TraverseGraphArgs): Promise<ToolResult>;
|
|
19
|
+
export declare function handleGetNode(args: GetNodeArgs): Promise<ToolResult>;
|
|
20
|
+
export declare function handleGetNeighbors(args: GetNeighborsArgs): Promise<ToolResult>;
|
|
21
|
+
export declare function handleTraverseGraph(args: TraverseGraphArgs): Promise<ToolResult>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=graph-handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/graph-handlers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAK3D;;;GAGG;AACH,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7D,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACvF,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CACxF;AA4BD,wBAAsB,YAAY,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAkB/F;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAkCzG;AAED,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAwE3G;AAoBD,wBAAsB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAG1E;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAGpF;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAGtF"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph traversal handlers: get_node, get_neighbors, traverse_graph
|
|
3
|
+
* REG-521: Add raw graph traversal primitives to MCP
|
|
4
|
+
*/
|
|
5
|
+
import { ensureAnalyzed } from '../analysis.js';
|
|
6
|
+
import { textResult, errorResult } from '../utils.js';
|
|
7
|
+
import { isGrafemaUri, toCompactSemanticId } from '@grafema/util';
|
|
8
|
+
const MAX_TRAVERSAL_RESULTS = 10_000;
|
|
9
|
+
const MAX_DEPTH = 20;
|
|
10
|
+
// === Shared helpers ===
|
|
11
|
+
async function groupEdgesByType(edges, db, getNodeId) {
|
|
12
|
+
const grouped = {};
|
|
13
|
+
for (const edge of edges) {
|
|
14
|
+
const type = edge.type;
|
|
15
|
+
if (!grouped[type])
|
|
16
|
+
grouped[type] = [];
|
|
17
|
+
const nodeId = getNodeId(edge);
|
|
18
|
+
const node = await db.getNode(nodeId);
|
|
19
|
+
grouped[type].push({
|
|
20
|
+
id: nodeId,
|
|
21
|
+
...(node ? { type: node.type, name: node.name, file: node.file, line: node.line } : { type: 'UNKNOWN' }),
|
|
22
|
+
...(edge.metadata ? { edgeMetadata: edge.metadata } : {}),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return grouped;
|
|
26
|
+
}
|
|
27
|
+
// === Logic functions (testable, accept backend directly) ===
|
|
28
|
+
export async function getNodeLogic(db, args) {
|
|
29
|
+
const { semanticId } = args;
|
|
30
|
+
if (!semanticId || semanticId.trim() === '') {
|
|
31
|
+
return errorResult('semanticId must be a non-empty string');
|
|
32
|
+
}
|
|
33
|
+
// Accept both grafema:// URI and compact format
|
|
34
|
+
// If URI is passed, convert to compact for error messages
|
|
35
|
+
const displayId = isGrafemaUri(semanticId) ? toCompactSemanticId(semanticId) : semanticId;
|
|
36
|
+
const node = await db.getNode(semanticId);
|
|
37
|
+
if (!node) {
|
|
38
|
+
return errorResult(`Node not found: "${displayId}". Use find_nodes to search by type, name, or file.`);
|
|
39
|
+
}
|
|
40
|
+
return textResult(JSON.stringify(node, null, 2));
|
|
41
|
+
}
|
|
42
|
+
export async function getNeighborsLogic(db, args) {
|
|
43
|
+
const { semanticId, direction = 'both', edgeTypes } = args;
|
|
44
|
+
if (!semanticId || semanticId.trim() === '') {
|
|
45
|
+
return errorResult('semanticId must be a non-empty string');
|
|
46
|
+
}
|
|
47
|
+
if (edgeTypes !== undefined && edgeTypes.length === 0) {
|
|
48
|
+
return errorResult('edgeTypes must not be an empty array. Omit edgeTypes to get all edge types.');
|
|
49
|
+
}
|
|
50
|
+
// Accept both grafema:// URI and compact format
|
|
51
|
+
const displayId = isGrafemaUri(semanticId) ? toCompactSemanticId(semanticId) : semanticId;
|
|
52
|
+
const node = await db.getNode(semanticId);
|
|
53
|
+
if (!node) {
|
|
54
|
+
return errorResult(`Node not found: "${displayId}". Use find_nodes to search by type, name, or file.`);
|
|
55
|
+
}
|
|
56
|
+
const edgeFilter = edgeTypes ?? null;
|
|
57
|
+
const result = {};
|
|
58
|
+
if (direction === 'outgoing' || direction === 'both') {
|
|
59
|
+
const edges = await db.getOutgoingEdges(semanticId, edgeFilter);
|
|
60
|
+
result.outgoing = await groupEdgesByType(edges, db, (e) => e.dst);
|
|
61
|
+
}
|
|
62
|
+
if (direction === 'incoming' || direction === 'both') {
|
|
63
|
+
const edges = await db.getIncomingEdges(semanticId, edgeFilter);
|
|
64
|
+
result.incoming = await groupEdgesByType(edges, db, (e) => e.src);
|
|
65
|
+
}
|
|
66
|
+
return textResult(JSON.stringify(result, null, 2));
|
|
67
|
+
}
|
|
68
|
+
export async function traverseGraphLogic(db, args) {
|
|
69
|
+
const { startNodeIds, edgeTypes, maxDepth = 5, direction = 'outgoing' } = args;
|
|
70
|
+
// Validate inputs
|
|
71
|
+
if (!startNodeIds || startNodeIds.length === 0) {
|
|
72
|
+
return errorResult('startNodeIds must not be empty');
|
|
73
|
+
}
|
|
74
|
+
if (!edgeTypes || edgeTypes.length === 0) {
|
|
75
|
+
return errorResult('edgeTypes must not be empty. Use get_schema(type="edges") to see available types.');
|
|
76
|
+
}
|
|
77
|
+
if (!Number.isInteger(maxDepth) || maxDepth < 0) {
|
|
78
|
+
return errorResult('maxDepth must be a non-negative integer');
|
|
79
|
+
}
|
|
80
|
+
if (maxDepth > MAX_DEPTH) {
|
|
81
|
+
return errorResult(`maxDepth must be <= ${MAX_DEPTH} to prevent performance issues`);
|
|
82
|
+
}
|
|
83
|
+
// Deduplicate start nodes
|
|
84
|
+
const uniqueStartIds = [...new Set(startNodeIds)];
|
|
85
|
+
// Verify start nodes exist
|
|
86
|
+
for (const id of uniqueStartIds) {
|
|
87
|
+
const node = await db.getNode(id);
|
|
88
|
+
if (!node) {
|
|
89
|
+
// Accept both grafema:// URI and compact format for display
|
|
90
|
+
const displayId = isGrafemaUri(id) ? toCompactSemanticId(id) : id;
|
|
91
|
+
return errorResult(`Start node not found: "${displayId}". Use find_nodes to search by type, name, or file.`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const edgeFilter = edgeTypes;
|
|
95
|
+
// Manual BFS (works for both directions, provides depth info)
|
|
96
|
+
const visited = new Set(uniqueStartIds);
|
|
97
|
+
const queue = uniqueStartIds.map(id => ({ id, depth: 0 }));
|
|
98
|
+
const results = uniqueStartIds.map(id => ({ id, depth: 0 }));
|
|
99
|
+
while (queue.length > 0) {
|
|
100
|
+
const current = queue.shift();
|
|
101
|
+
if (current.depth >= maxDepth)
|
|
102
|
+
continue;
|
|
103
|
+
const edges = direction === 'outgoing'
|
|
104
|
+
? await db.getOutgoingEdges(current.id, edgeFilter)
|
|
105
|
+
: await db.getIncomingEdges(current.id, edgeFilter);
|
|
106
|
+
for (const edge of edges) {
|
|
107
|
+
const neighborId = direction === 'outgoing' ? edge.dst : edge.src;
|
|
108
|
+
if (!visited.has(neighborId)) {
|
|
109
|
+
visited.add(neighborId);
|
|
110
|
+
const nextDepth = current.depth + 1;
|
|
111
|
+
queue.push({ id: neighborId, depth: nextDepth });
|
|
112
|
+
results.push({ id: neighborId, depth: nextDepth });
|
|
113
|
+
if (results.length >= MAX_TRAVERSAL_RESULTS) {
|
|
114
|
+
const nodes = await enrichResults(db, results);
|
|
115
|
+
return textResult(JSON.stringify({
|
|
116
|
+
count: nodes.length,
|
|
117
|
+
truncated: true,
|
|
118
|
+
message: `Traversal hit limit of ${MAX_TRAVERSAL_RESULTS} nodes. Use more specific edge types or lower maxDepth.`,
|
|
119
|
+
nodes,
|
|
120
|
+
}, null, 2));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const nodes = await enrichResults(db, results);
|
|
126
|
+
return textResult(JSON.stringify({
|
|
127
|
+
count: nodes.length,
|
|
128
|
+
truncated: false,
|
|
129
|
+
nodes,
|
|
130
|
+
}, null, 2));
|
|
131
|
+
}
|
|
132
|
+
async function enrichResults(db, results) {
|
|
133
|
+
return Promise.all(results.map(async ({ id, depth }) => {
|
|
134
|
+
const node = await db.getNode(id);
|
|
135
|
+
return {
|
|
136
|
+
id,
|
|
137
|
+
depth,
|
|
138
|
+
...(node ? { type: node.type, name: node.name, file: node.file, line: node.line } : { type: 'UNKNOWN' }),
|
|
139
|
+
};
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
// === Public handlers (call ensureAnalyzed, used by MCP routing) ===
|
|
143
|
+
export async function handleGetNode(args) {
|
|
144
|
+
const db = await ensureAnalyzed();
|
|
145
|
+
return getNodeLogic(db, args);
|
|
146
|
+
}
|
|
147
|
+
export async function handleGetNeighbors(args) {
|
|
148
|
+
const db = await ensureAnalyzed();
|
|
149
|
+
return getNeighborsLogic(db, args);
|
|
150
|
+
}
|
|
151
|
+
export async function handleTraverseGraph(args) {
|
|
152
|
+
const db = await ensureAnalyzed();
|
|
153
|
+
return traverseGraphLogic(db, args);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=graph-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-handlers.js","sourceRoot":"","sources":["../../src/handlers/graph-handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL query handler — execute GraphQL queries against the code graph.
|
|
3
|
+
*
|
|
4
|
+
* Uses @grafema/api's schema and resolvers in-process via graphql-yoga.
|
|
5
|
+
* No HTTP server needed — yoga.fetch() accepts synthetic Request objects.
|
|
6
|
+
*/
|
|
7
|
+
import type { ToolResult, GraphQLQueryArgs } from '../types.js';
|
|
8
|
+
export declare function handleGraphQLQuery(args: GraphQLQueryArgs): Promise<ToolResult>;
|
|
9
|
+
//# sourceMappingURL=graphql-handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/graphql-handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsBhE,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAsCpF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL query handler — execute GraphQL queries against the code graph.
|
|
3
|
+
*
|
|
4
|
+
* Uses @grafema/api's schema and resolvers in-process via graphql-yoga.
|
|
5
|
+
* No HTTP server needed — yoga.fetch() accepts synthetic Request objects.
|
|
6
|
+
*/
|
|
7
|
+
import { ensureAnalyzed } from '../analysis.js';
|
|
8
|
+
import { textResult, errorResult } from '../utils.js';
|
|
9
|
+
let yogaInstance = null;
|
|
10
|
+
let yogaBackend = null;
|
|
11
|
+
/**
|
|
12
|
+
* Get or create the yoga instance.
|
|
13
|
+
* Recreated if the backend changes (e.g., after re-analysis).
|
|
14
|
+
*/
|
|
15
|
+
async function getYoga(backend) {
|
|
16
|
+
if (yogaInstance && yogaBackend === backend) {
|
|
17
|
+
return yogaInstance;
|
|
18
|
+
}
|
|
19
|
+
// Dynamic import to avoid loading graphql-yoga unless needed
|
|
20
|
+
const { createGraphQLServer } = await import('@grafema/api');
|
|
21
|
+
yogaInstance = createGraphQLServer({ backend });
|
|
22
|
+
yogaBackend = backend;
|
|
23
|
+
return yogaInstance;
|
|
24
|
+
}
|
|
25
|
+
export async function handleGraphQLQuery(args) {
|
|
26
|
+
const { query, variables, operationName } = args;
|
|
27
|
+
if (!query || query.trim() === '') {
|
|
28
|
+
return errorResult('query must be a non-empty GraphQL query string');
|
|
29
|
+
}
|
|
30
|
+
const db = await ensureAnalyzed();
|
|
31
|
+
const yoga = await getYoga(db);
|
|
32
|
+
// Build the GraphQL request body
|
|
33
|
+
const body = { query };
|
|
34
|
+
if (variables)
|
|
35
|
+
body.variables = variables;
|
|
36
|
+
if (operationName)
|
|
37
|
+
body.operationName = operationName;
|
|
38
|
+
// Execute via yoga.fetch() — no HTTP server needed
|
|
39
|
+
const response = await yoga.fetch('http://localhost/graphql', {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers: { 'Content-Type': 'application/json' },
|
|
42
|
+
body: JSON.stringify(body),
|
|
43
|
+
});
|
|
44
|
+
const result = await response.json();
|
|
45
|
+
// Format output
|
|
46
|
+
if (result.errors && result.errors.length > 0) {
|
|
47
|
+
const errorMessages = result.errors.map((e) => e.message).join('\n');
|
|
48
|
+
if (result.data) {
|
|
49
|
+
// Partial success — return data with errors noted
|
|
50
|
+
return textResult(`GraphQL partial result (with errors):\n${errorMessages}\n\n` +
|
|
51
|
+
JSON.stringify(result.data, null, 2));
|
|
52
|
+
}
|
|
53
|
+
return errorResult(`GraphQL errors:\n${errorMessages}`);
|
|
54
|
+
}
|
|
55
|
+
return textResult(JSON.stringify(result.data, null, 2));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=graphql-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql-handlers.js","sourceRoot":"","sources":["../../src/handlers/graphql-handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAItD,IAAI,YAAY,GAAQ,IAAI,CAAC;AAC7B,IAAI,WAAW,GAA6B,IAAI,CAAC;AAEjD;;;GAGG;AACH,KAAK,UAAU,OAAO,CAAC,OAA0B;IAC/C,IAAI,YAAY,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;QAC5C,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,6DAA6D;IAC7D,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IAC7D,YAAY,GAAG,mBAAmB,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAChD,WAAW,GAAG,OAAO,CAAC;IACtB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAsB;IAC7D,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAEjD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAClC,OAAO,WAAW,CAAC,gDAAgD,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,EAAuB,CAAC,CAAC;IAEpD,iCAAiC;IACjC,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,CAAC;IAChD,IAAI,SAAS;QAAE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC1C,IAAI,aAAa;QAAE,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IAEtD,mDAAmD;IACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,0BAA0B,EAAE;QAC5D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAErC,gBAAgB;IAChB,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,kDAAkD;YAClD,OAAO,UAAU,CACf,0CAA0C,aAAa,MAAM;gBAC7D,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CACrC,CAAC;QACJ,CAAC;QACD,OAAO,WAAW,CAAC,oBAAoB,aAAa,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { getOrCreateBackend, getGuaranteeManager, getGuaranteeAPI } from '../state.js';
|
|
5
5
|
import { textResult, errorResult, } from '../utils.js';
|
|
6
|
-
import { isGuaranteeType } from '@grafema/
|
|
6
|
+
import { isGuaranteeType } from '@grafema/util';
|
|
7
7
|
// === GUARANTEE HANDLERS ===
|
|
8
8
|
/**
|
|
9
9
|
* Create a new guarantee (Datalog-based or contract-based)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/guard-handlers.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"guard-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/guard-handlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EAEf,MAAM,aAAa,CAAC;AAIrB;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CA4EhF"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { getOrCreateBackend } from '../state.js';
|
|
5
5
|
import { serializeBigInt, textResult, errorResult, } from '../utils.js';
|
|
6
|
+
import { isGrafemaUri, toCompactSemanticId } from '@grafema/util';
|
|
6
7
|
// === FIND GUARDS (REG-274) ===
|
|
7
8
|
/**
|
|
8
9
|
* Find conditional guards protecting a node.
|
|
@@ -15,10 +16,12 @@ import { serializeBigInt, textResult, errorResult, } from '../utils.js';
|
|
|
15
16
|
export async function handleFindGuards(args) {
|
|
16
17
|
const db = await getOrCreateBackend();
|
|
17
18
|
const { nodeId } = args;
|
|
19
|
+
// Accept both grafema:// URI and compact format
|
|
20
|
+
const displayId = isGrafemaUri(nodeId) ? toCompactSemanticId(nodeId) : nodeId;
|
|
18
21
|
// Verify target node exists
|
|
19
22
|
const targetNode = await db.getNode(nodeId);
|
|
20
23
|
if (!targetNode) {
|
|
21
|
-
return errorResult(`Node not found: ${
|
|
24
|
+
return errorResult(`Node not found: ${displayId}`);
|
|
22
25
|
}
|
|
23
26
|
const guards = [];
|
|
24
27
|
const visited = new Set();
|
|
@@ -60,7 +63,7 @@ export async function handleFindGuards(args) {
|
|
|
60
63
|
currentId = parentId;
|
|
61
64
|
}
|
|
62
65
|
if (guards.length === 0) {
|
|
63
|
-
return textResult(`No guards found for node: ${
|
|
66
|
+
return textResult(`No guards found for node: ${displayId}\n` +
|
|
64
67
|
`The node is not protected by any conditional scope (if/else/switch/etc.).`);
|
|
65
68
|
}
|
|
66
69
|
const summary = guards.map((g, i) => {
|
|
@@ -68,7 +71,7 @@ export async function handleFindGuards(args) {
|
|
|
68
71
|
return `${indent}${i + 1}. ${g.scopeType} at ${g.file}:${g.line}` +
|
|
69
72
|
(g.condition ? `\n${indent} condition: ${g.condition}` : '');
|
|
70
73
|
}).join('\n');
|
|
71
|
-
return textResult(`Found ${guards.length} guard(s) for node: ${
|
|
74
|
+
return textResult(`Found ${guards.length} guard(s) for node: ${displayId}\n` +
|
|
72
75
|
`(inner to outer order)\n\n` +
|
|
73
76
|
summary +
|
|
74
77
|
`\n\n` +
|