@ttsc/graph 0.16.5 → 0.16.6
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/lib/TtscGraphApplication.js +36 -23
- package/lib/TtscGraphApplication.js.map +1 -1
- package/lib/model/loadGraph.js +17 -17
- package/lib/server/accessAliases.js +53 -0
- package/lib/server/accessAliases.js.map +1 -0
- package/lib/server/createServer.js +1133 -634
- package/lib/server/createServer.js.map +1 -1
- package/lib/server/instructions.js +69 -21
- package/lib/server/instructions.js.map +1 -1
- package/lib/server/runDetails.js +413 -0
- package/lib/server/runDetails.js.map +1 -0
- package/lib/server/{runIndex.js → runEntrypoints.js} +91 -26
- package/lib/server/runEntrypoints.js.map +1 -0
- package/lib/server/{runQuery.js → runLookup.js} +102 -15
- package/lib/server/runLookup.js.map +1 -0
- package/lib/server/runOverview.js +31 -21
- package/lib/server/runOverview.js.map +1 -1
- package/lib/server/runTrace.js +133 -38
- package/lib/server/runTrace.js.map +1 -1
- package/lib/structures/{ITtscGraphQuery.js → ITtscGraphDetails.js} +1 -1
- package/lib/structures/ITtscGraphDetails.js.map +1 -0
- package/lib/structures/ITtscGraphEntrypoints.js +3 -0
- package/lib/structures/ITtscGraphEntrypoints.js.map +1 -0
- package/lib/structures/{ITtscGraphExpand.js → ITtscGraphEscape.js} +1 -1
- package/lib/structures/ITtscGraphEscape.js.map +1 -0
- package/lib/structures/{ITtscGraphIndex.js → ITtscGraphLookup.js} +1 -1
- package/lib/structures/ITtscGraphLookup.js.map +1 -0
- package/lib/structures/index.js +4 -3
- package/lib/structures/index.js.map +1 -1
- package/package.json +2 -2
- package/src/TtscGraphApplication.ts +39 -32
- package/src/server/accessAliases.ts +55 -0
- package/src/server/createServer.ts +4 -7
- package/src/server/instructions.ts +69 -21
- package/src/server/runDetails.ts +469 -0
- package/src/server/{runIndex.ts → runEntrypoints.ts} +109 -34
- package/src/server/{runQuery.ts → runLookup.ts} +123 -16
- package/src/server/runOverview.ts +35 -23
- package/src/server/runTrace.ts +164 -38
- package/src/structures/ITtscGraphApplication.ts +100 -52
- package/src/structures/ITtscGraphDecorator.ts +12 -14
- package/src/structures/ITtscGraphDetails.ts +134 -0
- package/src/structures/{ITtscGraphIndex.ts → ITtscGraphEntrypoints.ts} +34 -16
- package/src/structures/ITtscGraphEscape.ts +39 -0
- package/src/structures/ITtscGraphEvidence.ts +5 -8
- package/src/structures/ITtscGraphLookup.ts +61 -0
- package/src/structures/ITtscGraphNode.ts +10 -4
- package/src/structures/ITtscGraphOverview.ts +24 -16
- package/src/structures/ITtscGraphTrace.ts +54 -11
- package/src/structures/TtscGraphNodeKind.ts +2 -2
- package/src/structures/index.ts +4 -3
- package/lib/server/runExpand.js +0 -177
- package/lib/server/runExpand.js.map +0 -1
- package/lib/server/runIndex.js.map +0 -1
- package/lib/server/runQuery.js.map +0 -1
- package/lib/structures/ITtscGraphExpand.js.map +0 -1
- package/lib/structures/ITtscGraphIndex.js.map +0 -1
- package/lib/structures/ITtscGraphQuery.js.map +0 -1
- package/src/server/runExpand.ts +0 -186
- package/src/structures/ITtscGraphExpand.ts +0 -85
- package/src/structures/ITtscGraphQuery.ts +0 -49
package/src/server/runTrace.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { TtscGraphMemory } from "../model/TtscGraphMemory";
|
|
2
|
+
import { ITtscGraphEvidence } from "../structures/ITtscGraphEvidence";
|
|
2
3
|
import { ITtscGraphNode } from "../structures/ITtscGraphNode";
|
|
3
4
|
import { ITtscGraphTrace } from "../structures/ITtscGraphTrace";
|
|
5
|
+
import { accessAliasesFor } from "./accessAliases";
|
|
4
6
|
import { resolveGraphHandle } from "./resolveHandle";
|
|
5
|
-
import { signatureOf } from "./
|
|
7
|
+
import { edgeEvidenceOf, edgeEvidenceTextOf, signatureOf } from "./runDetails";
|
|
6
8
|
|
|
7
|
-
const DEFAULT_DEPTH =
|
|
8
|
-
const DEFAULT_MAX_NODES =
|
|
9
|
+
const DEFAULT_DEPTH = 2;
|
|
10
|
+
const DEFAULT_MAX_NODES = 6;
|
|
11
|
+
const MAX_OPEN_DEPTH = 2;
|
|
12
|
+
const MAX_OPEN_NODES = 8;
|
|
13
|
+
const MAX_HOPS_PER_NODE = 1;
|
|
14
|
+
const MAX_STEPS = 6;
|
|
15
|
+
const MAX_NEXT_HANDLES = 2;
|
|
9
16
|
|
|
10
17
|
/**
|
|
11
18
|
* Breadth-first trace along the dependency graph. Structural
|
|
@@ -16,11 +23,13 @@ const DEFAULT_MAX_NODES = 60;
|
|
|
16
23
|
*/
|
|
17
24
|
export function runTrace(
|
|
18
25
|
graph: TtscGraphMemory,
|
|
19
|
-
props: ITtscGraphTrace.
|
|
26
|
+
props: ITtscGraphTrace.IRequest,
|
|
20
27
|
): ITtscGraphTrace {
|
|
21
28
|
const direction = props.direction ?? "forward";
|
|
22
|
-
const
|
|
23
|
-
const
|
|
29
|
+
const focus = props.focus ?? "all";
|
|
30
|
+
const maxDepth = bound(props.maxDepth, DEFAULT_DEPTH, 1, MAX_OPEN_DEPTH);
|
|
31
|
+
const maxNodes = bound(props.maxNodes, DEFAULT_MAX_NODES, 1, MAX_OPEN_NODES);
|
|
32
|
+
const maxHops = maxNodes * MAX_HOPS_PER_NODE;
|
|
24
33
|
const reverse = direction === "reverse" || direction === "impact";
|
|
25
34
|
// Only an impact trace tags reached nodes with their public-surface role; for
|
|
26
35
|
// forward/reverse the role is noise.
|
|
@@ -29,49 +38,62 @@ export function runTrace(
|
|
|
29
38
|
const start = resolveGraphHandle(graph, props.from);
|
|
30
39
|
if (start.candidates) {
|
|
31
40
|
return {
|
|
41
|
+
type: "trace",
|
|
32
42
|
direction,
|
|
33
43
|
hops: [],
|
|
34
44
|
reached: [],
|
|
35
45
|
truncated: false,
|
|
36
|
-
candidates: start.candidates.map((n) => summary(n)),
|
|
46
|
+
candidates: start.candidates.map((n) => summary(graph, n)),
|
|
37
47
|
};
|
|
38
48
|
}
|
|
39
49
|
if (start.node === undefined) {
|
|
40
|
-
return {
|
|
50
|
+
return {
|
|
51
|
+
type: "trace",
|
|
52
|
+
direction,
|
|
53
|
+
hops: [],
|
|
54
|
+
reached: [],
|
|
55
|
+
truncated: false,
|
|
56
|
+
};
|
|
41
57
|
}
|
|
42
58
|
|
|
43
|
-
// Path mode: with `to`, return the dependency path from `from` to `to
|
|
44
|
-
// one-call answer for "how does A reach B"
|
|
59
|
+
// Path mode: with `to`, return the dependency path from `from` to `to`, the
|
|
60
|
+
// one-call answer for "how does A reach B", instead of an open-ended trace.
|
|
45
61
|
if (props.to !== undefined && props.to !== "") {
|
|
46
|
-
const base = {
|
|
62
|
+
const base = {
|
|
63
|
+
type: "trace" as const,
|
|
64
|
+
direction: "path",
|
|
65
|
+
hops: [],
|
|
66
|
+
reached: [],
|
|
67
|
+
truncated: false,
|
|
68
|
+
};
|
|
47
69
|
const target = resolveGraphHandle(graph, props.to);
|
|
48
70
|
if (target.candidates) {
|
|
49
71
|
return {
|
|
50
72
|
...base,
|
|
51
|
-
start: summary(start.node),
|
|
52
|
-
candidates: target.candidates.map((n) => summary(n)),
|
|
73
|
+
start: summary(graph, start.node),
|
|
74
|
+
candidates: target.candidates.map((n) => summary(graph, n)),
|
|
53
75
|
};
|
|
54
76
|
}
|
|
55
77
|
if (target.node === undefined) {
|
|
56
|
-
return { ...base, start: summary(start.node) };
|
|
78
|
+
return { ...base, start: summary(graph, start.node) };
|
|
57
79
|
}
|
|
58
80
|
const found = findPath(
|
|
59
81
|
graph,
|
|
60
82
|
start.node.id,
|
|
61
83
|
target.node.id,
|
|
62
|
-
|
|
84
|
+
bound(props.maxDepth, 12, 1, 12),
|
|
85
|
+
focus,
|
|
63
86
|
);
|
|
87
|
+
const path = found?.path ?? [];
|
|
88
|
+
const hops = found?.hops ?? [];
|
|
64
89
|
return {
|
|
65
90
|
...base,
|
|
66
|
-
start: summary(start.node),
|
|
67
|
-
target: summary(target.node),
|
|
68
|
-
hops
|
|
69
|
-
path:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (sig !== undefined) node_.signature = sig;
|
|
73
|
-
return node_;
|
|
74
|
-
}),
|
|
91
|
+
start: summary(graph, start.node),
|
|
92
|
+
target: summary(graph, target.node),
|
|
93
|
+
hops,
|
|
94
|
+
path: path.map((node, i) => summary(graph, node, i, false, true)),
|
|
95
|
+
steps: traceSteps(graph, hops),
|
|
96
|
+
next: nextFromPath(path),
|
|
75
97
|
};
|
|
76
98
|
}
|
|
77
99
|
|
|
@@ -92,30 +114,42 @@ export function runTrace(
|
|
|
92
114
|
}
|
|
93
115
|
const edges = reverse ? graph.incoming(id) : graph.outgoing(id);
|
|
94
116
|
for (const edge of edges) {
|
|
95
|
-
if (!traversable(edge.kind)) continue;
|
|
117
|
+
if (!traversable(edge.kind, focus)) continue;
|
|
96
118
|
const otherId = reverse ? edge.from : edge.to;
|
|
97
119
|
const other = graph.node(otherId);
|
|
98
120
|
if (other === undefined || other.kind === "file") continue;
|
|
99
|
-
const hop = {
|
|
121
|
+
const hop: ITtscGraphTrace.IHop = {
|
|
100
122
|
from: edge.from,
|
|
101
123
|
to: edge.to,
|
|
102
124
|
kind: edge.kind,
|
|
103
125
|
depth: depth + 1,
|
|
104
126
|
};
|
|
127
|
+
const evidence = edgeEvidenceOf(edge);
|
|
128
|
+
if (evidence !== undefined) hop.evidence = evidence;
|
|
129
|
+
const aliases = accessAliasesFor(
|
|
130
|
+
graph.node(edge.to),
|
|
131
|
+
edgeEvidenceTextOf(edge),
|
|
132
|
+
);
|
|
133
|
+
if (aliases !== undefined) hop.aliases = aliases;
|
|
105
134
|
// A back-edge to the start or an already-reached node: record the hop;
|
|
106
135
|
// its endpoints are already represented.
|
|
107
136
|
if (visited.has(otherId)) {
|
|
108
|
-
hops.
|
|
137
|
+
if (hops.length >= maxHops) truncated = true;
|
|
138
|
+
else hops.push(hop);
|
|
109
139
|
continue;
|
|
110
140
|
}
|
|
111
|
-
// A new node past the cap is left unrepresented, so drop its hop too
|
|
141
|
+
// A new node past the cap is left unrepresented, so drop its hop too:
|
|
112
142
|
// every hop's endpoints stay resolvable in `reached`/`start`.
|
|
113
143
|
if (reached.size >= maxNodes) {
|
|
114
144
|
truncated = true;
|
|
115
145
|
continue;
|
|
116
146
|
}
|
|
147
|
+
if (hops.length >= maxHops) {
|
|
148
|
+
truncated = true;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
117
151
|
visited.add(otherId);
|
|
118
|
-
reached.set(otherId, summary(other, depth + 1, withRoles));
|
|
152
|
+
reached.set(otherId, summary(graph, other, depth + 1, withRoles));
|
|
119
153
|
next.push({ id: otherId, depth: depth + 1 });
|
|
120
154
|
hops.push(hop);
|
|
121
155
|
}
|
|
@@ -124,14 +158,46 @@ export function runTrace(
|
|
|
124
158
|
}
|
|
125
159
|
|
|
126
160
|
return {
|
|
127
|
-
|
|
161
|
+
type: "trace",
|
|
162
|
+
start: summary(graph, start.node),
|
|
128
163
|
direction,
|
|
129
164
|
hops,
|
|
130
165
|
reached: [...reached.values()],
|
|
166
|
+
steps: traceSteps(graph, hops),
|
|
167
|
+
next: {
|
|
168
|
+
details: [start.node.id, ...reached.keys()].slice(0, MAX_NEXT_HANDLES),
|
|
169
|
+
traceFrom: [...reached.keys()].slice(0, MAX_NEXT_HANDLES),
|
|
170
|
+
},
|
|
131
171
|
truncated,
|
|
132
172
|
};
|
|
133
173
|
}
|
|
134
174
|
|
|
175
|
+
function nextFromPath(path: ITtscGraphNode[]): ITtscGraphTrace.INext {
|
|
176
|
+
return {
|
|
177
|
+
details: path.map((node) => node.id),
|
|
178
|
+
traceFrom: path.length > 0 ? [path[path.length - 1]!.id] : [],
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function traceSteps(
|
|
183
|
+
graph: TtscGraphMemory,
|
|
184
|
+
hops: ITtscGraphTrace.IHop[],
|
|
185
|
+
): string[] {
|
|
186
|
+
return hops.slice(0, MAX_STEPS).map((hop) => {
|
|
187
|
+
const from = graph.node(hop.from);
|
|
188
|
+
const to = graph.node(hop.to);
|
|
189
|
+
const lhs = from?.qualifiedName ?? from?.name ?? hop.from;
|
|
190
|
+
const rhs = to?.qualifiedName ?? to?.name ?? hop.to;
|
|
191
|
+
const evidence =
|
|
192
|
+
hop.evidence === undefined
|
|
193
|
+
? ""
|
|
194
|
+
: ` at ${hop.evidence.file}:${hop.evidence.startLine}`;
|
|
195
|
+
const aliases =
|
|
196
|
+
hop.aliases === undefined ? "" : ` aliases ${hop.aliases.join(", ")}`;
|
|
197
|
+
return `${lhs} -[${hop.kind}${evidence}${aliases}]-> ${rhs}`;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
135
201
|
/**
|
|
136
202
|
* The shortest dependency path from `startId` to `targetId` over real (non-
|
|
137
203
|
* structural) forward edges, breadth-first, or null when `targetId` is not
|
|
@@ -142,11 +208,20 @@ function findPath(
|
|
|
142
208
|
startId: string,
|
|
143
209
|
targetId: string,
|
|
144
210
|
maxDepth: number,
|
|
211
|
+
focus: ITtscGraphTrace.IRequest["focus"],
|
|
145
212
|
): { path: ITtscGraphNode[]; hops: ITtscGraphTrace.IHop[] } | null {
|
|
146
213
|
const startNode = graph.node(startId);
|
|
147
214
|
if (startNode === undefined) return null;
|
|
148
215
|
if (startId === targetId) return { path: [startNode], hops: [] };
|
|
149
|
-
const parent = new Map<
|
|
216
|
+
const parent = new Map<
|
|
217
|
+
string,
|
|
218
|
+
{
|
|
219
|
+
via: string;
|
|
220
|
+
kind: string;
|
|
221
|
+
evidence?: ITtscGraphEvidence;
|
|
222
|
+
evidenceText?: string;
|
|
223
|
+
}
|
|
224
|
+
>();
|
|
150
225
|
const visited = new Set<string>([startId]);
|
|
151
226
|
let queue: Array<{ id: string; depth: number }> = [{ id: startId, depth: 0 }];
|
|
152
227
|
while (queue.length > 0) {
|
|
@@ -154,13 +229,19 @@ function findPath(
|
|
|
154
229
|
for (const { id, depth } of queue) {
|
|
155
230
|
if (depth >= maxDepth) continue;
|
|
156
231
|
for (const edge of graph.outgoing(id)) {
|
|
157
|
-
if (!traversable(edge.kind)) continue;
|
|
232
|
+
if (!traversable(edge.kind, focus)) continue;
|
|
158
233
|
const otherId = edge.to;
|
|
159
234
|
if (visited.has(otherId)) continue;
|
|
160
235
|
const other = graph.node(otherId);
|
|
161
236
|
if (other === undefined || other.kind === "file") continue;
|
|
162
237
|
visited.add(otherId);
|
|
163
|
-
|
|
238
|
+
const evidence = edgeEvidenceOf(edge);
|
|
239
|
+
parent.set(otherId, {
|
|
240
|
+
via: id,
|
|
241
|
+
kind: edge.kind,
|
|
242
|
+
evidence,
|
|
243
|
+
evidenceText: edgeEvidenceTextOf(edge),
|
|
244
|
+
});
|
|
164
245
|
if (otherId === targetId) {
|
|
165
246
|
const ids: string[] = [otherId];
|
|
166
247
|
let cur = otherId;
|
|
@@ -178,12 +259,18 @@ function findPath(
|
|
|
178
259
|
const hops: ITtscGraphTrace.IHop[] = [];
|
|
179
260
|
for (let i = 1; i < path.length; i++) {
|
|
180
261
|
const node = path[i]!;
|
|
181
|
-
|
|
262
|
+
const parentEdge = parent.get(node.id);
|
|
263
|
+
const hop: ITtscGraphTrace.IHop = {
|
|
182
264
|
from: path[i - 1]!.id,
|
|
183
265
|
to: node.id,
|
|
184
|
-
kind:
|
|
266
|
+
kind: parentEdge?.kind ?? "calls",
|
|
185
267
|
depth: i,
|
|
186
|
-
}
|
|
268
|
+
};
|
|
269
|
+
if (parentEdge?.evidence !== undefined)
|
|
270
|
+
hop.evidence = parentEdge.evidence;
|
|
271
|
+
const aliases = accessAliasesFor(node, parentEdge?.evidenceText);
|
|
272
|
+
if (aliases !== undefined) hop.aliases = aliases;
|
|
273
|
+
hops.push(hop);
|
|
187
274
|
}
|
|
188
275
|
return { path, hops };
|
|
189
276
|
}
|
|
@@ -200,9 +287,11 @@ function findPath(
|
|
|
200
287
|
* roles (exported / test) an impact trace reports; other directions omit them.
|
|
201
288
|
*/
|
|
202
289
|
function summary(
|
|
290
|
+
graph: TtscGraphMemory,
|
|
203
291
|
node: ITtscGraphNode,
|
|
204
292
|
depth?: number,
|
|
205
293
|
withRoles = false,
|
|
294
|
+
withSignature = false,
|
|
206
295
|
): ITtscGraphTrace.INode {
|
|
207
296
|
const out: ITtscGraphTrace.INode = {
|
|
208
297
|
id: node.id,
|
|
@@ -211,6 +300,10 @@ function summary(
|
|
|
211
300
|
file: node.file,
|
|
212
301
|
};
|
|
213
302
|
if (depth !== undefined) out.depth = depth;
|
|
303
|
+
if (withSignature) {
|
|
304
|
+
const sig = signatureOf(graph.project, node);
|
|
305
|
+
if (sig !== undefined) out.signature = sig;
|
|
306
|
+
}
|
|
214
307
|
if (withRoles) {
|
|
215
308
|
const roles: string[] = [];
|
|
216
309
|
if (node.exported) roles.push("exported");
|
|
@@ -221,8 +314,31 @@ function summary(
|
|
|
221
314
|
}
|
|
222
315
|
|
|
223
316
|
/** An edge the trace should follow: a real dependency, not a structural edge. */
|
|
224
|
-
function traversable(
|
|
225
|
-
|
|
317
|
+
function traversable(
|
|
318
|
+
kind: string,
|
|
319
|
+
focus: ITtscGraphTrace.IRequest["focus"],
|
|
320
|
+
): boolean {
|
|
321
|
+
if (kind === "contains" || kind === "exports" || kind === "imports") {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
if (focus === "execution") {
|
|
325
|
+
return (
|
|
326
|
+
kind === "calls" ||
|
|
327
|
+
kind === "instantiates" ||
|
|
328
|
+
kind === "accesses" ||
|
|
329
|
+
kind === "renders"
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
if (focus === "types") {
|
|
333
|
+
return (
|
|
334
|
+
kind === "type_ref" ||
|
|
335
|
+
kind === "extends" ||
|
|
336
|
+
kind === "implements" ||
|
|
337
|
+
kind === "overrides" ||
|
|
338
|
+
kind === "decorates"
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
return true;
|
|
226
342
|
}
|
|
227
343
|
|
|
228
344
|
function isTestFile(file: string): boolean {
|
|
@@ -231,3 +347,13 @@ function isTestFile(file: string): boolean {
|
|
|
231
347
|
/\.(test|spec)\.[cm]?tsx?$/.test(file)
|
|
232
348
|
);
|
|
233
349
|
}
|
|
350
|
+
|
|
351
|
+
function bound(
|
|
352
|
+
value: number | undefined,
|
|
353
|
+
fallback: number,
|
|
354
|
+
min: number,
|
|
355
|
+
max: number,
|
|
356
|
+
): number {
|
|
357
|
+
const n = value === undefined || !Number.isFinite(value) ? fallback : value;
|
|
358
|
+
return Math.max(min, Math.min(max, Math.floor(n)));
|
|
359
|
+
}
|
|
@@ -1,68 +1,116 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ITtscGraphDetails } from "./ITtscGraphDetails";
|
|
2
|
+
import { ITtscGraphEntrypoints } from "./ITtscGraphEntrypoints";
|
|
3
|
+
import { ITtscGraphEscape } from "./ITtscGraphEscape";
|
|
4
|
+
import { ITtscGraphLookup } from "./ITtscGraphLookup";
|
|
3
5
|
import { ITtscGraphOverview } from "./ITtscGraphOverview";
|
|
4
|
-
import { ITtscGraphQuery } from "./ITtscGraphQuery";
|
|
5
6
|
import { ITtscGraphTrace } from "./ITtscGraphTrace";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* The MCP tool surface of `@ttsc/graph`, as a typed application.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* graph.
|
|
11
|
+
* The single method is the single MCP tool. Its parameter object becomes the
|
|
12
|
+
* JSON schema once `typia.llm.controller` reflects this interface.
|
|
13
|
+
* `TtscGraphApplication` implements it over the resident graph.
|
|
14
14
|
*/
|
|
15
15
|
export interface ITtscGraphApplication {
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
* handles mentioned in the query, declaration signatures, and direct
|
|
19
|
-
* dependency context. Use this before reading source.
|
|
17
|
+
* Query the TypeScript project graph for code evidence.
|
|
20
18
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* The project's architecture — folder layers, dependency hotspots, and the
|
|
28
|
-
* public API. Call first to orient on an unfamiliar codebase.
|
|
19
|
+
* Use this before answering TypeScript codebase questions. It returns
|
|
20
|
+
* checker-resolved symbols, dependency paths, edge evidence ranges, and
|
|
21
|
+
* sourceSpan anchors from the resident graph, avoiding assumptions, shell
|
|
22
|
+
* search, or file reads when graph evidence is enough.
|
|
29
23
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
|
|
33
|
-
graph_overview(props: ITtscGraphOverview.IProps): ITtscGraphOverview;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* The declared shape of the given symbols: each one's signature, and for a
|
|
37
|
-
* class/interface/namespace its members. Handles may be ids or dotted symbol
|
|
38
|
-
* names. Set `source: true` to also read a specific body, `neighbors: true`
|
|
39
|
-
* to list what it uses and what uses it.
|
|
24
|
+
* Fill properties in order: question, graphNeed, draft, review, request.
|
|
25
|
+
* Write `draft.reason` before `draft.type`, then choose `entrypoints`,
|
|
26
|
+
* `lookup`, `trace`, `details`, `overview`, or `escape`.
|
|
40
27
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
|
|
44
|
-
graph_expand(props: ITtscGraphExpand.IProps): ITtscGraphExpand;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Find any symbol — class, function, method, or field — by name or
|
|
48
|
-
* description. Each hit comes with its signature, so the query alone often
|
|
49
|
-
* answers the question, and `next.expand` gives handles for source
|
|
50
|
-
* follow-up.
|
|
28
|
+
* Most answers should need 1-3 calls; four is the hard stop for one answer.
|
|
29
|
+
* Keep slices small, prefer defaults, and stop once file/symbol/range
|
|
30
|
+
* evidence is enough.
|
|
51
31
|
*
|
|
52
|
-
* @param props The
|
|
53
|
-
* @returns
|
|
32
|
+
* @param props The reasoning and selected graph request
|
|
33
|
+
* @returns One `result` union member matching the selected request type
|
|
54
34
|
*/
|
|
55
|
-
|
|
35
|
+
query(props: ITtscGraphApplication.IProps): ITtscGraphApplication.IResult;
|
|
36
|
+
}
|
|
56
37
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
38
|
+
export namespace ITtscGraphApplication {
|
|
39
|
+
/** Think, review, then submit exactly one graph request. */
|
|
40
|
+
export interface IProps {
|
|
41
|
+
/**
|
|
42
|
+
* User's TypeScript code question.
|
|
43
|
+
*
|
|
44
|
+
* Restate the codebase question being answered. Keep this about TypeScript
|
|
45
|
+
* source, symbols, call flow, type flow, or architecture. If the user is
|
|
46
|
+
* asking about scripts, config, generated output, or documentation instead,
|
|
47
|
+
* say that boundary here.
|
|
48
|
+
*/
|
|
49
|
+
question: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Why the resident graph is the next evidence source.
|
|
53
|
+
*
|
|
54
|
+
* State what graph evidence is needed and why assumptions or broad shell
|
|
55
|
+
* search are not the next step for this call. Name the smallest evidence
|
|
56
|
+
* that would let the agent stop. If graph is not actually the right source,
|
|
57
|
+
* say that and use `escape`.
|
|
58
|
+
*/
|
|
59
|
+
graphNeed: string;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* First request-type decision before arguments are filled.
|
|
63
|
+
*
|
|
64
|
+
* Explain why one operation class is smaller than the alternatives, then
|
|
65
|
+
* name it in `draft.type`. This is only the draft; the final arguments are
|
|
66
|
+
* in `request` after `review`.
|
|
67
|
+
*/
|
|
68
|
+
draft: IRequestDraft;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Critical review of the draft request.
|
|
72
|
+
*
|
|
73
|
+
* Check whether the draft avoids overfetch, non-graph fallback, broad
|
|
74
|
+
* reads, and unnecessary neighbor expansion. If this would be a fourth
|
|
75
|
+
* broad lookup, trace, or details call, prefer answering from evidence in
|
|
76
|
+
* hand or choose `escape`. Do not spend graph calls only to hunt for tests.
|
|
77
|
+
* If the draft is wrong, choose the corrected type in `request`.
|
|
78
|
+
*/
|
|
79
|
+
review: string;
|
|
80
|
+
|
|
81
|
+
/** The graph operation chosen from the reasoning above, or a no-op escape. */
|
|
82
|
+
request:
|
|
83
|
+
| ITtscGraphEntrypoints.IRequest
|
|
84
|
+
| ITtscGraphLookup.IRequest
|
|
85
|
+
| ITtscGraphTrace.IRequest
|
|
86
|
+
| ITtscGraphDetails.IRequest
|
|
87
|
+
| ITtscGraphOverview.IRequest
|
|
88
|
+
| ITtscGraphEscape.IRequest;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** First-pass operation choice before final request arguments. */
|
|
92
|
+
export interface IRequestDraft {
|
|
93
|
+
/** Why this operation type is the smallest useful next step. */
|
|
94
|
+
reason: string;
|
|
95
|
+
|
|
96
|
+
/** Draft discriminator for the intended graph operation. */
|
|
97
|
+
type:
|
|
98
|
+
| ITtscGraphEntrypoints.IRequest["type"]
|
|
99
|
+
| ITtscGraphLookup.IRequest["type"]
|
|
100
|
+
| ITtscGraphTrace.IRequest["type"]
|
|
101
|
+
| ITtscGraphDetails.IRequest["type"]
|
|
102
|
+
| ITtscGraphOverview.IRequest["type"]
|
|
103
|
+
| ITtscGraphEscape.IRequest["type"];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The selected request's output. `result.type` mirrors `request.type`. */
|
|
107
|
+
export interface IResult {
|
|
108
|
+
result:
|
|
109
|
+
| ITtscGraphEntrypoints
|
|
110
|
+
| ITtscGraphLookup
|
|
111
|
+
| ITtscGraphTrace
|
|
112
|
+
| ITtscGraphDetails
|
|
113
|
+
| ITtscGraphOverview
|
|
114
|
+
| ITtscGraphEscape;
|
|
115
|
+
}
|
|
68
116
|
}
|
|
@@ -1,32 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A decorator as written on a declaration, carried on the decorated
|
|
3
|
-
* {@link ITtscGraphNode}'s `decorators`.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* {@link ITtscGraphNode}'s `decorators`.
|
|
4
|
+
*
|
|
5
|
+
* The graph reports the decorator faithfully rather than interpreting any
|
|
6
|
+
* framework's convention: the `name` is the decorator as written (`Controller`,
|
|
7
|
+
* `Get`, `TypedRoute.Get`, ...), and statically resolvable literal arguments
|
|
8
|
+
* are preserved so a consumer can apply its own meaning without re-parsing
|
|
9
|
+
* source.
|
|
8
10
|
*/
|
|
9
11
|
export interface ITtscGraphDecorator {
|
|
10
12
|
/**
|
|
11
|
-
* The decorator name as written, qualified through its access path
|
|
13
|
+
* The decorator name as written, qualified through its access path:
|
|
12
14
|
* `Controller`, `Get`, `TypedRoute.Get`, `MessagePattern`.
|
|
13
15
|
*/
|
|
14
16
|
name: string;
|
|
15
17
|
|
|
16
|
-
/** The call arguments, in source order. Empty for a bare decorator. */
|
|
18
|
+
/** The literal call arguments, in source order. Empty for a bare decorator. */
|
|
17
19
|
arguments: ITtscGraphDecorator.IArgument[];
|
|
18
20
|
}
|
|
19
21
|
export namespace ITtscGraphDecorator {
|
|
20
22
|
/**
|
|
21
|
-
* One argument of an {@link ITtscGraphDecorator}. `
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* so a consumer can use it without evaluating code.
|
|
23
|
+
* One argument of an {@link ITtscGraphDecorator}. `literal` is set only when
|
|
24
|
+
* the argument is a string, number, or boolean literal the producer could
|
|
25
|
+
* resolve statically, so a consumer can use it without evaluating code.
|
|
25
26
|
*/
|
|
26
27
|
export interface IArgument {
|
|
27
|
-
/** The argument expression's source text. */
|
|
28
|
-
text: string;
|
|
29
|
-
|
|
30
28
|
/** The statically-resolved literal value, when the argument is a literal. */
|
|
31
29
|
literal?: string | number | boolean;
|
|
32
30
|
}
|