@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.
Files changed (61) hide show
  1. package/lib/TtscGraphApplication.js +36 -23
  2. package/lib/TtscGraphApplication.js.map +1 -1
  3. package/lib/model/loadGraph.js +17 -17
  4. package/lib/server/accessAliases.js +53 -0
  5. package/lib/server/accessAliases.js.map +1 -0
  6. package/lib/server/createServer.js +1133 -634
  7. package/lib/server/createServer.js.map +1 -1
  8. package/lib/server/instructions.js +69 -21
  9. package/lib/server/instructions.js.map +1 -1
  10. package/lib/server/runDetails.js +413 -0
  11. package/lib/server/runDetails.js.map +1 -0
  12. package/lib/server/{runIndex.js → runEntrypoints.js} +91 -26
  13. package/lib/server/runEntrypoints.js.map +1 -0
  14. package/lib/server/{runQuery.js → runLookup.js} +102 -15
  15. package/lib/server/runLookup.js.map +1 -0
  16. package/lib/server/runOverview.js +31 -21
  17. package/lib/server/runOverview.js.map +1 -1
  18. package/lib/server/runTrace.js +133 -38
  19. package/lib/server/runTrace.js.map +1 -1
  20. package/lib/structures/{ITtscGraphQuery.js → ITtscGraphDetails.js} +1 -1
  21. package/lib/structures/ITtscGraphDetails.js.map +1 -0
  22. package/lib/structures/ITtscGraphEntrypoints.js +3 -0
  23. package/lib/structures/ITtscGraphEntrypoints.js.map +1 -0
  24. package/lib/structures/{ITtscGraphExpand.js → ITtscGraphEscape.js} +1 -1
  25. package/lib/structures/ITtscGraphEscape.js.map +1 -0
  26. package/lib/structures/{ITtscGraphIndex.js → ITtscGraphLookup.js} +1 -1
  27. package/lib/structures/ITtscGraphLookup.js.map +1 -0
  28. package/lib/structures/index.js +4 -3
  29. package/lib/structures/index.js.map +1 -1
  30. package/package.json +2 -2
  31. package/src/TtscGraphApplication.ts +39 -32
  32. package/src/server/accessAliases.ts +55 -0
  33. package/src/server/createServer.ts +4 -7
  34. package/src/server/instructions.ts +69 -21
  35. package/src/server/runDetails.ts +469 -0
  36. package/src/server/{runIndex.ts → runEntrypoints.ts} +109 -34
  37. package/src/server/{runQuery.ts → runLookup.ts} +123 -16
  38. package/src/server/runOverview.ts +35 -23
  39. package/src/server/runTrace.ts +164 -38
  40. package/src/structures/ITtscGraphApplication.ts +100 -52
  41. package/src/structures/ITtscGraphDecorator.ts +12 -14
  42. package/src/structures/ITtscGraphDetails.ts +134 -0
  43. package/src/structures/{ITtscGraphIndex.ts → ITtscGraphEntrypoints.ts} +34 -16
  44. package/src/structures/ITtscGraphEscape.ts +39 -0
  45. package/src/structures/ITtscGraphEvidence.ts +5 -8
  46. package/src/structures/ITtscGraphLookup.ts +61 -0
  47. package/src/structures/ITtscGraphNode.ts +10 -4
  48. package/src/structures/ITtscGraphOverview.ts +24 -16
  49. package/src/structures/ITtscGraphTrace.ts +54 -11
  50. package/src/structures/TtscGraphNodeKind.ts +2 -2
  51. package/src/structures/index.ts +4 -3
  52. package/lib/server/runExpand.js +0 -177
  53. package/lib/server/runExpand.js.map +0 -1
  54. package/lib/server/runIndex.js.map +0 -1
  55. package/lib/server/runQuery.js.map +0 -1
  56. package/lib/structures/ITtscGraphExpand.js.map +0 -1
  57. package/lib/structures/ITtscGraphIndex.js.map +0 -1
  58. package/lib/structures/ITtscGraphQuery.js.map +0 -1
  59. package/src/server/runExpand.ts +0 -186
  60. package/src/structures/ITtscGraphExpand.ts +0 -85
  61. package/src/structures/ITtscGraphQuery.ts +0 -49
