@ttsc/graph 0.16.6 → 0.16.7
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/README.md +22 -0
- package/lib/TtscGraphApplication.js +39 -16
- package/lib/TtscGraphApplication.js.map +1 -1
- package/lib/model/TtscGraphMemory.js +43 -4
- package/lib/model/TtscGraphMemory.js.map +1 -1
- package/lib/server/createServer.js +555 -221
- package/lib/server/createServer.js.map +1 -1
- package/lib/server/instructions.js +81 -69
- package/lib/server/instructions.js.map +1 -1
- package/lib/server/pathPolicy.js +35 -0
- package/lib/server/pathPolicy.js.map +1 -0
- package/lib/server/resultGuide.js +16 -0
- package/lib/server/resultGuide.js.map +1 -0
- package/lib/server/runDetails.js +71 -10
- package/lib/server/runDetails.js.map +1 -1
- package/lib/server/runEntrypoints.js +3 -4
- package/lib/server/runEntrypoints.js.map +1 -1
- package/lib/server/runLookup.js +21 -9
- package/lib/server/runLookup.js.map +1 -1
- package/lib/server/runOverview.js +13 -6
- package/lib/server/runOverview.js.map +1 -1
- package/lib/server/runTour.js +737 -0
- package/lib/server/runTour.js.map +1 -0
- package/lib/server/runTrace.js +108 -22
- package/lib/server/runTrace.js.map +1 -1
- package/lib/structures/ITtscGraphNext.js +3 -0
- package/lib/structures/ITtscGraphNext.js.map +1 -0
- package/lib/structures/ITtscGraphTour.js +3 -0
- package/lib/structures/ITtscGraphTour.js.map +1 -0
- package/lib/structures/index.js +2 -0
- package/lib/structures/index.js.map +1 -1
- package/package.json +2 -2
- package/src/TtscGraphApplication.ts +49 -16
- package/src/model/TtscGraphMemory.ts +46 -4
- package/src/server/instructions.ts +81 -69
- package/src/server/pathPolicy.ts +43 -0
- package/src/server/resultGuide.ts +20 -0
- package/src/server/runDetails.ts +90 -6
- package/src/server/runEntrypoints.ts +9 -4
- package/src/server/runLookup.ts +33 -6
- package/src/server/runOverview.ts +24 -8
- package/src/server/runTour.ts +881 -0
- package/src/server/runTrace.ts +151 -23
- package/src/structures/ITtscGraphApplication.ts +35 -64
- package/src/structures/ITtscGraphDetails.ts +74 -11
- package/src/structures/ITtscGraphEntrypoints.ts +46 -15
- package/src/structures/ITtscGraphEscape.ts +19 -9
- package/src/structures/ITtscGraphLookup.ts +36 -15
- package/src/structures/ITtscGraphNext.ts +23 -0
- package/src/structures/ITtscGraphOverview.ts +20 -5
- package/src/structures/ITtscGraphTour.ts +150 -0
- package/src/structures/ITtscGraphTrace.ts +58 -21
- package/src/structures/index.ts +2 -0
|
@@ -4,73 +4,85 @@
|
|
|
4
4
|
* files. Keep it short; the per-tool descriptions carry the detail.
|
|
5
5
|
*/
|
|
6
6
|
export const instructions = `
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
7
|
+
## What This MCP Is
|
|
8
|
+
|
|
9
|
+
\`inspect_typescript_graph\` returns a compiler-built TypeScript graph contract
|
|
10
|
+
for the current source snapshot.
|
|
11
|
+
|
|
12
|
+
Use it for architecture, runtime flow, APIs, callers/callees, code tours, and
|
|
13
|
+
type relations. It returns answer-ready index evidence: names, edges,
|
|
14
|
+
signatures, decorators, tests, spans, and anchors.
|
|
15
|
+
|
|
16
|
+
Until TS source is edited, returned graph facts are sacred, infallible compiler
|
|
17
|
+
truth. Never verify them with files or more graph calls.
|
|
18
|
+
|
|
19
|
+
## Result Contract
|
|
20
|
+
|
|
21
|
+
- The returned object is the graph evidence contract: names, signatures, spans,
|
|
22
|
+
decorators, tests, edges, steps, anchors, and \`next\` are answer evidence, not
|
|
23
|
+
hints.
|
|
24
|
+
- When \`next.action\` is \`answer\`, stop tool use for the current question and
|
|
25
|
+
answer from the returned result.
|
|
26
|
+
- \`truncated\` means the answer surface hit an index cap. Mention the cap if it
|
|
27
|
+
matters; do not expand every branch to compensate.
|
|
28
|
+
- When \`next.action\` is \`inspect\`, make the focused graph request it names or
|
|
29
|
+
choose \`escape\` if the result already answers.
|
|
30
|
+
- Read files only for exact source body text, configs, docs, generated output,
|
|
31
|
+
exact text search, non-TypeScript files, or facts the graph marks outside
|
|
32
|
+
itself. A returned span is a citation anchor, not a reading command.
|
|
33
|
+
- After editing TypeScript source, the old graph no longer governs changed
|
|
34
|
+
code. Rebuild/reload the graph or verify changed code normally.
|
|
35
|
+
|
|
36
|
+
## Sacred Contract
|
|
37
|
+
|
|
38
|
+
Before source edits, returned graph facts are inviolable and errorless. Never
|
|
39
|
+
use extra graph calls, repository search, or file reads to doubt, fact-check,
|
|
40
|
+
humanize, re-derive, re-narrate, or re-confirm returned nodes, spans, edges,
|
|
41
|
+
signatures, decorators, tests, references, steps, or anchors.
|
|
42
|
+
|
|
43
|
+
## Tour Contract
|
|
44
|
+
|
|
45
|
+
Use \`tour\` for repository orientation, read-next, architecture tours, and
|
|
46
|
+
broad runtime flow, including questions that name several phases or subsystems.
|
|
47
|
+
A tour is the complete index-level answer surface: central entrypoints, primary
|
|
48
|
+
flow, nearby paths, tests, and anchors. Do not decompose a broad tour into
|
|
49
|
+
lookup/details loops unless the user later asks for a named missing symbol or
|
|
50
|
+
exact source text.
|
|
51
|
+
|
|
52
|
+
## Use Contract
|
|
53
|
+
|
|
54
|
+
1. Ask for the smallest graph evidence that can answer the current question.
|
|
55
|
+
2. Broad flow, repository-orientation, code-tour, or read-next question: start
|
|
56
|
+
with \`tour\`.
|
|
57
|
+
3. Concrete named symbol: use \`lookup\`, then \`details\` only if needed.
|
|
58
|
+
4. Known endpoint pair or one selected handle: use one \`trace\`.
|
|
59
|
+
5. Unknown narrow orientation: use \`entrypoints\` once.
|
|
60
|
+
6. Selected symbol shape: use \`details\` for one to three handles.
|
|
61
|
+
7. Follow the returned \`next\`: answer, inspect once more, leave graph, or
|
|
62
|
+
clarify.
|
|
63
|
+
8. Use \`escape\` when another graph call would repeat evidence or the remaining
|
|
64
|
+
evidence is outside the TypeScript graph.
|
|
65
|
+
|
|
66
|
+
Most TypeScript structure answers need one or two graph calls.
|
|
67
|
+
|
|
68
|
+
## Request Fields
|
|
69
|
+
|
|
70
|
+
Fill the visible checklist, then exactly one request.
|
|
71
|
+
|
|
72
|
+
- \`question\`: restate the code question being considered.
|
|
73
|
+
- \`draft\`: initial request type and why it seems smallest.
|
|
74
|
+
- \`review\`: correct a wrong, broad, stale, or duplicate draft. If graph facts
|
|
75
|
+
already answer, if prior \`next.action\` was \`answer\`, or if the next evidence
|
|
76
|
+
is outside the indexed TypeScript graph, say so here and make \`request.type\`
|
|
77
|
+
be \`escape\`. If a broad flow draft is not \`tour\`, correct it here.
|
|
78
|
+
- \`request\`: final request after review.
|
|
79
|
+
|
|
80
|
+
## How to answer from graph evidence
|
|
81
|
+
|
|
82
|
+
- Use returned node names, signatures, edges, references, evidence, and
|
|
83
|
+
\`sourceSpan\` ranges directly.
|
|
84
|
+
- Explain the central path first, then mention important branches.
|
|
85
|
+
- For tests, impact, or reading lists, returned nodes and ranges are the answer
|
|
86
|
+
evidence, not search keywords.
|
|
87
|
+
- A returned range is a sacred citation anchor, not permission to open the file.
|
|
76
88
|
`.trim();
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ITtscGraphNode } from "../structures/ITtscGraphNode";
|
|
2
|
+
|
|
3
|
+
/** True for dependency declarations outside the authored project graph. */
|
|
4
|
+
export function isExternalNode(node: ITtscGraphNode): boolean {
|
|
5
|
+
return (
|
|
6
|
+
node.external ||
|
|
7
|
+
node.file.startsWith("bundled://") ||
|
|
8
|
+
/(^|\/)node_modules\//.test(node.file)
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** True for tests, examples, fixtures, generated output, and build artifacts. */
|
|
13
|
+
export function isSupportPath(file: string): boolean {
|
|
14
|
+
return (
|
|
15
|
+
file === "" ||
|
|
16
|
+
file.startsWith("bundled://") ||
|
|
17
|
+
/(^|\/)node_modules\//.test(file) ||
|
|
18
|
+
/(^|\/)(test|tests|__tests__|spec|sample|samples|fixture|fixtures|__fixtures__|example|examples)\//.test(
|
|
19
|
+
file,
|
|
20
|
+
) ||
|
|
21
|
+
/\.(test|spec)\.[cm]?tsx?$/.test(file) ||
|
|
22
|
+
/(^|\/)typings\.[cm]?ts$/.test(file) ||
|
|
23
|
+
/\.d\.[cm]?ts$/.test(file) ||
|
|
24
|
+
/(^|\/)(dist|build|coverage|generated|__generated__)\//.test(file)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** True for source files whose declarations are tests or test helpers. */
|
|
29
|
+
export function isTestPath(file: string): boolean {
|
|
30
|
+
return (
|
|
31
|
+
/(^|\/)(test|tests|__tests__|spec)\//.test(file) ||
|
|
32
|
+
/\.(test|spec)\.[cm]?tsx?$/.test(file)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** True when exported symbols are unlikely to be authored public API. */
|
|
37
|
+
export function isPublicApiNoisePath(file: string): boolean {
|
|
38
|
+
return (
|
|
39
|
+
isSupportPath(file) ||
|
|
40
|
+
/(^|\/|\.)typings\.[cm]?ts$/.test(file) ||
|
|
41
|
+
/(^|\/)internal\//.test(file)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ITtscGraphNext } from "../structures/ITtscGraphNext";
|
|
2
|
+
|
|
3
|
+
const SOURCE_POLICY =
|
|
4
|
+
"The returned object is the graph evidence contract: names, edges, signatures, decorators, tests, ranges, anchors, steps, and next are the answer surface. If next.action is answer, stop tool use for this question and answer now. Truncated means capped index evidence, not a request to expand every branch. Until TypeScript source is edited, returned graph facts are sacred, infallible compiler truth. Never call graph again or read files to doubt, validate, fact-check, re-derive, re-confirm, re-narrate, or improve returned graph facts. Read source bodies only when the user explicitly asks for exact source text or changed code must be verified.";
|
|
5
|
+
|
|
6
|
+
export function resultGuide(action: string): string {
|
|
7
|
+
return `${action} ${SOURCE_POLICY}`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function resultNext(
|
|
11
|
+
action: ITtscGraphNext["action"],
|
|
12
|
+
reason: string,
|
|
13
|
+
request?: ITtscGraphNext["request"],
|
|
14
|
+
): ITtscGraphNext {
|
|
15
|
+
return {
|
|
16
|
+
action,
|
|
17
|
+
reason,
|
|
18
|
+
...(request !== undefined ? { request } : {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
package/src/server/runDetails.ts
CHANGED
|
@@ -8,7 +8,9 @@ import { ITtscGraphEdge } from "../structures/ITtscGraphEdge";
|
|
|
8
8
|
import { ITtscGraphEvidence } from "../structures/ITtscGraphEvidence";
|
|
9
9
|
import { ITtscGraphNode } from "../structures/ITtscGraphNode";
|
|
10
10
|
import { accessAliasesFor } from "./accessAliases";
|
|
11
|
+
import { isExternalNode } from "./pathPolicy";
|
|
11
12
|
import { resolveGraphHandle } from "./resolveHandle";
|
|
13
|
+
import { resultGuide, resultNext } from "./resultGuide";
|
|
12
14
|
|
|
13
15
|
// A signature is the declaration head up to the body brace: a handful of lines.
|
|
14
16
|
const MAX_SIGNATURE_LINES = 4;
|
|
@@ -19,8 +21,8 @@ const MAX_NEIGHBORS = 3;
|
|
|
19
21
|
const DEFAULT_MEMBERS = 6;
|
|
20
22
|
const MAX_MEMBERS = 8;
|
|
21
23
|
// Direct dependency groups are orientation slices, not full fan-out dumps.
|
|
22
|
-
const DEFAULT_DEPENDENCIES =
|
|
23
|
-
const MAX_DEPENDENCIES =
|
|
24
|
+
const DEFAULT_DEPENDENCIES = 2;
|
|
25
|
+
const MAX_DEPENDENCIES = 4;
|
|
24
26
|
// Object literal outlines are navigation aids, not source excerpts.
|
|
25
27
|
const MAX_OBJECT_MEMBER_LINES = 300;
|
|
26
28
|
// Structural relationships are navigation, not the dependency picture details is for.
|
|
@@ -58,6 +60,7 @@ export function runDetails(
|
|
|
58
60
|
MAX_DEPENDENCIES,
|
|
59
61
|
);
|
|
60
62
|
const wantNeighbors = props.neighbors === true;
|
|
63
|
+
const includeExternal = props.includeExternal === true;
|
|
61
64
|
const nodes: ITtscGraphDetails.INode[] = [];
|
|
62
65
|
const unknown: string[] = [];
|
|
63
66
|
for (const handle of props.handles) {
|
|
@@ -89,10 +92,30 @@ export function runDetails(
|
|
|
89
92
|
endLine: span.endLine,
|
|
90
93
|
};
|
|
91
94
|
}
|
|
92
|
-
const calls = dependencyRefs(
|
|
95
|
+
const calls = dependencyRefs(
|
|
96
|
+
graph,
|
|
97
|
+
node,
|
|
98
|
+
executionKinds,
|
|
99
|
+
dependencyLimit,
|
|
100
|
+
includeExternal,
|
|
101
|
+
);
|
|
93
102
|
if (calls.length > 0) detail.calls = calls;
|
|
94
|
-
const types = dependencyRefs(
|
|
103
|
+
const types = dependencyRefs(
|
|
104
|
+
graph,
|
|
105
|
+
node,
|
|
106
|
+
typeKinds,
|
|
107
|
+
dependencyLimit,
|
|
108
|
+
includeExternal,
|
|
109
|
+
);
|
|
95
110
|
if (types.length > 0) detail.types = types;
|
|
111
|
+
const implementedBy = incomingDependencyRefs(
|
|
112
|
+
graph,
|
|
113
|
+
node,
|
|
114
|
+
implementationKinds,
|
|
115
|
+
dependencyLimit,
|
|
116
|
+
includeExternal,
|
|
117
|
+
);
|
|
118
|
+
if (implementedBy.length > 0) detail.implementedBy = implementedBy;
|
|
96
119
|
if (CONTAINER_KINDS.has(node.kind)) {
|
|
97
120
|
const list = members(graph, node, memberLimit);
|
|
98
121
|
if (list.length > 0) detail.members = list;
|
|
@@ -113,17 +136,30 @@ export function runDetails(
|
|
|
113
136
|
graph.outgoing(node.id),
|
|
114
137
|
"to",
|
|
115
138
|
neighborLimit,
|
|
139
|
+
includeExternal,
|
|
116
140
|
);
|
|
117
141
|
detail.dependedOnBy = refs(
|
|
118
142
|
graph,
|
|
119
143
|
graph.incoming(node.id),
|
|
120
144
|
"from",
|
|
121
145
|
neighborLimit,
|
|
146
|
+
includeExternal,
|
|
122
147
|
);
|
|
123
148
|
}
|
|
124
149
|
nodes.push(detail);
|
|
125
150
|
}
|
|
126
|
-
return {
|
|
151
|
+
return {
|
|
152
|
+
type: "details",
|
|
153
|
+
nodes,
|
|
154
|
+
next: resultNext(
|
|
155
|
+
"answer",
|
|
156
|
+
"Selected signatures, members, dependencies, implementation candidates, and ranges are enough for a shape or reading-anchor answer.",
|
|
157
|
+
),
|
|
158
|
+
guide: resultGuide(
|
|
159
|
+
"Use signatures, members, calls, types, implementedBy, literals, and sourceSpan anchors as selected symbol facts.",
|
|
160
|
+
),
|
|
161
|
+
unknown,
|
|
162
|
+
};
|
|
127
163
|
}
|
|
128
164
|
|
|
129
165
|
/** The members a container owns (via `contains`), each with its own signature. */
|
|
@@ -238,12 +274,14 @@ function refs(
|
|
|
238
274
|
edges: readonly ITtscGraphEdge[],
|
|
239
275
|
end: "to" | "from",
|
|
240
276
|
limit: number,
|
|
277
|
+
includeExternal: boolean,
|
|
241
278
|
): ITtscGraphDetails.IReference[] {
|
|
242
279
|
const ranked: Array<{ ref: ITtscGraphDetails.IReference; rank: number }> = [];
|
|
243
280
|
for (const edge of edges) {
|
|
244
281
|
if (STRUCTURAL_KINDS.has(edge.kind)) continue;
|
|
245
282
|
const other = graph.node(end === "to" ? edge.to : edge.from);
|
|
246
283
|
if (other === undefined) continue;
|
|
284
|
+
if (!includeExternal && isExternalNode(other)) continue;
|
|
247
285
|
const ref: ITtscGraphDetails.IReference = {
|
|
248
286
|
id: other.id,
|
|
249
287
|
name: other.qualifiedName ?? other.name,
|
|
@@ -274,18 +312,21 @@ const executionKinds = new Set([
|
|
|
274
312
|
"renders",
|
|
275
313
|
]);
|
|
276
314
|
const typeKinds = new Set(["type_ref", "extends", "implements", "overrides"]);
|
|
315
|
+
const implementationKinds = new Set(["implements", "overrides"]);
|
|
277
316
|
|
|
278
317
|
function dependencyRefs(
|
|
279
318
|
graph: TtscGraphMemory,
|
|
280
319
|
node: ITtscGraphNode,
|
|
281
320
|
kinds: ReadonlySet<string>,
|
|
282
321
|
limit: number,
|
|
322
|
+
includeExternal: boolean,
|
|
283
323
|
): ITtscGraphDetails.IReference[] {
|
|
284
324
|
const ranked: Array<{ ref: ITtscGraphDetails.IReference; rank: number }> = [];
|
|
285
325
|
for (const edge of graph.outgoing(node.id)) {
|
|
286
326
|
if (!kinds.has(edge.kind)) continue;
|
|
287
327
|
const other = graph.node(edge.to);
|
|
288
328
|
if (other === undefined || other.kind === "file") continue;
|
|
329
|
+
if (!includeExternal && isExternalNode(other)) continue;
|
|
289
330
|
const name = other.qualifiedName ?? other.name;
|
|
290
331
|
const ref: ITtscGraphDetails.IReference = {
|
|
291
332
|
id: other.id,
|
|
@@ -317,6 +358,49 @@ function dependencyRefs(
|
|
|
317
358
|
return out;
|
|
318
359
|
}
|
|
319
360
|
|
|
361
|
+
function incomingDependencyRefs(
|
|
362
|
+
graph: TtscGraphMemory,
|
|
363
|
+
node: ITtscGraphNode,
|
|
364
|
+
kinds: ReadonlySet<string>,
|
|
365
|
+
limit: number,
|
|
366
|
+
includeExternal: boolean,
|
|
367
|
+
): ITtscGraphDetails.IReference[] {
|
|
368
|
+
const ranked: Array<{ ref: ITtscGraphDetails.IReference; rank: number }> = [];
|
|
369
|
+
for (const edge of graph.incoming(node.id)) {
|
|
370
|
+
if (!kinds.has(edge.kind)) continue;
|
|
371
|
+
const other = graph.node(edge.from);
|
|
372
|
+
if (other === undefined || other.kind === "file") continue;
|
|
373
|
+
if (!includeExternal && isExternalNode(other)) continue;
|
|
374
|
+
const ref: ITtscGraphDetails.IReference = {
|
|
375
|
+
id: other.id,
|
|
376
|
+
name: other.qualifiedName ?? other.name,
|
|
377
|
+
kind: other.kind,
|
|
378
|
+
file: other.file,
|
|
379
|
+
relation: edge.kind,
|
|
380
|
+
};
|
|
381
|
+
if (other.evidence?.startLine) ref.line = other.evidence.startLine;
|
|
382
|
+
const evidence = edgeEvidenceOf(edge);
|
|
383
|
+
if (evidence !== undefined) ref.evidence = evidence;
|
|
384
|
+
const aliases = accessAliasesFor(other, edgeEvidenceTextOf(edge));
|
|
385
|
+
if (aliases !== undefined) ref.aliases = aliases;
|
|
386
|
+
ranked.push({
|
|
387
|
+
ref,
|
|
388
|
+
rank: refRank(ref, edge),
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
ranked.sort((a, b) => a.rank - b.rank);
|
|
392
|
+
const out: ITtscGraphDetails.IReference[] = [];
|
|
393
|
+
const seen = new Set<string>();
|
|
394
|
+
for (const item of ranked) {
|
|
395
|
+
const key = `${item.ref.relation}:${item.ref.id}`;
|
|
396
|
+
if (seen.has(key)) continue;
|
|
397
|
+
seen.add(key);
|
|
398
|
+
out.push(item.ref);
|
|
399
|
+
if (out.length >= limit) break;
|
|
400
|
+
}
|
|
401
|
+
return out;
|
|
402
|
+
}
|
|
403
|
+
|
|
320
404
|
function literalSummaries(text: string | undefined): string[] {
|
|
321
405
|
if (text === undefined) return [];
|
|
322
406
|
const out: string[] = [];
|
|
@@ -462,7 +546,7 @@ export function signatureOf(
|
|
|
462
546
|
const line = lines[i];
|
|
463
547
|
if (line === undefined) break;
|
|
464
548
|
out.push(line);
|
|
465
|
-
if (line.includes("{")) break;
|
|
549
|
+
if (line.includes("{") || line.trimEnd().endsWith(";")) break;
|
|
466
550
|
}
|
|
467
551
|
const text = out.join("\n").trim();
|
|
468
552
|
return text === "" ? undefined : text;
|
|
@@ -3,6 +3,7 @@ import { ITtscGraphEdge } from "../structures/ITtscGraphEdge";
|
|
|
3
3
|
import { ITtscGraphEntrypoints } from "../structures/ITtscGraphEntrypoints";
|
|
4
4
|
import { ITtscGraphNode } from "../structures/ITtscGraphNode";
|
|
5
5
|
import { resolveGraphHandle } from "./resolveHandle";
|
|
6
|
+
import { resultGuide, resultNext } from "./resultGuide";
|
|
6
7
|
import { decoratorsOf, edgeEvidenceOf, signatureOf } from "./runDetails";
|
|
7
8
|
import { runLookup } from "./runLookup";
|
|
8
9
|
|
|
@@ -84,10 +85,14 @@ export function runEntrypoints(
|
|
|
84
85
|
hits,
|
|
85
86
|
mentions,
|
|
86
87
|
neighborhood,
|
|
87
|
-
next:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
next: resultNext(
|
|
89
|
+
"inspect",
|
|
90
|
+
"Use one returned handle for trace/details when the answer needs flow or selected shape.",
|
|
91
|
+
"trace",
|
|
92
|
+
),
|
|
93
|
+
guide: resultGuide(
|
|
94
|
+
"Use hits, mentions, and neighborhood as the code index. If they identify the relevant files and symbols, answer or make one focused trace/details call; do not search the repository to verify them.",
|
|
95
|
+
),
|
|
91
96
|
...(truncated ? { truncated: true } : {}),
|
|
92
97
|
};
|
|
93
98
|
}
|
package/src/server/runLookup.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { TtscGraphMemory } from "../model/TtscGraphMemory";
|
|
2
2
|
import { ITtscGraphLookup } from "../structures/ITtscGraphLookup";
|
|
3
3
|
import { ITtscGraphNode } from "../structures/ITtscGraphNode";
|
|
4
|
+
import { isExternalNode, isSupportPath } from "./pathPolicy";
|
|
5
|
+
import { resultGuide, resultNext } from "./resultGuide";
|
|
4
6
|
import { decoratorsOf, signatureOf } from "./runDetails";
|
|
5
7
|
|
|
6
8
|
// One file should not crowd out the rest of the ranking, so cap hits per file.
|
|
@@ -24,12 +26,25 @@ export function runLookup(
|
|
|
24
26
|
const requestedKinds = requestedSymbolKinds(props.query);
|
|
25
27
|
const queryLc = props.query.trim().toLowerCase();
|
|
26
28
|
const wantsInternal = wantsInternalSymbol(queryLc, codeTerms);
|
|
29
|
+
const wantsSupport = wantsSupportSymbol(queryLc);
|
|
30
|
+
const includeExternal = props.includeExternal === true;
|
|
27
31
|
if (terms.length === 0)
|
|
28
|
-
return {
|
|
32
|
+
return {
|
|
33
|
+
type: "lookup",
|
|
34
|
+
hits: [],
|
|
35
|
+
next: resultNext(
|
|
36
|
+
"clarify",
|
|
37
|
+
"No symbol matched; ask for a concrete symbol or scope.",
|
|
38
|
+
),
|
|
39
|
+
guide: resultGuide(
|
|
40
|
+
"No symbol matched; answer that the graph did not resolve this name or ask for a more concrete symbol.",
|
|
41
|
+
),
|
|
42
|
+
};
|
|
29
43
|
|
|
30
44
|
const scored: ITtscGraphLookup.IHit[] = [];
|
|
31
45
|
for (const node of graph.nodes) {
|
|
32
46
|
if (node.kind === "file") continue;
|
|
47
|
+
if (!includeExternal && isExternalNode(node)) continue;
|
|
33
48
|
const score = scoreNode(
|
|
34
49
|
graph,
|
|
35
50
|
node,
|
|
@@ -38,6 +53,7 @@ export function runLookup(
|
|
|
38
53
|
codeTerms,
|
|
39
54
|
requestedKinds,
|
|
40
55
|
wantsInternal,
|
|
56
|
+
wantsSupport,
|
|
41
57
|
);
|
|
42
58
|
if (score <= 0) continue;
|
|
43
59
|
const hit: ITtscGraphLookup.IHit = {
|
|
@@ -78,10 +94,14 @@ export function runLookup(
|
|
|
78
94
|
return {
|
|
79
95
|
type: "lookup",
|
|
80
96
|
hits,
|
|
81
|
-
next:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
next: resultNext(
|
|
98
|
+
"inspect",
|
|
99
|
+
"Use one returned id for trace/details when the answer needs flow or shape.",
|
|
100
|
+
"details",
|
|
101
|
+
),
|
|
102
|
+
guide: resultGuide(
|
|
103
|
+
"Use ranked hits and signatures as symbol evidence. If the target is clear, answer or make one focused trace/details call; do not search files to verify the match.",
|
|
104
|
+
),
|
|
85
105
|
};
|
|
86
106
|
}
|
|
87
107
|
|
|
@@ -94,6 +114,7 @@ function scoreNode(
|
|
|
94
114
|
codeTerms: string[],
|
|
95
115
|
requestedKinds: Set<string>,
|
|
96
116
|
wantsInternal: boolean,
|
|
117
|
+
wantsSupport: boolean,
|
|
97
118
|
): number {
|
|
98
119
|
const name = node.name.toLowerCase();
|
|
99
120
|
const qualified = (node.qualifiedName ?? node.name).toLowerCase();
|
|
@@ -148,13 +169,19 @@ function scoreNode(
|
|
|
148
169
|
score += Math.min(8, Math.log2(1 + fan) * 2);
|
|
149
170
|
|
|
150
171
|
// Dampen what is rarely the intended target.
|
|
151
|
-
if (node.external) score *= 0.5;
|
|
152
172
|
if (node.ignored) score *= 0.3;
|
|
153
173
|
if (isTestFile(node.file)) score *= 0.7;
|
|
174
|
+
if (!wantsSupport && isSupportPath(node.file)) score *= 0.35;
|
|
154
175
|
if (!wantsInternal && isInternalish(node)) score *= 0.82;
|
|
155
176
|
return score;
|
|
156
177
|
}
|
|
157
178
|
|
|
179
|
+
function wantsSupportSymbol(queryLc: string): boolean {
|
|
180
|
+
return /\b(test|tests|spec|fixture|fixtures|sample|samples|example|examples|generated|build|dist)\b/.test(
|
|
181
|
+
queryLc,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
158
185
|
function wantsInternalSymbol(queryLc: string, codeTerms: string[]): boolean {
|
|
159
186
|
return (
|
|
160
187
|
/\b(internal|private|implementation|impl)\b/.test(queryLc) ||
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { TtscGraphMemory } from "../model/TtscGraphMemory";
|
|
2
2
|
import { ITtscGraphNode } from "../structures/ITtscGraphNode";
|
|
3
3
|
import { ITtscGraphOverview } from "../structures/ITtscGraphOverview";
|
|
4
|
+
import { isPublicApiNoisePath, isSupportPath } from "./pathPolicy";
|
|
5
|
+
import { resultGuide, resultNext } from "./resultGuide";
|
|
4
6
|
|
|
5
7
|
/** Edges that express nesting/packaging, not code dependency. */
|
|
6
8
|
const STRUCTURAL_KINDS = new Set<string>(["contains", "exports", "imports"]);
|
|
@@ -36,6 +38,13 @@ export function runOverview(
|
|
|
36
38
|
edges: graph.edges.length,
|
|
37
39
|
byKind,
|
|
38
40
|
},
|
|
41
|
+
next: resultNext(
|
|
42
|
+
"answer",
|
|
43
|
+
"Counts, layers, hotspots, and public API are sufficient for broad orientation.",
|
|
44
|
+
),
|
|
45
|
+
guide: resultGuide(
|
|
46
|
+
"Use counts, layers, hotspots, and public API as a broad orientation map. Do not expand it into file reads unless the user needs exact source body text.",
|
|
47
|
+
),
|
|
39
48
|
};
|
|
40
49
|
if (want("layers")) result.layers = layers(graph);
|
|
41
50
|
if (want("hotspots")) result.hotspots = hotspots(graph);
|
|
@@ -47,7 +56,13 @@ export function runOverview(
|
|
|
47
56
|
function layers(graph: TtscGraphMemory): ITtscGraphOverview.ILayer[] {
|
|
48
57
|
const byDir = new Map<string, { files: Set<string>; exported: number }>();
|
|
49
58
|
for (const node of graph.nodes) {
|
|
50
|
-
if (
|
|
59
|
+
if (
|
|
60
|
+
node.external ||
|
|
61
|
+
node.ignored ||
|
|
62
|
+
node.kind === "file" ||
|
|
63
|
+
isSupportPath(node.file)
|
|
64
|
+
)
|
|
65
|
+
continue;
|
|
51
66
|
const dir = dirname(node.file);
|
|
52
67
|
let entry = byDir.get(dir);
|
|
53
68
|
if (!entry) {
|
|
@@ -80,7 +95,13 @@ function hotspots(graph: TtscGraphMemory): ITtscGraphOverview.IHotspot[] {
|
|
|
80
95
|
return n;
|
|
81
96
|
};
|
|
82
97
|
return graph.nodes
|
|
83
|
-
.filter(
|
|
98
|
+
.filter(
|
|
99
|
+
(node) =>
|
|
100
|
+
!node.external &&
|
|
101
|
+
!node.ignored &&
|
|
102
|
+
node.kind !== "file" &&
|
|
103
|
+
!isSupportPath(node.file),
|
|
104
|
+
)
|
|
84
105
|
.map((node) => ({
|
|
85
106
|
...nodeOf(node),
|
|
86
107
|
fanIn: real(node.id, "in"),
|
|
@@ -137,12 +158,7 @@ function publicApi(graph: TtscGraphMemory): ITtscGraphOverview.IPublicApi[] {
|
|
|
137
158
|
* not framework-specific; it keeps the API surface to authored, used code.
|
|
138
159
|
*/
|
|
139
160
|
function isNoiseFile(file: string): boolean {
|
|
140
|
-
return (
|
|
141
|
-
/(^|\/)(test|tests|__tests__|spec|sample|samples)\//.test(file) ||
|
|
142
|
-
/\.(test|spec)\.[cm]?tsx?$/.test(file) ||
|
|
143
|
-
/(^|\/|\.)typings\.[cm]?ts$/.test(file) ||
|
|
144
|
-
/\.d\.[cm]?ts$/.test(file)
|
|
145
|
-
);
|
|
161
|
+
return isPublicApiNoisePath(file);
|
|
146
162
|
}
|
|
147
163
|
|
|
148
164
|
/** The parent directory of a project-relative path (`.` at the root). */
|