@mrclrchtr/supi-code-intelligence 6.4.0 → 7.0.1
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 +6 -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/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 +608 -45
- 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 +31 -11
- package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +19 -3
- 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 +12 -1
- package/src/session/health-types.ts +18 -6
- package/src/session/health-workflow.ts +21 -19
- package/src/session/orientation-types.ts +5 -6
- package/src/session/orientation-workflow.ts +10 -2
- package/src/session/target-workflow.ts +9 -6
- package/src/substrate/lsp/source-tracking.ts +11 -6
- package/src/tool/code_find/guidance.ts +2 -2
- 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 +1 -1
- 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 +2 -4
- package/src/tool/code_health/markdown.ts +75 -58
- package/src/tool/code_health/refresh-outcome.ts +41 -1
- package/src/tool/code_health/refresh-status.ts +114 -48
- 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 +25 -38
- package/src/tool/code_inspect/tui.ts +7 -1
- 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 +1 -1
- package/src/tool/code_refactor_plan/tui.ts +7 -1
- package/src/tool/code_resolve/guidance.ts +2 -4
- package/src/tool/code_resolve/result.ts +13 -10
- package/src/tool/code_resolve/tui.ts +18 -1
- 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
|
@@ -11,6 +11,8 @@ export interface CalleesResult {
|
|
|
11
11
|
enclosingScope: CalleeScope | null;
|
|
12
12
|
callees: CalleeEntry[];
|
|
13
13
|
confidence: "structural" | "unavailable";
|
|
14
|
+
/** Original provider reason when callee evidence is unavailable. */
|
|
15
|
+
message: string | null;
|
|
14
16
|
depth: "direct" | "deep";
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -30,7 +32,7 @@ export async function collectCallees(
|
|
|
30
32
|
control?: CodeRequestControl,
|
|
31
33
|
): Promise<CalleesResult> {
|
|
32
34
|
if (!deps.provider?.calleesAt) {
|
|
33
|
-
return unavailableCallees(targetName);
|
|
35
|
+
return unavailableCallees(targetName, "No structural callee provider", depth);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const depthOrOptions = control ? { depth, control } : depth;
|
|
@@ -40,8 +42,8 @@ export async function collectCallees(
|
|
|
40
42
|
targetCharacter,
|
|
41
43
|
depthOrOptions,
|
|
42
44
|
);
|
|
43
|
-
if (result.kind !== "success"
|
|
44
|
-
return unavailableCallees(targetName);
|
|
45
|
+
if (result.kind !== "success") {
|
|
46
|
+
return unavailableCallees(targetName, result.message, depth);
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
void maxResults;
|
|
@@ -53,9 +55,10 @@ export async function collectCallees(
|
|
|
53
55
|
);
|
|
54
56
|
const callees: CalleeEntry[] = result.data.callees.map((c) => ({
|
|
55
57
|
name: c.name,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
...(c.displayName ? { displayName: c.displayName } : {}),
|
|
59
|
+
file: targetFile,
|
|
60
|
+
line: c.startLine,
|
|
61
|
+
character: c.startCharacter,
|
|
59
62
|
}));
|
|
60
63
|
|
|
61
64
|
return {
|
|
@@ -64,18 +67,24 @@ export async function collectCallees(
|
|
|
64
67
|
enclosingScope,
|
|
65
68
|
callees,
|
|
66
69
|
confidence: "structural",
|
|
70
|
+
message: null,
|
|
67
71
|
depth: result.data.depth ?? depth,
|
|
68
72
|
};
|
|
69
73
|
}
|
|
70
74
|
|
|
71
|
-
function unavailableCallees(
|
|
75
|
+
function unavailableCallees(
|
|
76
|
+
targetName: string | null,
|
|
77
|
+
message: string,
|
|
78
|
+
depth: "direct" | "deep",
|
|
79
|
+
): CalleesResult {
|
|
72
80
|
return {
|
|
73
81
|
kind: "callees",
|
|
74
82
|
targetName: targetName ?? "symbol",
|
|
75
83
|
enclosingScope: null,
|
|
76
84
|
callees: [],
|
|
77
85
|
confidence: "unavailable",
|
|
78
|
-
|
|
86
|
+
message,
|
|
87
|
+
depth,
|
|
79
88
|
};
|
|
80
89
|
}
|
|
81
90
|
|
|
@@ -73,8 +73,7 @@ export async function collectImplementations(
|
|
|
73
73
|
implementations: project,
|
|
74
74
|
externalCount: normalized.external.length,
|
|
75
75
|
invalidLocationCount: normalized.invalidLocationCount,
|
|
76
|
-
partialReason:
|
|
77
|
-
normalized.partialReason ?? (result.kind === "partial" ? "provider-limited" : null),
|
|
76
|
+
partialReason: result.kind === "partial" ? "provider-limited" : normalized.partialReason,
|
|
78
77
|
confidence: "semantic",
|
|
79
78
|
};
|
|
80
79
|
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "./provider-locations.ts";
|
|
14
14
|
import type { CallerEvidence, CallerReference, RelationsServiceDeps } from "./types.ts";
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
interface CallerEvidenceData {
|
|
17
17
|
kind: "callers";
|
|
18
18
|
targetName: string;
|
|
19
19
|
references: CallerReference[];
|
|
@@ -22,9 +22,12 @@ export interface CallersResult {
|
|
|
22
22
|
invalidLocationCount: number;
|
|
23
23
|
partialReason: RelationLocationPartialReason | null;
|
|
24
24
|
evidence: CallerEvidence;
|
|
25
|
-
confidence: "semantic" | "unavailable";
|
|
26
25
|
}
|
|
27
26
|
|
|
27
|
+
/** Reference evidence, or the provider reason that prevented collection. */
|
|
28
|
+
export type CallersResult = CallerEvidenceData &
|
|
29
|
+
({ confidence: "semantic" } | { confidence: "unavailable"; message: string });
|
|
30
|
+
|
|
28
31
|
/**
|
|
29
32
|
* Collect callers (references) for a target file/position using semantic provider.
|
|
30
33
|
*/
|
|
@@ -46,6 +49,7 @@ export async function collectCallers(
|
|
|
46
49
|
partialReason: null,
|
|
47
50
|
evidence: "semantic-references",
|
|
48
51
|
confidence: "unavailable",
|
|
52
|
+
message: "No semantic references provider",
|
|
49
53
|
};
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -60,6 +64,7 @@ export async function collectCallers(
|
|
|
60
64
|
partialReason: null,
|
|
61
65
|
evidence: "semantic-references",
|
|
62
66
|
confidence: "unavailable",
|
|
67
|
+
message: result.reason,
|
|
63
68
|
};
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -77,8 +82,7 @@ export async function collectCallers(
|
|
|
77
82
|
references: inProject,
|
|
78
83
|
externalCount: normalized.external.length,
|
|
79
84
|
invalidLocationCount: normalized.invalidLocationCount,
|
|
80
|
-
partialReason:
|
|
81
|
-
normalized.partialReason ?? (result.kind === "partial" ? "provider-limited" : null),
|
|
85
|
+
partialReason: result.kind === "partial" ? "provider-limited" : normalized.partialReason,
|
|
82
86
|
evidence: "semantic-references",
|
|
83
87
|
confidence: "semantic",
|
|
84
88
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SemanticProvider, StructuralProvider } from "@mrclrchtr/supi-code-runtime/api";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Shared types for the relations analysis modules.
|
|
@@ -32,13 +32,15 @@ export interface CalleeScope {
|
|
|
32
32
|
/** One direct structural callee entry from an enclosing-scope lookup. */
|
|
33
33
|
export interface CalleeEntry {
|
|
34
34
|
name: string;
|
|
35
|
+
/** Syntax-based preview only; the full name remains the grouping key. */
|
|
36
|
+
displayName?: string;
|
|
35
37
|
file: string;
|
|
36
38
|
line: number;
|
|
37
39
|
character: number;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
/**
|
|
41
|
-
export type CallEntry =
|
|
42
|
+
/** One structural call site with a 1-based UTF-16 coordinate. */
|
|
43
|
+
export type CallEntry = CalleeEntry;
|
|
42
44
|
|
|
43
45
|
/** One implementation entry from a semantic implementation lookup. */
|
|
44
46
|
export interface ImplementationEntry {
|
|
@@ -54,32 +56,6 @@ export interface RelationsServiceDeps {
|
|
|
54
56
|
provider: {
|
|
55
57
|
references?: SemanticProvider["references"];
|
|
56
58
|
implementation?: SemanticProvider["implementation"];
|
|
57
|
-
calleesAt?:
|
|
58
|
-
file: string,
|
|
59
|
-
line: number,
|
|
60
|
-
character: number,
|
|
61
|
-
depthOrOptions?:
|
|
62
|
-
| "direct"
|
|
63
|
-
| "deep"
|
|
64
|
-
| { depth?: "direct" | "deep"; control?: CodeRequestControl },
|
|
65
|
-
) => Promise<{
|
|
66
|
-
kind: string;
|
|
67
|
-
data?: {
|
|
68
|
-
enclosingScope?: {
|
|
69
|
-
name?: string;
|
|
70
|
-
startLine?: number;
|
|
71
|
-
endLine?: number;
|
|
72
|
-
};
|
|
73
|
-
callees: Array<{
|
|
74
|
-
name: string;
|
|
75
|
-
file?: string;
|
|
76
|
-
location?: string;
|
|
77
|
-
startLine?: number;
|
|
78
|
-
startCharacter?: number;
|
|
79
|
-
}>;
|
|
80
|
-
depth?: "direct" | "deep";
|
|
81
|
-
};
|
|
82
|
-
message?: string;
|
|
83
|
-
}>;
|
|
59
|
+
calleesAt?: StructuralProvider["calleesAt"];
|
|
84
60
|
} | null;
|
|
85
61
|
}
|
|
@@ -191,7 +191,9 @@ async function candidatesFromSymbols(
|
|
|
191
191
|
): Promise<{
|
|
192
192
|
kind: "disambiguation";
|
|
193
193
|
candidates: DisambiguationCandidateData[];
|
|
194
|
+
totalCount: number;
|
|
194
195
|
omittedCount: number;
|
|
196
|
+
partialReason: null;
|
|
195
197
|
}> {
|
|
196
198
|
const candidates = await Promise.all(
|
|
197
199
|
matched.map(async (s, idx) => {
|
|
@@ -215,7 +217,13 @@ async function candidatesFromSymbols(
|
|
|
215
217
|
} satisfies DisambiguationCandidateData;
|
|
216
218
|
}),
|
|
217
219
|
);
|
|
218
|
-
return {
|
|
220
|
+
return {
|
|
221
|
+
kind: "disambiguation",
|
|
222
|
+
candidates,
|
|
223
|
+
totalCount: candidates.length,
|
|
224
|
+
omittedCount: 0,
|
|
225
|
+
partialReason: null,
|
|
226
|
+
};
|
|
219
227
|
}
|
|
220
228
|
|
|
221
229
|
/** Layer 1: match the coordinate against LSP document symbols. Returns null to fall through. */
|
|
@@ -18,7 +18,11 @@ import { isWithinOrEqual } from "@mrclrchtr/supi-core/project";
|
|
|
18
18
|
import type { TargetSymbolKind } from "../../session/target-input.ts";
|
|
19
19
|
import type { AnchorKind } from "../../session/target-store.ts";
|
|
20
20
|
import { normalizePath } from "../search/paths.ts";
|
|
21
|
-
import type {
|
|
21
|
+
import type {
|
|
22
|
+
DisambiguationCandidateData,
|
|
23
|
+
TargetCandidateCompleteness,
|
|
24
|
+
TargetOutcome,
|
|
25
|
+
} from "./types.ts";
|
|
22
26
|
|
|
23
27
|
const MAX_CANDIDATES = 8; // default fallback when maxResults is not provided
|
|
24
28
|
const NON_EXPORTED_KINDS = new Set(["Variable", "Field", "Property"]);
|
|
@@ -146,6 +150,7 @@ export async function resolveSymbolTarget(
|
|
|
146
150
|
return buildCandidateOutcome({
|
|
147
151
|
kind: "kind-mismatch",
|
|
148
152
|
candidates: eligible,
|
|
153
|
+
...candidateCompleteness(result, eligible.length),
|
|
149
154
|
semantic,
|
|
150
155
|
cwd,
|
|
151
156
|
maxResults: options.maxResults,
|
|
@@ -155,6 +160,7 @@ export async function resolveSymbolTarget(
|
|
|
155
160
|
}
|
|
156
161
|
return resolveCandidates({
|
|
157
162
|
candidates: exactKind,
|
|
163
|
+
...candidateCompleteness(result, exactKind.length),
|
|
158
164
|
semantic,
|
|
159
165
|
cwd,
|
|
160
166
|
maxResults: options.maxResults,
|
|
@@ -164,6 +170,7 @@ export async function resolveSymbolTarget(
|
|
|
164
170
|
|
|
165
171
|
return resolveCandidates({
|
|
166
172
|
candidates: eligible,
|
|
173
|
+
...candidateCompleteness(result, eligible.length),
|
|
167
174
|
semantic,
|
|
168
175
|
cwd,
|
|
169
176
|
maxResults: options?.maxResults,
|
|
@@ -179,19 +186,15 @@ function normalizeProviderKind(kind: string): string {
|
|
|
179
186
|
return kind.replace(/[\s_-]/g, "").toLowerCase();
|
|
180
187
|
}
|
|
181
188
|
|
|
182
|
-
async function resolveCandidates(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
cwd
|
|
186
|
-
maxResults?: number;
|
|
187
|
-
control?: CodeRequestControl;
|
|
188
|
-
}): Promise<TargetOutcome> {
|
|
189
|
-
const { candidates, semantic, cwd, maxResults, control } = options;
|
|
189
|
+
async function resolveCandidates(
|
|
190
|
+
options: CandidateOutcomeBase & Pick<TargetCandidateCompleteness, "totalCount" | "partialReason">,
|
|
191
|
+
): Promise<TargetOutcome> {
|
|
192
|
+
const { candidates, semantic, cwd, maxResults, control, totalCount, partialReason } = options;
|
|
190
193
|
const ranged = candidates.filter(
|
|
191
194
|
(candidate) =>
|
|
192
195
|
candidate.declarationAnchor.line > 0 || candidate.declarationAnchor.character > 0,
|
|
193
196
|
);
|
|
194
|
-
if (ranged.length === 1) {
|
|
197
|
+
if (ranged.length === 1 && totalCount !== null) {
|
|
195
198
|
return resolvedTarget(await refineResolvedSymbolAnchor(ranged[0], semantic, control));
|
|
196
199
|
}
|
|
197
200
|
return buildCandidateOutcome({
|
|
@@ -200,6 +203,8 @@ async function resolveCandidates(options: {
|
|
|
200
203
|
semantic,
|
|
201
204
|
cwd,
|
|
202
205
|
maxResults,
|
|
206
|
+
totalCount,
|
|
207
|
+
partialReason,
|
|
203
208
|
control,
|
|
204
209
|
});
|
|
205
210
|
}
|
|
@@ -230,13 +235,24 @@ interface CandidateOutcomeBase {
|
|
|
230
235
|
semantic: SemanticSubstrate;
|
|
231
236
|
cwd: string;
|
|
232
237
|
maxResults?: number;
|
|
238
|
+
control?: CodeRequestControl;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function candidateCompleteness(
|
|
242
|
+
result: Exclude<CodeQueryResult<CodeSymbol[]>, { kind: "unavailable" }>,
|
|
243
|
+
totalCount: number,
|
|
244
|
+
): Pick<TargetCandidateCompleteness, "totalCount" | "partialReason"> {
|
|
245
|
+
return result.kind === "partial"
|
|
246
|
+
? { totalCount: null, partialReason: "provider-limited" }
|
|
247
|
+
: { totalCount, partialReason: null };
|
|
233
248
|
}
|
|
234
249
|
|
|
235
250
|
type CandidateOutcomeOptions = CandidateOutcomeBase &
|
|
251
|
+
Pick<TargetCandidateCompleteness, "totalCount" | "partialReason"> &
|
|
236
252
|
(
|
|
237
253
|
| { kind: "disambiguation"; requestedKind?: never }
|
|
238
254
|
| { kind: "kind-mismatch"; requestedKind: TargetSymbolKind }
|
|
239
|
-
)
|
|
255
|
+
);
|
|
240
256
|
|
|
241
257
|
/**
|
|
242
258
|
* Refine only bounded visible candidates to name anchors while retaining the
|
|
@@ -271,7 +287,9 @@ async function buildCandidateOutcome(
|
|
|
271
287
|
);
|
|
272
288
|
const common = {
|
|
273
289
|
candidates: toDisambiguationCandidates(refined, options.cwd),
|
|
290
|
+
totalCount: options.totalCount,
|
|
274
291
|
omittedCount: Math.max(0, options.candidates.length - cap),
|
|
292
|
+
partialReason: options.partialReason,
|
|
275
293
|
};
|
|
276
294
|
return options.kind === "kind-mismatch"
|
|
277
295
|
? {
|
|
@@ -136,6 +136,16 @@ export interface DisambiguationCandidateData {
|
|
|
136
136
|
anchorKind: AnchorKind;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/** Completeness metadata for a bounded candidate collection. */
|
|
140
|
+
export interface TargetCandidateCompleteness {
|
|
141
|
+
/** Exact candidate total, or null when the provider returned partial data. */
|
|
142
|
+
totalCount: number | null;
|
|
143
|
+
/** Candidates returned by the provider but hidden by the target cap. */
|
|
144
|
+
omittedCount: number;
|
|
145
|
+
/** Why the provider cannot establish an exact candidate total. */
|
|
146
|
+
partialReason: "provider-limited" | null;
|
|
147
|
+
}
|
|
148
|
+
|
|
139
149
|
/**
|
|
140
150
|
* Typed outcome of a resolution attempt.
|
|
141
151
|
*
|
|
@@ -145,16 +155,14 @@ export interface DisambiguationCandidateData {
|
|
|
145
155
|
export type TargetOutcome =
|
|
146
156
|
| { kind: "resolved"; target: ResolvedTargetData }
|
|
147
157
|
| { kind: "group"; group: ResolvedTargetGroupData }
|
|
148
|
-
| {
|
|
158
|
+
| ({
|
|
149
159
|
kind: "disambiguation";
|
|
150
160
|
candidates: DisambiguationCandidateData[];
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
| {
|
|
161
|
+
} & TargetCandidateCompleteness)
|
|
162
|
+
| ({
|
|
154
163
|
kind: "kind-mismatch";
|
|
155
164
|
requestedKind: TargetSymbolKind;
|
|
156
165
|
candidates: DisambiguationCandidateData[];
|
|
157
|
-
|
|
158
|
-
}
|
|
166
|
+
} & TargetCandidateCompleteness)
|
|
159
167
|
| { kind: "unavailable"; reason: string }
|
|
160
168
|
| { kind: "error"; message: string };
|
package/src/api.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "@mrclrchtr/supi-code-runtime/api";
|
|
8
8
|
import type { CodeProvider } from "../../analysis/provider.ts";
|
|
9
9
|
import {
|
|
10
|
+
readNextAround,
|
|
10
11
|
readNextEnclosingScope,
|
|
11
12
|
readNextTarget,
|
|
12
13
|
readNextTopSites,
|
|
@@ -75,7 +76,7 @@ async function collectReferences(options: CollectRelationOptions): Promise<Graph
|
|
|
75
76
|
},
|
|
76
77
|
});
|
|
77
78
|
if (result.confidence === "unavailable") {
|
|
78
|
-
return { kind: "unavailable", rel: "references", message:
|
|
79
|
+
return { kind: "unavailable", rel: "references", message: result.message };
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
const targetLine = options.position.line + 1;
|
|
@@ -132,7 +133,11 @@ async function collectCalleesRelation(options: CollectRelationOptions): Promise<
|
|
|
132
133
|
options.requestControl,
|
|
133
134
|
);
|
|
134
135
|
if (result.confidence === "unavailable") {
|
|
135
|
-
return {
|
|
136
|
+
return {
|
|
137
|
+
kind: "unavailable",
|
|
138
|
+
rel: "callees",
|
|
139
|
+
message: `${result.message ?? "Callees unavailable"}\nUse code_inspect at the target position to check the scope.`,
|
|
140
|
+
};
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
const enclosingScope = result.enclosingScope ?? {
|
|
@@ -143,8 +148,10 @@ async function collectCalleesRelation(options: CollectRelationOptions): Promise<
|
|
|
143
148
|
};
|
|
144
149
|
const calls: CallEntry[] = result.callees.map((callee) => ({
|
|
145
150
|
name: callee.name,
|
|
151
|
+
...(callee.displayName ? { displayName: callee.displayName } : {}),
|
|
146
152
|
file: callee.file,
|
|
147
153
|
line: callee.line,
|
|
154
|
+
character: callee.character,
|
|
148
155
|
}));
|
|
149
156
|
return {
|
|
150
157
|
kind: "ok",
|
|
@@ -192,6 +199,14 @@ async function collectImplementationsRelation(
|
|
|
192
199
|
invalidLocationCount: result.invalidLocationCount,
|
|
193
200
|
partialReason: result.partialReason,
|
|
194
201
|
},
|
|
195
|
-
readNext:
|
|
202
|
+
readNext: result.implementations
|
|
203
|
+
.slice(0, Math.min(options.maxResults, 2))
|
|
204
|
+
.map((implementation) =>
|
|
205
|
+
readNextAround(
|
|
206
|
+
toDisplayPath(options.cwd, implementation.file),
|
|
207
|
+
implementation.line,
|
|
208
|
+
"inspect an implementation site",
|
|
209
|
+
),
|
|
210
|
+
),
|
|
196
211
|
};
|
|
197
212
|
}
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
} from "@mrclrchtr/supi-code-runtime/api";
|
|
5
5
|
import {
|
|
6
6
|
emptyProcessCrashRecoveryReport,
|
|
7
|
+
emptyStartupRetryReport,
|
|
8
|
+
type SemanticReadinessResult,
|
|
7
9
|
type WorkspaceDiagnosticReport,
|
|
8
10
|
type WorkspaceLspRuntime,
|
|
9
11
|
} from "@mrclrchtr/supi-lsp/api";
|
|
@@ -29,6 +31,8 @@ interface HealthRefreshAttemptOptions {
|
|
|
29
31
|
|
|
30
32
|
export interface HealthRefreshCollection {
|
|
31
33
|
readonly attempt: HealthRefreshAttempt;
|
|
34
|
+
/** File readiness observed by the same explicit refresh call. */
|
|
35
|
+
readonly fileReadiness?: SemanticReadinessResult;
|
|
32
36
|
/** Next typed maintenance state, committed only after the attempt returns. */
|
|
33
37
|
readonly maintenanceState: LspMaintenanceState;
|
|
34
38
|
/** Final report from the runtime, retained only for the current workflow. */
|
|
@@ -58,12 +62,13 @@ async function collectFileRefreshAttempt(
|
|
|
58
62
|
});
|
|
59
63
|
const readiness = await options.runtime.waitUntilReadyForFile(
|
|
60
64
|
scope.path,
|
|
61
|
-
|
|
65
|
+
{ retryFailedRoute: true },
|
|
62
66
|
options.control,
|
|
63
67
|
);
|
|
64
68
|
const fileReadiness: HealthFileReadiness =
|
|
65
69
|
readiness.kind === "ready" ? "ready" : readiness.kind === "timeout" ? "pending" : "unavailable";
|
|
66
70
|
return {
|
|
71
|
+
fileReadiness: readiness,
|
|
67
72
|
maintenanceState: maintenance.maintenanceState,
|
|
68
73
|
attempt: {
|
|
69
74
|
kind: "completed",
|
|
@@ -75,6 +80,7 @@ async function collectFileRefreshAttempt(
|
|
|
75
80
|
fileReadiness,
|
|
76
81
|
restartedClients: 0,
|
|
77
82
|
processCrashRecovery: readiness.processCrashRecovery ?? emptyProcessCrashRecoveryReport(),
|
|
83
|
+
startupRetry: readiness.startupRetry ?? emptyStartupRetryReport(),
|
|
78
84
|
staleAssessment: {
|
|
79
85
|
scope: "file",
|
|
80
86
|
suspected: null,
|
|
@@ -111,6 +117,7 @@ async function collectWorkspaceRefreshAttempt(
|
|
|
111
117
|
operationScope: "workspace-runtime",
|
|
112
118
|
diagnosticEvidence: maintenance.diagnosticEvidence,
|
|
113
119
|
processCrashRecovery: emptyProcessCrashRecoveryReport(),
|
|
120
|
+
startupRetry: emptyStartupRetryReport(),
|
|
114
121
|
...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
|
|
115
122
|
reason: maintenance.failureReason,
|
|
116
123
|
},
|
|
@@ -127,6 +134,7 @@ async function collectWorkspaceRefreshAttempt(
|
|
|
127
134
|
// runtime then performs a fresh pass that includes the replacement.
|
|
128
135
|
initialEvidence: maintenance.diagnosticEvidence,
|
|
129
136
|
processCrashDemand: {
|
|
137
|
+
explicit: true,
|
|
130
138
|
...(workspaceScope?.filter ? { scopes: [workspaceScope.filter] } : {}),
|
|
131
139
|
},
|
|
132
140
|
});
|
|
@@ -154,6 +162,7 @@ async function collectWorkspaceRefreshAttempt(
|
|
|
154
162
|
},
|
|
155
163
|
diagnosticEvidence,
|
|
156
164
|
processCrashRecovery: recovery.processCrashRecovery,
|
|
165
|
+
startupRetry: recovery.startupRetry,
|
|
157
166
|
...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
|
|
158
167
|
reason: recovery.refreshFailureReason,
|
|
159
168
|
},
|
|
@@ -171,6 +180,7 @@ async function collectWorkspaceRefreshAttempt(
|
|
|
171
180
|
attemptedActiveClients: recovery.attemptedClients,
|
|
172
181
|
restartedClients: recovery.restartedClients,
|
|
173
182
|
processCrashRecovery: recovery.processCrashRecovery,
|
|
183
|
+
startupRetry: recovery.startupRetry,
|
|
174
184
|
diagnosticEvidence,
|
|
175
185
|
...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
|
|
176
186
|
staleAssessment: {
|
|
@@ -196,6 +206,7 @@ async function collectWorkspaceRefreshAttempt(
|
|
|
196
206
|
operationScope: "workspace-runtime",
|
|
197
207
|
diagnosticEvidence: maintenance.diagnosticEvidence,
|
|
198
208
|
processCrashRecovery: emptyProcessCrashRecoveryReport(),
|
|
209
|
+
startupRetry: emptyStartupRetryReport(),
|
|
199
210
|
...(maintenance.sourceTracking ? { sourceTracking: maintenance.sourceTracking } : {}),
|
|
200
211
|
reason: errorMessage(error),
|
|
201
212
|
},
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
ProcessCrashRecoveryReport,
|
|
5
5
|
ProjectServerInfo,
|
|
6
6
|
ProjectServerStatusReason,
|
|
7
|
+
StartupRetryReport,
|
|
7
8
|
} from "@mrclrchtr/supi-lsp/api";
|
|
8
9
|
import type { CapabilityWarningReport } from "../analysis/capability/capability-warnings.ts";
|
|
9
10
|
import type { SourceTrackingReport } from "../substrate/lsp/source-tracking.ts";
|
|
@@ -63,7 +64,7 @@ export type HealthDiagnosticObservation =
|
|
|
63
64
|
readonly scope: HealthDiagnosticScope;
|
|
64
65
|
readonly entries: readonly HealthDiagnosticEntry[];
|
|
65
66
|
readonly evidence: DiagnosticEvidenceSummary;
|
|
66
|
-
/** Tsconfig scope decision for
|
|
67
|
+
/** Tsconfig scope decision for an applicable TypeScript or JavaScript file. */
|
|
67
68
|
readonly scopeStatus?: FileScopeDecision;
|
|
68
69
|
}
|
|
69
70
|
| {
|
|
@@ -72,7 +73,7 @@ export type HealthDiagnosticObservation =
|
|
|
72
73
|
readonly entries: readonly HealthDiagnosticEntry[];
|
|
73
74
|
readonly evidence: DiagnosticEvidenceSummary;
|
|
74
75
|
readonly reason: string;
|
|
75
|
-
/** Tsconfig scope decision for
|
|
76
|
+
/** Tsconfig scope decision for an applicable TypeScript or JavaScript file. */
|
|
76
77
|
readonly scopeStatus?: FileScopeDecision;
|
|
77
78
|
}
|
|
78
79
|
| {
|
|
@@ -81,7 +82,7 @@ export type HealthDiagnosticObservation =
|
|
|
81
82
|
readonly entries: readonly HealthDiagnosticEntry[];
|
|
82
83
|
readonly evidence: DiagnosticEvidenceSummary;
|
|
83
84
|
readonly reason: string;
|
|
84
|
-
/** Tsconfig scope decision for
|
|
85
|
+
/** Tsconfig scope decision for an applicable TypeScript or JavaScript file. */
|
|
85
86
|
readonly scopeStatus?: FileScopeDecision;
|
|
86
87
|
};
|
|
87
88
|
|
|
@@ -93,6 +94,7 @@ export interface HealthStaleAssessment {
|
|
|
93
94
|
readonly warning: string | null;
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
/** Runtime scope of maintenance; it is not the diagnostic result scope. */
|
|
96
98
|
export type HealthRefreshOperationScope = "file-runtime" | "workspace-runtime";
|
|
97
99
|
|
|
98
100
|
/** Readiness result for a file-scoped maintenance attempt. */
|
|
@@ -114,12 +116,17 @@ interface CompletedHealthRefreshAttempt {
|
|
|
114
116
|
readonly restartedClients: number;
|
|
115
117
|
/** Separate outcome for process-crash route recovery. */
|
|
116
118
|
readonly processCrashRecovery: ProcessCrashRecoveryReport;
|
|
119
|
+
/** Separate outcome for initial-start retries. */
|
|
120
|
+
readonly startupRetry?: StartupRetryReport;
|
|
117
121
|
readonly staleAssessment: HealthStaleAssessment;
|
|
118
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Source discovery and bounded tracking facts for broad refreshes. The
|
|
124
|
+
* report's skipped list describes automatic tracking policy, not capability.
|
|
125
|
+
*/
|
|
119
126
|
readonly sourceTracking?: SourceTrackingReport;
|
|
120
127
|
}
|
|
121
128
|
|
|
122
|
-
/** A diagnostic refresh attempt
|
|
129
|
+
/** A diagnostic refresh attempt with separate maintenance and result scopes. */
|
|
123
130
|
export type HealthRefreshAttempt =
|
|
124
131
|
| (CompletedHealthRefreshAttempt & {
|
|
125
132
|
readonly operationScope: "workspace-runtime";
|
|
@@ -147,7 +154,12 @@ export type HealthRefreshAttempt =
|
|
|
147
154
|
readonly diagnosticEvidence?: DiagnosticEvidenceSummary;
|
|
148
155
|
/** Process-crash outcome, when the recovery pass returned one. */
|
|
149
156
|
readonly processCrashRecovery?: ProcessCrashRecoveryReport;
|
|
150
|
-
/**
|
|
157
|
+
/** Initial-start retry outcome, when the recovery pass returned one. */
|
|
158
|
+
readonly startupRetry?: StartupRetryReport;
|
|
159
|
+
/**
|
|
160
|
+
* Source discovery and bounded tracking facts for broad refreshes. The
|
|
161
|
+
* report's skipped list describes automatic tracking policy, not capability.
|
|
162
|
+
*/
|
|
151
163
|
readonly sourceTracking?: SourceTrackingReport;
|
|
152
164
|
/** File readiness outcome, when a file-scoped attempt failed. */
|
|
153
165
|
readonly fileReadiness?: HealthFileReadiness;
|
|
@@ -4,6 +4,7 @@ import type { CapabilityState } from "@mrclrchtr/supi-code-runtime/api";
|
|
|
4
4
|
import { isCodeRequestInterruption } from "@mrclrchtr/supi-code-runtime/api";
|
|
5
5
|
import type {
|
|
6
6
|
LspRuntimeController,
|
|
7
|
+
SemanticReadinessResult,
|
|
7
8
|
WorkspaceDiagnosticReport,
|
|
8
9
|
WorkspaceLspRuntime,
|
|
9
10
|
WorkspaceLspRuntimeState,
|
|
@@ -80,7 +81,6 @@ export async function runHealthWorkflow(
|
|
|
80
81
|
const diagnosticsScope = diagnosticScope(scopeFilter);
|
|
81
82
|
const refreshCollection = await collectRefreshState({
|
|
82
83
|
refreshRequested: request.refresh === true,
|
|
83
|
-
diagnosticsRequested: included.includes("diagnostics"),
|
|
84
84
|
runtime,
|
|
85
85
|
lspState,
|
|
86
86
|
diagnosticsScope,
|
|
@@ -94,6 +94,7 @@ export async function runHealthWorkflow(
|
|
|
94
94
|
scopeFilter,
|
|
95
95
|
lspState,
|
|
96
96
|
capabilityState: capabilityStates.semantic,
|
|
97
|
+
refreshReadiness: refreshCollection.fileReadiness,
|
|
97
98
|
control,
|
|
98
99
|
});
|
|
99
100
|
const semanticReady = semanticState?.kind === "ready";
|
|
@@ -146,6 +147,8 @@ interface SemanticHealthStateOptions {
|
|
|
146
147
|
requested: boolean;
|
|
147
148
|
/** Whether this call requests file-routed evidence rather than passive inventory. */
|
|
148
149
|
fileReadinessRequested: boolean;
|
|
150
|
+
/** Readiness observed by the explicit refresh phase, when one ran. */
|
|
151
|
+
refreshReadiness?: SemanticReadinessResult;
|
|
149
152
|
runtime: WorkspaceLspRuntime | null;
|
|
150
153
|
scopeFilter: string | null;
|
|
151
154
|
lspState: WorkspaceLspRuntimeState;
|
|
@@ -157,12 +160,17 @@ async function establishSemanticHealthState(
|
|
|
157
160
|
options: SemanticHealthStateOptions,
|
|
158
161
|
): Promise<SemanticHealthState | null> {
|
|
159
162
|
if (!options.requested) return null;
|
|
160
|
-
if (options.fileReadinessRequested &&
|
|
161
|
-
const readiness =
|
|
162
|
-
options.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
if (options.fileReadinessRequested && isScopedFile(options.scopeFilter)) {
|
|
164
|
+
const readiness =
|
|
165
|
+
options.refreshReadiness ??
|
|
166
|
+
(options.runtime
|
|
167
|
+
? await options.runtime.waitUntilReadyForFile(
|
|
168
|
+
options.scopeFilter,
|
|
169
|
+
undefined,
|
|
170
|
+
options.control,
|
|
171
|
+
)
|
|
172
|
+
: null);
|
|
173
|
+
if (!readiness) return deriveNonReadySemanticState(options.lspState, options.capabilityState);
|
|
166
174
|
if (readiness.kind === "ready") return { kind: "ready" };
|
|
167
175
|
if (readiness.kind === "timeout") {
|
|
168
176
|
return { kind: "pending", reason: SEMANTIC_READINESS_TIMEOUT_REASON };
|
|
@@ -226,12 +234,12 @@ function collectCapabilityWarnings(
|
|
|
226
234
|
|
|
227
235
|
interface HealthRefreshStateCollection {
|
|
228
236
|
readonly attempt: HealthRefreshState;
|
|
237
|
+
readonly fileReadiness?: SemanticReadinessResult;
|
|
229
238
|
readonly diagnosticReport?: WorkspaceDiagnosticReport;
|
|
230
239
|
}
|
|
231
240
|
|
|
232
241
|
interface RefreshStateOptions {
|
|
233
242
|
readonly refreshRequested: boolean;
|
|
234
|
-
readonly diagnosticsRequested: boolean;
|
|
235
243
|
readonly runtime: WorkspaceLspRuntime | null;
|
|
236
244
|
readonly lspState: WorkspaceLspRuntimeState;
|
|
237
245
|
readonly diagnosticsScope: HealthDiagnosticScope;
|
|
@@ -243,16 +251,7 @@ interface RefreshStateOptions {
|
|
|
243
251
|
async function collectRefreshState(
|
|
244
252
|
options: RefreshStateOptions,
|
|
245
253
|
): Promise<HealthRefreshStateCollection> {
|
|
246
|
-
const { deps,
|
|
247
|
-
if (!diagnosticsRequested) {
|
|
248
|
-
return {
|
|
249
|
-
attempt: {
|
|
250
|
-
kind: "not-requested",
|
|
251
|
-
reason: "Diagnostics were not requested.",
|
|
252
|
-
lastAttempt: deps.lastRefreshAttempt,
|
|
253
|
-
},
|
|
254
|
-
};
|
|
255
|
-
}
|
|
254
|
+
const { deps, diagnosticsScope, lspState, runtime } = options;
|
|
256
255
|
if (!options.refreshRequested) {
|
|
257
256
|
return {
|
|
258
257
|
attempt: {
|
|
@@ -296,7 +295,10 @@ async function collectRefreshState(
|
|
|
296
295
|
});
|
|
297
296
|
deps.updateMaintenanceState(attempt.maintenanceState);
|
|
298
297
|
deps.trackRefreshAttempt(attempt.attempt);
|
|
299
|
-
return
|
|
298
|
+
return {
|
|
299
|
+
...attempt,
|
|
300
|
+
...(attempt.fileReadiness ? { fileReadiness: attempt.fileReadiness } : {}),
|
|
301
|
+
};
|
|
300
302
|
} catch (error) {
|
|
301
303
|
// Cancellation must propagate; a cancelled caller no longer awaits a
|
|
302
304
|
// recorded failed attempt or the refresh data it would carry.
|