@@ -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 "./runExpand";
7
+ import { edgeEvidenceOf, edgeEvidenceTextOf, signatureOf } from "./runDetails";
6
8
 
7
- const DEFAULT_DEPTH = 6;
8
- const DEFAULT_MAX_NODES = 60;
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.IProps,
26
+ props: ITtscGraphTrace.IRequest,
20
27
  ): ITtscGraphTrace {
21
28
  const direction = props.direction ?? "forward";
22
- const maxDepth = Math.max(1, props.maxDepth ?? DEFAULT_DEPTH);
23
- const maxNodes = Math.max(1, props.maxNodes ?? DEFAULT_MAX_NODES);
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 { direction, hops: [], reached: [], truncated: false };
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` the
44
- // one-call answer for "how does A reach B" instead of an open-ended trace.
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 = { direction: "path", hops: [], reached: [], truncated: false };
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
- Math.max(1, props.maxDepth ?? 12),
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: found?.hops ?? [],
69
- path: (found?.path ?? []).map((node, i) => {
70
- const node_ = summary(node, i);
71
- const sig = signatureOf(graph.project, node);
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.push(hop);
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
- start: summary(start.node),
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<string, { via: string; kind: string }>();
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
- parent.set(otherId, { via: id, kind: edge.kind });
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
- hops.push({
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: parent.get(node.id)?.kind ?? "calls",
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(kind: string): boolean {
225
- return kind !== "contains" && kind !== "exports" && kind !== "imports";
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 { ITtscGraphExpand } from "./ITtscGraphExpand";
2
- import { ITtscGraphIndex } from "./ITtscGraphIndex";
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
- * Each method is one MCP tool; its name is the tool name and its parameter
11
- * object becomes the tool's JSON schema once `typia.llm.controller` reflects
12
- * this interface. `TtscGraphApplication` implements it over the resident
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
- * The first source-free index for a code question: ranked symbols, exact code
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
- * @param props The natural code question or search phrase
22
- * @returns Compact graph coordinates and dependency context
23
- */
24
- graph_index(props: ITtscGraphIndex.IProps): ITtscGraphIndex;
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
- * @param props Which facet to project
31
- * @returns The requested architecture facets
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
- * @param props The handles to expand
42
- * @returns The resolved nodes, and any handles that did not resolve
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 query and result cap
53
- * @returns Ranked hits with handles
32
+ * @param props The reasoning and selected graph request
33
+ * @returns One `result` union member matching the selected request type
54
34
  */
55
- graph_query(props: ITtscGraphQuery.IProps): ITtscGraphQuery;
35
+ query(props: ITtscGraphApplication.IProps): ITtscGraphApplication.IResult;
36
+ }
56
37
 
57
- /**
58
- * Follow dependency flow from a symbol: `forward` to what it uses, `reverse`
59
- * to what uses it, or `impact` to the public API and tests a change reaches.
60
- * Give `from`/`to` as ids or dotted names to get the path between two symbols
61
- * in one call — how A reaches B.
62
- *
63
- * @param props The start, optional target, direction, and bounds
64
- * @returns The ordered hops and reached nodes, or candidates for an ambiguous
65
- * start
66
- */
67
- graph_trace(props: ITtscGraphTrace.IProps): ITtscGraphTrace;
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`. The graph reports the decorator
4
- * faithfully rather than interpreting any framework's convention: the `name` is
5
- * the decorator as written (`Controller`, `Get`, `TypedRoute.Get`, …) and the
6
- * statically resolvable `arguments` are preserved, so a consumer can apply its
7
- * own meaning without re-parsing source.
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}. `text` is always the source
22
- * of the argument expression; `literal` is set only when the argument is a
23
- * string, number, or boolean literal the producer could resolve statically,
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
  }