@mrclrchtr/supi-code-intelligence 6.3.0 → 7.0.0
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 +164 -82
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +8 -1
- package/node_modules/@mrclrchtr/supi-core/README.md +8 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +10 -3
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/llm.ts +141 -16
- package/node_modules/@mrclrchtr/supi-lsp/README.md +35 -13
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +8 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +8 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +10 -3
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/llm.ts +141 -16
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/index.js +3 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/legacy.js +3 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +16 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +43 -35
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +83 -17
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-collection.ts +108 -92
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-evidence.ts +44 -82
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-host.ts +3 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-publication.ts +9 -68
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-pull.ts +45 -58
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +230 -331
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-request.ts +201 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +129 -70
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-typescript.ts +395 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-waiters.ts +8 -12
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +685 -183
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-state.ts +2 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-sync.ts +60 -60
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-request-enrollment.ts +75 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-semantic-input-barrier.ts +443 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-semantic-input-errors.ts +30 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-semantic-input-file.ts +15 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +290 -37
- package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +72 -16
- package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +1 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-scope.ts +30 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sentinels.ts +4 -32
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sources.ts +108 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +10 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-process-crash-report.ts +50 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +11 -7
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +770 -56
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostic-surface.ts +3 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +37 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +48 -12
- package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +50 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +8 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +10 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/llm.ts +141 -16
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callee-display-name.ts +165 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +67 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +2 -0
- package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/yaml/browser/dist/nodes/Alias.js +25 -23
- package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/yaml/dist/nodes/Alias.js +25 -23
- package/node_modules/yaml/package.json +1 -1
- package/package.json +5 -5
- package/src/analysis/health/diagnostics.ts +1 -2
- package/src/analysis/health/file-scope.ts +4 -1
- package/src/analysis/health/server-status.ts +1 -1
- package/src/analysis/relations/callees.ts +17 -8
- package/src/analysis/relations/implementations.ts +1 -2
- package/src/analysis/relations/references.ts +8 -4
- package/src/analysis/relations/types.ts +6 -30
- package/src/analysis/target/anchored.ts +9 -1
- package/src/analysis/target/symbol.ts +29 -11
- package/src/analysis/target/types.ts +14 -6
- package/src/api.ts +2 -0
- package/src/session/graph/collect.ts +18 -3
- package/src/session/health-refresh.ts +27 -11
- package/src/session/health-types.ts +21 -4
- package/src/session/health-workflow.ts +28 -22
- package/src/session/orientation-types.ts +5 -6
- package/src/session/orientation-workflow.ts +10 -2
- package/src/session/session.ts +12 -5
- package/src/session/target-workflow.ts +9 -6
- package/src/substrate/lsp/maintenance.ts +53 -47
- package/src/substrate/lsp/source-tracking.ts +252 -0
- package/src/tool/code_find/guidance.ts +3 -3
- package/src/tool/code_find/spec.ts +5 -4
- package/src/tool/code_find/tui.ts +7 -1
- package/src/tool/code_graph/details.ts +32 -0
- package/src/tool/code_graph/display.ts +54 -0
- package/src/tool/code_graph/format.ts +60 -0
- package/src/tool/code_graph/guidance.ts +2 -2
- package/src/tool/code_graph/markdown.ts +76 -198
- package/src/tool/code_graph/read-next.ts +65 -0
- package/src/tool/code_graph/result.ts +118 -83
- package/src/tool/code_graph/tui.ts +216 -54
- package/src/tool/code_health/guidance.ts +3 -5
- package/src/tool/code_health/markdown.ts +90 -57
- package/src/tool/code_health/refresh-outcome.ts +51 -0
- package/src/tool/code_health/refresh-status.ts +130 -43
- package/src/tool/code_health/scope.ts +78 -0
- package/src/tool/code_health/spec.ts +1 -1
- package/src/tool/code_health/tui.ts +29 -38
- package/src/tool/code_inspect/guidance.ts +5 -3
- package/src/tool/code_inspect/tui.ts +7 -1
- package/src/tool/code_orientation/guidance.ts +3 -4
- package/src/tool/code_orientation/result.ts +31 -8
- package/src/tool/code_orientation/tui.ts +26 -5
- package/src/tool/code_refactor_apply/guidance.ts +1 -1
- package/src/tool/code_refactor_apply/tui.ts +7 -3
- package/src/tool/code_refactor_plan/guidance.ts +3 -5
- package/src/tool/code_refactor_plan/tui.ts +7 -1
- package/src/tool/code_resolve/guidance.ts +3 -5
- package/src/tool/code_resolve/result.ts +13 -10
- package/src/tool/code_resolve/tui.ts +18 -1
- package/src/tool/guidance.ts +11 -9
- package/src/tool/infra/truncate.ts +39 -13
- package/src/tool/result/candidate-row.ts +27 -0
- package/src/tool/result/errors.ts +21 -6
- package/src/tool/result/types.ts +7 -3
- package/src/tool/schemas.ts +5 -0
- package/src/types/execution.ts +2 -0
- package/src/types/index.ts +2 -0
- package/src/ui/tui/candidate-legacy-body.ts +69 -0
- package/src/ui/tui/candidate-selection.ts +366 -0
- package/src/ui/tui/common.ts +26 -31
- package/src/ui/tui/execution-error.ts +92 -0
|
@@ -1,222 +1,100 @@
|
|
|
1
1
|
/** Markdown adapter for assembled code_graph evidence. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
type EvidenceList,
|
|
5
|
-
type EvidenceListMetadata,
|
|
6
|
-
renderEvidenceListMetadataDisclosure,
|
|
7
|
-
} from "../../analysis/evidence.ts";
|
|
8
3
|
import { renderReadNextSection } from "../../analysis/read-next.ts";
|
|
9
|
-
import {
|
|
10
|
-
compactLineRanges,
|
|
11
|
-
formatAssembledReferenceList,
|
|
12
|
-
} from "../../analysis/references/semantic-refs.ts";
|
|
13
|
-
import type {
|
|
14
|
-
CallEntry,
|
|
15
|
-
CalleeScope,
|
|
16
|
-
ImplementationEntry,
|
|
17
|
-
ReferenceEntry,
|
|
18
|
-
} from "../../analysis/relations/types.ts";
|
|
4
|
+
import type { CallEntry, CalleeScope } from "../../analysis/relations/types.ts";
|
|
19
5
|
import { toDisplayPath } from "../../analysis/search/paths.ts";
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
6
|
+
import { assembledReadNext } from "../result/assembly.ts";
|
|
7
|
+
import {
|
|
8
|
+
compactGraphLabel,
|
|
9
|
+
formatGraphEvidence,
|
|
10
|
+
formatGraphRange,
|
|
11
|
+
graphCodeSpan,
|
|
12
|
+
} from "./format.ts";
|
|
13
|
+
import type { AssembledGraphSection, GraphResultAssembly } from "./result.ts";
|
|
14
|
+
|
|
15
|
+
/** Render one target and one summary per requested relation. */
|
|
23
16
|
export function renderGraphResult(assembly: GraphResultAssembly): string {
|
|
24
17
|
const lines = [
|
|
25
|
-
|
|
26
|
-
"",
|
|
27
|
-
`_File: \`${assembly.resolvedDisplayFile}\`_`,
|
|
18
|
+
`Target: ${graphCodeSpan(assembly.displayName)} — ${graphCodeSpan(assembly.resolvedDisplayFile)}`,
|
|
28
19
|
"",
|
|
29
20
|
];
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (available.length > 0) {
|
|
33
|
-
lines.push(
|
|
34
|
-
available
|
|
35
|
-
.map(
|
|
36
|
-
(section) =>
|
|
37
|
-
`**${section.rel}**: ${sectionCount(section)} result${sectionCount(section) === 1 ? "" : "s"}`,
|
|
38
|
-
)
|
|
39
|
-
.join(" | "),
|
|
40
|
-
"",
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const unavailable = assembly.sections.filter((section) => section.kind === "unavailable");
|
|
45
|
-
if (unavailable.length > 0) {
|
|
46
|
-
lines.push(
|
|
47
|
-
`_Unavailable: ${unavailable.map((section) => `\`${section.rel}\``).join(", ")}_`,
|
|
48
|
-
"",
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
for (const section of assembly.sections) {
|
|
53
|
-
if (section.kind === "unavailable") {
|
|
54
|
-
lines.push(`**${section.rel}**: ${section.message}`, "");
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
switch (section.rel) {
|
|
59
|
-
case "references": {
|
|
60
|
-
const rendered = renderReferencesResult({
|
|
61
|
-
symbolName: assembly.displayName,
|
|
62
|
-
references: section.evidence,
|
|
63
|
-
externalCount: section.data.externalCount,
|
|
64
|
-
confidence: section.data.confidence,
|
|
65
|
-
cwd: assembly.cwd,
|
|
66
|
-
});
|
|
67
|
-
lines.push(rendered.content, "");
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
case "callees": {
|
|
71
|
-
const rendered = renderCallsResult(
|
|
72
|
-
section.data.enclosingScope,
|
|
73
|
-
section.evidence,
|
|
74
|
-
assembly.resolvedDisplayFile,
|
|
75
|
-
section.data.depth,
|
|
76
|
-
);
|
|
77
|
-
lines.push(rendered.content, "");
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
case "implements": {
|
|
81
|
-
const rendered = renderImplementationsResult({
|
|
82
|
-
implementations: section.evidence,
|
|
83
|
-
externalCount: section.data.externalCount,
|
|
84
|
-
cwd: assembly.cwd,
|
|
85
|
-
targetName: assembly.displayName,
|
|
86
|
-
});
|
|
87
|
-
lines.push(rendered.content, "");
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
lines.push(...renderReadNextSection(available.flatMap((section) => section.readNext)));
|
|
21
|
+
for (const section of assembly.sections) lines.push(...renderSection(section, assembly), "");
|
|
22
|
+
lines.push(...renderReadNextSection(assembledReadNext(assembly.assembled)));
|
|
94
23
|
return lines.join("\n");
|
|
95
24
|
}
|
|
96
25
|
|
|
97
|
-
function
|
|
98
|
-
section
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function renderReferencesResult(options: {
|
|
104
|
-
symbolName: string;
|
|
105
|
-
references: EvidenceList<ReferenceEntry>;
|
|
106
|
-
externalCount: number;
|
|
107
|
-
confidence: string;
|
|
108
|
-
cwd: string;
|
|
109
|
-
}): { content: string; evidenceList: EvidenceListMetadata | null } {
|
|
110
|
-
const total = options.references.metadata.totalCount ?? options.references.metadata.shownCount;
|
|
111
|
-
const lines = [
|
|
112
|
-
`# References of \`${options.symbolName}\``,
|
|
113
|
-
"",
|
|
114
|
-
`**${total} reference${total === 1 ? "" : "s"}** (${options.confidence})`,
|
|
115
|
-
];
|
|
116
|
-
if (options.externalCount > 0) {
|
|
117
|
-
lines.push(
|
|
118
|
-
`_+${options.externalCount} external reference${options.externalCount === 1 ? "" : "s"}_`,
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
const invalidDisclosure = renderInvalidProviderLocations(options.references.metadata);
|
|
122
|
-
if (invalidDisclosure) lines.push(invalidDisclosure);
|
|
123
|
-
lines.push("");
|
|
124
|
-
|
|
125
|
-
const displayEvidence = {
|
|
126
|
-
key: options.references.key,
|
|
127
|
-
items: options.references.items.map((reference) => ({
|
|
128
|
-
file: toDisplayPath(options.cwd, reference.file),
|
|
129
|
-
line: reference.line,
|
|
130
|
-
})),
|
|
131
|
-
metadata: options.references.metadata,
|
|
132
|
-
};
|
|
133
|
-
const evidenceList = formatAssembledReferenceList(lines, displayEvidence);
|
|
134
|
-
return { content: lines.join("\n"), evidenceList };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function renderCallsResult(
|
|
138
|
-
enclosingScope: CalleeScope,
|
|
139
|
-
calls: EvidenceList<CallEntry>,
|
|
140
|
-
relPath: string,
|
|
141
|
-
depth: "direct" | "deep" = "direct",
|
|
142
|
-
): { content: string; evidenceList: EvidenceListMetadata } {
|
|
143
|
-
const lines: string[] = [];
|
|
144
|
-
const depthLabel = depth === "deep" ? "Deep structural calls" : "Direct structural calls";
|
|
145
|
-
const depthNote =
|
|
146
|
-
depth === "deep"
|
|
147
|
-
? "_Deep: includes calls from nested function/method/callback scopes within the enclosing scope._"
|
|
148
|
-
: "_Structural only: call expressions are reported by source shape, not symbol identity; calls inside nested function/method/callback scopes are excluded from this enclosing scope._";
|
|
149
|
-
const total = calls.metadata.totalCount ?? calls.metadata.shownCount;
|
|
150
|
-
|
|
151
|
-
lines.push(`# ${depthLabel} from \`${enclosingScope.name}\``, "");
|
|
26
|
+
function renderSection(section: AssembledGraphSection, assembly: GraphResultAssembly): string[] {
|
|
27
|
+
const source = section.rel === "callees" ? "structural" : "semantic";
|
|
28
|
+
const depth = section.kind === "ok" && section.rel === "callees" ? `, ${section.data.depth}` : "";
|
|
29
|
+
const lines = [`## ${section.rel} (${source}${depth})`];
|
|
30
|
+
if (section.kind === "unavailable") return [...lines, `Unavailable — ${section.message}`];
|
|
152
31
|
lines.push(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
32
|
+
formatGraphEvidence(
|
|
33
|
+
section.evidence.metadata,
|
|
34
|
+
section.rel === "callees" ? "call sites" : "locations",
|
|
35
|
+
section.rel === "callees" ? 0 : section.data.externalCount,
|
|
36
|
+
),
|
|
156
37
|
"",
|
|
157
38
|
);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
function renderImplementationsResult(options: {
|
|
166
|
-
implementations: EvidenceList<ImplementationEntry>;
|
|
167
|
-
externalCount: number;
|
|
168
|
-
cwd: string;
|
|
169
|
-
targetName?: string;
|
|
170
|
-
}): { content: string; evidenceList: EvidenceListMetadata } {
|
|
171
|
-
const lines: string[] = [
|
|
172
|
-
options.targetName
|
|
173
|
-
? `# Implementations of \`${options.targetName}\` (semantic)`
|
|
174
|
-
: "# Implementations (semantic)",
|
|
39
|
+
if (section.rel !== "callees") return [...lines, ...formatLocations(section, assembly.cwd)];
|
|
40
|
+
return [
|
|
41
|
+
...lines,
|
|
42
|
+
formatScope(section.data.enclosingScope, assembly.displayName),
|
|
43
|
+
section.data.depth === "direct"
|
|
44
|
+
? "Nested scopes excluded; calls are source expressions, not resolved symbols."
|
|
45
|
+
: "Nested scopes included; calls are source expressions, not resolved symbols.",
|
|
175
46
|
"",
|
|
47
|
+
...formatCalls(section.evidence.items, assembly),
|
|
176
48
|
];
|
|
177
|
-
const total =
|
|
178
|
-
options.implementations.metadata.totalCount ?? options.implementations.metadata.shownCount;
|
|
179
|
-
if (total > 0) {
|
|
180
|
-
lines.push(`**${total} implementation${total === 1 ? "" : "s"}** in the project`, "");
|
|
181
|
-
for (const [file, locations] of groupByFile(options.implementations.items, options.cwd)) {
|
|
182
|
-
lines.push(`### ${file}`, `- ${compactLineRanges(locations)}`, "");
|
|
183
|
-
}
|
|
184
|
-
const disclosure = renderEvidenceListMetadataDisclosure(options.implementations.metadata);
|
|
185
|
-
if (disclosure) lines.push(disclosure);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (options.externalCount > 0) {
|
|
189
|
-
lines.push(
|
|
190
|
-
`_+${options.externalCount} external location${options.externalCount === 1 ? "" : "s"} (outside this project)_`,
|
|
191
|
-
"",
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
const invalidDisclosure = renderInvalidProviderLocations(options.implementations.metadata);
|
|
195
|
-
if (invalidDisclosure) lines.push(invalidDisclosure, "");
|
|
196
|
-
|
|
197
|
-
return { content: lines.join("\n"), evidenceList: options.implementations.metadata };
|
|
198
49
|
}
|
|
199
50
|
|
|
200
|
-
function
|
|
201
|
-
|
|
202
|
-
return `
|
|
51
|
+
function formatScope(scope: CalleeScope, targetName: string): string {
|
|
52
|
+
const name = scope.name === targetName ? "" : `${graphCodeSpan(scope.name)} — `;
|
|
53
|
+
return `Scope: ${name}${formatGraphRange(scope)}`;
|
|
203
54
|
}
|
|
204
55
|
|
|
205
|
-
function
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
56
|
+
function formatLocations(
|
|
57
|
+
section: Extract<AssembledGraphSection, { kind: "ok"; rel: "references" | "implements" }>,
|
|
58
|
+
cwd: string,
|
|
59
|
+
): string[] {
|
|
60
|
+
const groups = new Map<string, string[]>();
|
|
61
|
+
for (const location of section.evidence.items) {
|
|
62
|
+
const file = toDisplayPath(cwd, location.file);
|
|
63
|
+
const sites = groups.get(file) ?? [];
|
|
64
|
+
sites.push(`L${location.line}:${location.character}`);
|
|
65
|
+
groups.set(file, sites);
|
|
212
66
|
}
|
|
213
|
-
return
|
|
67
|
+
return [...groups].map(([file, sites]) => `- ${graphCodeSpan(file)}: ${sites.join(", ")}`);
|
|
214
68
|
}
|
|
215
69
|
|
|
216
|
-
/**
|
|
217
|
-
function
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
70
|
+
/** Group by the full expression, never by a shortened display label. */
|
|
71
|
+
function formatCalls(calls: readonly CallEntry[], assembly: GraphResultAssembly): string[] {
|
|
72
|
+
const groups = new Map<string, { name: string; file: string; sites: string[] }>();
|
|
73
|
+
for (const call of calls) {
|
|
74
|
+
const file = toDisplayPath(assembly.cwd, call.file);
|
|
75
|
+
const key = JSON.stringify([file, call.name]);
|
|
76
|
+
const group = groups.get(key) ?? { name: call.displayName ?? call.name, file, sites: [] };
|
|
77
|
+
group.sites.push(`L${call.line}:${call.character}`);
|
|
78
|
+
groups.set(key, group);
|
|
79
|
+
}
|
|
80
|
+
const previews = [...groups.values()].map((group) => ({
|
|
81
|
+
...group,
|
|
82
|
+
label: compactGraphLabel(group.name),
|
|
83
|
+
}));
|
|
84
|
+
const collisions = new Map<string, { count: number; seen: number }>();
|
|
85
|
+
for (const { file, label } of previews) {
|
|
86
|
+
const key = JSON.stringify([file, label]);
|
|
87
|
+
const count = (collisions.get(key)?.count ?? 0) + 1;
|
|
88
|
+
collisions.set(key, { count, seen: 0 });
|
|
89
|
+
}
|
|
90
|
+
return previews.map(({ label, file, sites }) => {
|
|
91
|
+
const collision = collisions.get(JSON.stringify([file, label]));
|
|
92
|
+
let qualifier = "";
|
|
93
|
+
if (collision && collision.count > 1) {
|
|
94
|
+
collision.seen++;
|
|
95
|
+
qualifier = ` (expression ${collision.seen}/${collision.count})`;
|
|
96
|
+
}
|
|
97
|
+
const prefix = file === assembly.resolvedDisplayFile ? "" : `${graphCodeSpan(file)}: `;
|
|
98
|
+
return `- ${graphCodeSpan(label)}${qualifier} — ${prefix}${sites.join(", ")}`;
|
|
99
|
+
});
|
|
222
100
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type ReadNextItem, readNextRange } from "../../analysis/read-next.ts";
|
|
2
|
+
import type { GraphSection } from "../../session/graph-types.ts";
|
|
3
|
+
|
|
4
|
+
/** Prefer the known enclosing scope, then alternate relation sites before the display cap. */
|
|
5
|
+
export function graphReadNext(sections: readonly GraphSection[]): ReadNextItem[] {
|
|
6
|
+
const calls = sections.find((section) => section.kind === "ok" && section.rel === "callees");
|
|
7
|
+
const scopeReads =
|
|
8
|
+
calls?.kind === "ok"
|
|
9
|
+
? calls.readNext.map((item) => ({ ...item, reason: "inspect the enclosing scope" }))
|
|
10
|
+
: [];
|
|
11
|
+
const queues = sections.flatMap((section) => {
|
|
12
|
+
if (section.kind !== "ok" || section.rel === "callees") return [];
|
|
13
|
+
// Reference collection puts the approximate target range first. The known scope replaces it.
|
|
14
|
+
return [
|
|
15
|
+
section.rel === "references" && scopeReads.length > 0
|
|
16
|
+
? section.readNext.slice(1)
|
|
17
|
+
: section.readNext,
|
|
18
|
+
];
|
|
19
|
+
});
|
|
20
|
+
const candidates = [...scopeReads];
|
|
21
|
+
const maxLength = Math.max(0, ...queues.map((queue) => queue.length));
|
|
22
|
+
for (let index = 0; index < maxLength; index++) {
|
|
23
|
+
for (const queue of queues) {
|
|
24
|
+
const item = queue[index];
|
|
25
|
+
if (item) candidates.push(item);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return mergeRanges(candidates)
|
|
29
|
+
.slice(0, 3)
|
|
30
|
+
.map((item) => readNextRange(item));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Merge connected ranges before bounding them, including ranges that bridge two earlier reads. */
|
|
34
|
+
function mergeRanges(items: readonly ReadNextItem[]): ReadNextItem[] {
|
|
35
|
+
const result: ReadNextItem[] = [];
|
|
36
|
+
for (const item of items) {
|
|
37
|
+
const merged = { ...item };
|
|
38
|
+
let firstIndex = result.length;
|
|
39
|
+
let index = 0;
|
|
40
|
+
while (index < result.length) {
|
|
41
|
+
const other = result[index];
|
|
42
|
+
if (
|
|
43
|
+
other.file === merged.file &&
|
|
44
|
+
other.startLine <= merged.endLine &&
|
|
45
|
+
merged.startLine <= other.endLine
|
|
46
|
+
) {
|
|
47
|
+
firstIndex = Math.min(firstIndex, index);
|
|
48
|
+
if (
|
|
49
|
+
merged.reason !== other.reason ||
|
|
50
|
+
merged.startLine !== other.startLine ||
|
|
51
|
+
merged.endLine !== other.endLine
|
|
52
|
+
)
|
|
53
|
+
merged.reason = "inspect related source ranges";
|
|
54
|
+
merged.startLine = Math.min(merged.startLine, other.startLine);
|
|
55
|
+
merged.endLine = Math.max(merged.endLine, other.endLine);
|
|
56
|
+
result.splice(index, 1);
|
|
57
|
+
index = 0;
|
|
58
|
+
} else {
|
|
59
|
+
index++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
result.splice(firstIndex, 0, merged);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { ConfidenceMode } from "@mrclrchtr/supi-code-runtime/api";
|
|
2
|
-
import {
|
|
2
|
+
import type { EvidenceListMetadata } from "../../analysis/evidence.ts";
|
|
3
|
+
import {
|
|
4
|
+
createEvidenceList,
|
|
5
|
+
createPartialEvidenceList,
|
|
6
|
+
type EvidenceList,
|
|
7
|
+
} from "../../analysis/evidence.ts";
|
|
3
8
|
import type { RelationLocationPartialReason } from "../../analysis/relations/provider-locations.ts";
|
|
4
9
|
import type {
|
|
5
10
|
CallEntry,
|
|
@@ -9,13 +14,18 @@ import type {
|
|
|
9
14
|
import { toDisplayPath } from "../../analysis/search/paths.ts";
|
|
10
15
|
import type { GraphSection } from "../../session/graph-types.ts";
|
|
11
16
|
import {
|
|
12
|
-
|
|
17
|
+
assembledReadNext,
|
|
13
18
|
assembleToolResult,
|
|
14
19
|
type ResultProvenance,
|
|
15
20
|
type ToolResultAssembly,
|
|
16
21
|
} from "../result/assembly.ts";
|
|
22
|
+
import { formatCandidateRow } from "../result/candidate-row.ts";
|
|
17
23
|
import { createToolDisplaySection } from "../result/display.ts";
|
|
18
|
-
import type {
|
|
24
|
+
import type { ToolDisplaySection } from "../result/types.ts";
|
|
25
|
+
import type { GraphDetails, GraphFileGroup, GraphSectionDetails } from "./details.ts";
|
|
26
|
+
import { graphDisplaySection } from "./display.ts";
|
|
27
|
+
import { formatGraphEvidence } from "./format.ts";
|
|
28
|
+
import { graphReadNext } from "./read-next.ts";
|
|
19
29
|
|
|
20
30
|
export type { GraphRelationKind, GraphSection } from "../../session/graph-types.ts";
|
|
21
31
|
|
|
@@ -40,7 +50,7 @@ export interface GraphResultAssembly {
|
|
|
40
50
|
resolvedDisplayFile: string;
|
|
41
51
|
cwd: string;
|
|
42
52
|
assembled: ToolResultAssembly<{ readonly sections: readonly AssembledGraphSection[] }>;
|
|
43
|
-
details:
|
|
53
|
+
details: GraphDetails;
|
|
44
54
|
displaySections: readonly ToolDisplaySection[];
|
|
45
55
|
}
|
|
46
56
|
|
|
@@ -74,13 +84,14 @@ export function assembleGraphResult(input: {
|
|
|
74
84
|
})),
|
|
75
85
|
evidenceLists,
|
|
76
86
|
nextQueries: [],
|
|
77
|
-
readNext: sections
|
|
87
|
+
readNext: graphReadNext(sections),
|
|
78
88
|
candidateCount,
|
|
79
89
|
confidence,
|
|
80
90
|
provenance,
|
|
81
91
|
});
|
|
82
92
|
|
|
83
|
-
const
|
|
93
|
+
const displays = sections.map((section) => graphDisplaySection(section, input.cwd));
|
|
94
|
+
const displaySections = displays.map(({ display }) => display);
|
|
84
95
|
|
|
85
96
|
return {
|
|
86
97
|
displayName: input.displayName,
|
|
@@ -90,51 +101,36 @@ export function assembleGraphResult(input: {
|
|
|
90
101
|
assembled,
|
|
91
102
|
displaySections,
|
|
92
103
|
details: {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
104
|
+
targetName: input.displayName,
|
|
105
|
+
targetFile: input.resolvedDisplayFile,
|
|
106
|
+
sections: sections.map((section, index) =>
|
|
107
|
+
graphSectionDetails(section, input.cwd, displays[index].fileGroups),
|
|
108
|
+
),
|
|
109
|
+
readNext: assembledReadNext(assembled),
|
|
97
110
|
evidenceLists: [...assembled.evidenceLists],
|
|
98
|
-
nextQueries: assembledNextQueries(assembled),
|
|
99
111
|
},
|
|
100
112
|
};
|
|
101
113
|
}
|
|
102
114
|
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
return createToolDisplaySection({
|
|
106
|
-
key: `graph.${section.rel}`,
|
|
107
|
-
title: section.rel,
|
|
108
|
-
items: [section.message],
|
|
109
|
-
format: (message) => `Unavailable — ${message}`,
|
|
110
|
-
totalCount: 1,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return createToolDisplaySection({
|
|
115
|
-
key: `graph.${section.rel}`,
|
|
116
|
-
title: section.rel,
|
|
117
|
-
items: section.evidence.items as readonly unknown[],
|
|
118
|
-
totalCount: section.evidence.metadata.totalCount,
|
|
119
|
-
omittedCount: section.evidence.metadata.omittedCount,
|
|
120
|
-
partialReason: section.evidence.metadata.partialReason,
|
|
121
|
-
format: (item) => formatGraphDisplayItem(section.rel, item, cwd),
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function formatGraphDisplayItem(
|
|
126
|
-
relation: "references" | "callees" | "implements",
|
|
127
|
-
item: unknown,
|
|
115
|
+
function graphSectionDetails(
|
|
116
|
+
section: AssembledGraphSection,
|
|
128
117
|
cwd: string,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
118
|
+
fileGroups: GraphFileGroup[],
|
|
119
|
+
): GraphSectionDetails {
|
|
120
|
+
const calls = section.kind === "ok" && section.rel === "callees" ? section.data : null;
|
|
121
|
+
return {
|
|
122
|
+
rel: section.rel,
|
|
123
|
+
source: section.rel === "callees" ? "structural" : "semantic",
|
|
124
|
+
status: section.kind === "ok" ? evidenceStatus(section.evidence) : "unavailable",
|
|
125
|
+
message: section.kind === "unavailable" ? section.message : null,
|
|
126
|
+
externalCount:
|
|
127
|
+
section.kind === "ok" && section.rel !== "callees" ? section.data.externalCount : 0,
|
|
128
|
+
enclosingScope: calls
|
|
129
|
+
? { ...calls.enclosingScope, file: toDisplayPath(cwd, calls.enclosingScope.file) }
|
|
130
|
+
: null,
|
|
131
|
+
depth: calls?.depth ?? null,
|
|
132
|
+
fileGroups,
|
|
133
|
+
};
|
|
138
134
|
}
|
|
139
135
|
|
|
140
136
|
function assembleGraphSection(section: GraphSection, maxResults: number): AssembledGraphSection {
|
|
@@ -181,11 +177,10 @@ function createRelationEvidenceList<T>(params: {
|
|
|
181
177
|
invalidLocationCount: number;
|
|
182
178
|
partialReason: RelationLocationPartialReason | null;
|
|
183
179
|
}): EvidenceList<T> {
|
|
184
|
-
const evidence =
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
});
|
|
180
|
+
const evidence =
|
|
181
|
+
params.partialReason === "provider-limited"
|
|
182
|
+
? createPartialEvidenceList({ ...params, partialReason: params.partialReason })
|
|
183
|
+
: createEvidenceList(params);
|
|
189
184
|
if (params.partialReason === null) return evidence;
|
|
190
185
|
return {
|
|
191
186
|
...evidence,
|
|
@@ -247,38 +242,7 @@ export function finishGraphResult(outcome: GraphOutcome, cwd: string): CodeIntel
|
|
|
247
242
|
return searchErrorResult(`**Error:** ${outcome.message}`, { message: outcome.message });
|
|
248
243
|
}
|
|
249
244
|
if (outcome.kind === "disambiguation" || outcome.kind === "kind-mismatch") {
|
|
250
|
-
|
|
251
|
-
outcome.kind === "kind-mismatch"
|
|
252
|
-
? `**No target matched provider kind \`${outcome.requestedKind}\`. Near matches:**`
|
|
253
|
-
: "**Target is ambiguous. Choose one candidate handle:**",
|
|
254
|
-
"",
|
|
255
|
-
];
|
|
256
|
-
for (const candidate of outcome.candidates) {
|
|
257
|
-
lines.push(
|
|
258
|
-
`- \`${candidate.targetId}\` — ${candidate.name} (\`${candidate.kind ?? "unknown"}\`) at ${candidate.file}:${candidate.line}:${candidate.character}`,
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
if (outcome.kind === "kind-mismatch") {
|
|
262
|
-
lines.push(
|
|
263
|
-
"",
|
|
264
|
-
"Retry without `symbolKind`, use an observed provider kind, or choose a handle.",
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
return searchErrorResult(lines.join("\n"), {
|
|
268
|
-
message:
|
|
269
|
-
outcome.kind === "kind-mismatch"
|
|
270
|
-
? `No target matched provider kind ${outcome.requestedKind}.`
|
|
271
|
-
: "The target is ambiguous.",
|
|
272
|
-
displaySections: [
|
|
273
|
-
createToolDisplaySection({
|
|
274
|
-
key: "graph.candidates",
|
|
275
|
-
title: "Candidates",
|
|
276
|
-
items: outcome.candidates,
|
|
277
|
-
format: (candidate) =>
|
|
278
|
-
`${candidate.targetId} — ${candidate.name} (${candidate.kind ?? "unknown"}) at ${candidate.file}:${candidate.line}:${candidate.character}`,
|
|
279
|
-
}),
|
|
280
|
-
],
|
|
281
|
-
});
|
|
245
|
+
return finishGraphCandidates(outcome);
|
|
282
246
|
}
|
|
283
247
|
|
|
284
248
|
const assembly = assembleGraphResult({
|
|
@@ -288,13 +252,84 @@ export function finishGraphResult(outcome: GraphOutcome, cwd: string): CodeIntel
|
|
|
288
252
|
maxResults: outcome.maxResults,
|
|
289
253
|
cwd,
|
|
290
254
|
});
|
|
255
|
+
const displayTruncated = hasHiddenDisplayEvidence(assembly);
|
|
291
256
|
return {
|
|
292
257
|
content: renderGraphResult(assembly),
|
|
293
258
|
details: {
|
|
294
|
-
type: "
|
|
259
|
+
type: "graph",
|
|
295
260
|
data: assembly.details,
|
|
296
261
|
status: "completed",
|
|
297
262
|
displaySections: assembly.displaySections,
|
|
263
|
+
...(displayTruncated ? { truncation: { truncated: false, displayTruncated: true } } : {}),
|
|
298
264
|
},
|
|
299
265
|
};
|
|
300
266
|
}
|
|
267
|
+
|
|
268
|
+
function finishGraphCandidates(
|
|
269
|
+
outcome: Extract<GraphOutcome, { kind: "disambiguation" | "kind-mismatch" }>,
|
|
270
|
+
): CodeIntelResult {
|
|
271
|
+
const lines = [
|
|
272
|
+
outcome.kind === "kind-mismatch"
|
|
273
|
+
? `**No target matched provider kind \`${outcome.requestedKind}\`. Near matches:**`
|
|
274
|
+
: "**Target is ambiguous. Choose one candidate handle:**",
|
|
275
|
+
"",
|
|
276
|
+
];
|
|
277
|
+
for (const candidate of outcome.candidates) {
|
|
278
|
+
lines.push(
|
|
279
|
+
`- \`${candidate.targetId}\` — ${candidate.name} (\`${candidate.kind ?? "unknown"}\`) at ${candidate.file}:${candidate.line}:${candidate.character}`,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
const evidence = graphCandidateEvidence(outcome);
|
|
283
|
+
lines.push("", formatGraphEvidence(evidence, "candidates"));
|
|
284
|
+
if (outcome.kind === "kind-mismatch") {
|
|
285
|
+
lines.push(
|
|
286
|
+
"",
|
|
287
|
+
"Retry without `symbolKind`, use an observed provider kind, or choose a handle.",
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
const displaySections = [
|
|
291
|
+
createToolDisplaySection({
|
|
292
|
+
key: "graph.candidates",
|
|
293
|
+
title: "Candidates",
|
|
294
|
+
items: outcome.candidates,
|
|
295
|
+
totalCount: evidence.totalCount,
|
|
296
|
+
omittedCount: evidence.omittedCount,
|
|
297
|
+
partialReason: evidence.partialReason,
|
|
298
|
+
format: (candidate) => formatCandidateRow(candidate, "handle-first"),
|
|
299
|
+
}),
|
|
300
|
+
];
|
|
301
|
+
return searchErrorResult(lines.join("\n"), {
|
|
302
|
+
confidence: "semantic",
|
|
303
|
+
evidenceLists: [evidence],
|
|
304
|
+
nextQueries:
|
|
305
|
+
outcome.kind === "kind-mismatch"
|
|
306
|
+
? ["Retry without symbolKind, use an observed provider kind, or choose a near-match handle"]
|
|
307
|
+
: ["Choose one candidate handle, or narrow the symbol selector with scope or symbolKind"],
|
|
308
|
+
status: outcome.kind === "disambiguation" ? "disambiguation" : "invalid-input",
|
|
309
|
+
message:
|
|
310
|
+
outcome.kind === "kind-mismatch"
|
|
311
|
+
? `No target matched provider kind ${outcome.requestedKind}.`
|
|
312
|
+
: "The target is ambiguous.",
|
|
313
|
+
displaySections,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function graphCandidateEvidence(
|
|
318
|
+
outcome: Extract<GraphOutcome, { kind: "disambiguation" | "kind-mismatch" }>,
|
|
319
|
+
): EvidenceListMetadata {
|
|
320
|
+
return {
|
|
321
|
+
key: "graph.candidates",
|
|
322
|
+
totalCount: outcome.totalCount,
|
|
323
|
+
shownCount: outcome.candidates.length,
|
|
324
|
+
omittedCount: outcome.omittedCount,
|
|
325
|
+
partialReason: outcome.partialReason,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function hasHiddenDisplayEvidence(assembly: GraphResultAssembly): boolean {
|
|
330
|
+
return assembly.sections.some(
|
|
331
|
+
(section, index) =>
|
|
332
|
+
section.kind === "ok" &&
|
|
333
|
+
assembly.displaySections[index].shownCount < section.evidence.items.length,
|
|
334
|
+
);
|
|
335
|
+
}
|