@mrclrchtr/supi-code-intelligence 6.1.0 → 6.3.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 +3 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/debug-identity.ts +11 -0
- package/node_modules/@mrclrchtr/supi-core/src/debug.ts +5 -0
- package/node_modules/@mrclrchtr/supi-lsp/README.md +23 -3
- 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-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-identity.ts +11 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug.ts +5 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/README.md +52 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/index.js +785 -129
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/legacy.js +660 -98
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/ignore/package.json +10 -4
- package/node_modules/@mrclrchtr/supi-lsp/package.json +4 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +16 -7
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +0 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-publication.ts +6 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +2 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +5 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +2 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +17 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +40 -18
- package/node_modules/@mrclrchtr/supi-lsp/src/config/config.ts +164 -30
- package/node_modules/@mrclrchtr/supi-lsp/src/config/lsp-settings.ts +9 -87
- package/node_modules/@mrclrchtr/supi-lsp/src/config/server-config.ts +0 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-scope.ts +4 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/config/types.ts +0 -29
- package/node_modules/@mrclrchtr/supi-lsp/src/debug-telemetry.ts +7 -21
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-severity.ts +6 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/diagnostic-summary.ts +11 -14
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +0 -5
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/stale-diagnostics.ts +0 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sentinels.ts +29 -49
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-client-state.ts +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +4 -8
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-helpers.ts +1 -9
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-process-crash-report.ts +106 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-project-info.ts +6 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +9 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +26 -41
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +577 -152
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +4 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-symbol-mapper.ts +59 -28
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +27 -19
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +54 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registration.ts +0 -17
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +74 -19
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-transition-debug.ts +5 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/session/scanner.ts +24 -21
- package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +29 -3
- package/node_modules/@mrclrchtr/supi-lsp/src/summary.ts +19 -40
- package/node_modules/@mrclrchtr/supi-lsp/src/utils.ts +13 -19
- package/node_modules/@mrclrchtr/supi-lsp/src/workspace-path-policy.ts +296 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +6 -18
- 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-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-identity.ts +11 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug.ts +5 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/README.md +29 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs +99 -19
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs.map +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js +94 -18
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js.map +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm +0 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm.map +14 -14
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/package.json +13 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs +97 -19
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs.map +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts +28 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts.map +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts +28 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts.map +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js +92 -18
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js.map +4 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm +0 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm.map +17 -17
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +7 -6
- package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/kotlin/tree-sitter-kotlin.wasm +0 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/kotlin/tree-sitter-kotlin.wasm.json +2 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/sql/tree-sitter-sql.wasm +0 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/sql/tree-sitter-sql.wasm.json +2 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +1 -11
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/coordinates.ts +19 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/language.ts +5 -23
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/operation-support.ts +3 -21
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +5 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +10 -20
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +7 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client.ts +9 -5
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-protocol.ts +134 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-name.ts +96 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +11 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +39 -56
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/exports.ts +9 -7
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/js-binding-pattern.ts +26 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/node-at.ts +2 -21
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-html-sql.ts +144 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline.ts +50 -37
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/scope.ts +138 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +0 -7
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store.ts +1 -14
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime.ts +0 -10
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/service.ts +6 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/worker-main.ts +34 -10
- package/package.json +5 -5
- package/src/analysis/capability/capability-warnings.ts +4 -22
- package/src/analysis/search/ast-scan-timing.ts +4 -2
- package/src/analysis/search/ast-scan.ts +1 -1
- package/src/api.ts +1 -0
- package/src/extension.ts +4 -2
- package/src/session/health-refresh.ts +26 -2
- package/src/session/health-types.ts +19 -0
- package/src/session/input/health-refactor.ts +16 -14
- package/src/session/refactor-types.ts +14 -1
- package/src/session/refactor-workflow.ts +21 -16
- package/src/substrate/lsp/lifecycle.ts +0 -3
- package/src/substrate/lsp/maintenance.ts +4 -5
- package/src/substrate/lsp/settings.ts +7 -9
- package/src/substrate/lsp/state.ts +0 -2
- package/src/substrate/workspace-provider-host.ts +2 -2
- package/src/tool/code_health/file-scope-markdown.ts +43 -0
- package/src/tool/code_health/markdown.ts +66 -66
- package/src/tool/code_health/refresh-outcome.ts +76 -0
- package/src/tool/code_health/refresh-status.ts +212 -23
- package/src/tool/code_health/result.ts +1 -0
- package/src/tool/code_health/tui.ts +18 -5
- package/src/tool/code_refactor_apply/guidance.ts +3 -2
- package/src/tool/code_refactor_plan/guidance.ts +1 -1
- package/src/tool/register.ts +5 -2
- package/src/tool/schemas.ts +21 -11
- package/node_modules/@mrclrchtr/supi-lsp/src/config/server-actions.ts +0 -59
- package/node_modules/@mrclrchtr/supi-lsp/src/pattern-matcher.ts +0 -24
- package/node_modules/@mrclrchtr/supi-tree-sitter/scripts/generate-kotlin-wasm.mjs +0 -132
- package/node_modules/@mrclrchtr/supi-tree-sitter/scripts/generate-sql-wasm.mjs +0 -158
- package/node_modules/@mrclrchtr/supi-tree-sitter/scripts/vendor-wasm.mjs +0 -167
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +0 -42
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-registration.ts +0 -37
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/service-registry.ts +0 -30
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/structure.ts +0 -8
|
@@ -11,9 +11,15 @@ import {
|
|
|
11
11
|
formatProjectServerRouteSummary,
|
|
12
12
|
formatProjectServerStatusReason,
|
|
13
13
|
} from "../../analysis/health/server-status.ts";
|
|
14
|
+
import { makeRelative, renderFileScopeStatus } from "./file-scope-markdown.ts";
|
|
15
|
+
import {
|
|
16
|
+
formatProcessCrashRecovery,
|
|
17
|
+
formatRefreshElapsed,
|
|
18
|
+
formatStaleDiagnosticRestarts as formatStaleDiagnosticRestartsText,
|
|
19
|
+
isFileReadinessPending,
|
|
20
|
+
} from "./refresh-outcome.ts";
|
|
14
21
|
import type {
|
|
15
22
|
HealthData,
|
|
16
|
-
HealthDiagnosticObservation,
|
|
17
23
|
HealthDiagnosticScope,
|
|
18
24
|
HealthRefreshAttempt,
|
|
19
25
|
HealthResultAssembly,
|
|
@@ -48,19 +54,25 @@ function renderRefreshStatus(
|
|
|
48
54
|
if (!hasDiagnostics) return;
|
|
49
55
|
|
|
50
56
|
switch (data.refresh.kind) {
|
|
51
|
-
case "completed":
|
|
57
|
+
case "completed": {
|
|
58
|
+
const fileReadinessPending = isFileReadinessPending(data.refresh, data.semanticState);
|
|
52
59
|
lines.push(
|
|
53
|
-
`**${refreshAttemptLabel(data.refresh)}**: ${asSentence(completedRefreshText(data.refresh))}`,
|
|
60
|
+
`**${refreshAttemptLabel(data.refresh)}**: ${asSentence(completedRefreshText(data.refresh, fileReadinessPending))}`,
|
|
54
61
|
);
|
|
55
62
|
lines.push(`**Stale assessment**: ${asSentence(staleAssessmentText(data.refresh))}`);
|
|
56
63
|
lines.push("");
|
|
57
64
|
return;
|
|
65
|
+
}
|
|
58
66
|
case "failed": {
|
|
59
67
|
const evidence = data.refresh.diagnosticEvidence
|
|
60
68
|
? `; ${formatDiagnosticEvidence(data.refresh.diagnosticEvidence)}`
|
|
61
69
|
: "";
|
|
70
|
+
const processCrashRecovery = data.refresh.processCrashRecovery
|
|
71
|
+
? formatProcessCrashRecovery(data.refresh.processCrashRecovery)
|
|
72
|
+
: null;
|
|
73
|
+
const staleRestart = formatStaleDiagnosticRestarts(data.refresh);
|
|
62
74
|
lines.push(
|
|
63
|
-
`**${refreshAttemptLabel(data.refresh)}**: failed — ${data.refresh.reason}${evidence}`,
|
|
75
|
+
`**${refreshAttemptLabel(data.refresh)}**: failed — ${data.refresh.reason}${staleRestart ? `; ${staleRestart}` : ""}${processCrashRecovery ? `; ${processCrashRecovery}` : ""}${evidence}`,
|
|
64
76
|
);
|
|
65
77
|
lines.push("");
|
|
66
78
|
return;
|
|
@@ -84,14 +96,27 @@ function renderRefreshStatus(
|
|
|
84
96
|
|
|
85
97
|
function completedRefreshText(
|
|
86
98
|
attempt: Extract<HealthRefreshAttempt, { kind: "completed" }>,
|
|
99
|
+
fileReadinessPending = attempt.fileReadiness === "pending",
|
|
87
100
|
): string {
|
|
88
|
-
const
|
|
89
|
-
|
|
101
|
+
const processCrashRecovery = formatProcessCrashRecovery(attempt.processCrashRecovery);
|
|
102
|
+
const noOp =
|
|
103
|
+
!fileReadinessPending &&
|
|
104
|
+
attempt.attemptedActiveClients === 0 &&
|
|
105
|
+
attempt.restartedClients === 0 &&
|
|
106
|
+
processCrashRecovery === null;
|
|
107
|
+
const base = fileReadinessPending
|
|
108
|
+
? "readiness pending — LSP may still be warming; retry shortly"
|
|
109
|
+
: noOp
|
|
90
110
|
? "completed no-op — no active clients were targeted"
|
|
91
|
-
: `completed — ${attempt.attemptedActiveClients} active client${plural(attempt.attemptedActiveClients)} targeted
|
|
111
|
+
: `completed — ${attempt.attemptedActiveClients} active client${plural(attempt.attemptedActiveClients)} targeted`;
|
|
112
|
+
const staleRestart = noOp ? null : formatStaleDiagnosticRestarts(attempt);
|
|
113
|
+
const outcome = [staleRestart, processCrashRecovery].filter(
|
|
114
|
+
(value): value is string => value !== null,
|
|
115
|
+
);
|
|
116
|
+
const withOutcome = outcome.length > 0 ? `${base}; ${outcome.join("; ")}` : base;
|
|
92
117
|
return attempt.operationScope === "workspace-runtime"
|
|
93
|
-
? `${
|
|
94
|
-
:
|
|
118
|
+
? `${withOutcome}; ${formatDiagnosticEvidence(attempt.diagnosticEvidence)}`
|
|
119
|
+
: withOutcome;
|
|
95
120
|
}
|
|
96
121
|
|
|
97
122
|
function refreshAttemptLabel(attempt: Pick<HealthRefreshAttempt, "operationScope">): string {
|
|
@@ -117,7 +142,7 @@ function renderLastAttempt(lines: string[], attempt: HealthRefreshAttempt, cwd:
|
|
|
117
142
|
const outcome = refreshAttemptOutcome(attempt);
|
|
118
143
|
const label = refreshAttemptLabel(attempt);
|
|
119
144
|
lines.push(
|
|
120
|
-
`**Previous ${label.toLowerCase()}**: ${asSentence(outcome)} Started ${
|
|
145
|
+
`**Previous ${label.toLowerCase()}**: ${asSentence(outcome)} Started ${formatRefreshElapsed(Date.now() - attempt.attemptedAt)}; requested ${formatDiagnosticScope(attempt.requestedDiagnosticScope, cwd)}; operation scope: ${refreshOperationScopeText(attempt)}.`,
|
|
121
146
|
);
|
|
122
147
|
}
|
|
123
148
|
|
|
@@ -125,24 +150,35 @@ function renderRetainedAttempt(lines: string[], attempt: HealthRefreshAttempt, c
|
|
|
125
150
|
const label =
|
|
126
151
|
attempt.operationScope === "file-runtime" ? "File LSP maintenance" : "Diagnostic refresh";
|
|
127
152
|
lines.push(
|
|
128
|
-
`**${label}**: not requested for this call. Previous attempt ${asSentence(refreshAttemptOutcome(attempt))} Started ${
|
|
153
|
+
`**${label}**: not requested for this call. Previous attempt ${asSentence(refreshAttemptOutcome(attempt))} Started ${formatRefreshElapsed(Date.now() - attempt.attemptedAt)}; requested ${formatDiagnosticScope(attempt.requestedDiagnosticScope, cwd)}; operation scope: ${refreshOperationScopeText(attempt)}.`,
|
|
129
154
|
);
|
|
130
155
|
}
|
|
131
156
|
|
|
132
157
|
function refreshAttemptOutcome(attempt: HealthRefreshAttempt): string {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
158
|
+
if (attempt.kind === "completed") return completedRefreshText(attempt);
|
|
159
|
+
const processCrashRecovery = attempt.processCrashRecovery
|
|
160
|
+
? formatProcessCrashRecovery(attempt.processCrashRecovery)
|
|
161
|
+
: null;
|
|
162
|
+
const staleRestart = formatStaleDiagnosticRestarts(attempt);
|
|
163
|
+
const evidence = attempt.diagnosticEvidence
|
|
164
|
+
? `; ${formatDiagnosticEvidence(attempt.diagnosticEvidence)}`
|
|
165
|
+
: "";
|
|
166
|
+
return `failed — ${attempt.reason}${staleRestart ? `; ${staleRestart}` : ""}${processCrashRecovery ? `; ${processCrashRecovery}` : ""}${evidence}`;
|
|
136
167
|
}
|
|
137
168
|
|
|
138
169
|
function refreshOperationScopeText(attempt: HealthRefreshAttempt): string {
|
|
139
170
|
return attempt.operationScope === "file-runtime" ? "file runtime" : "workspace runtime";
|
|
140
171
|
}
|
|
141
172
|
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
173
|
+
function formatStaleDiagnosticRestarts(attempt: {
|
|
174
|
+
kind?: HealthRefreshAttempt["kind"];
|
|
175
|
+
operationScope: HealthRefreshAttempt["operationScope"];
|
|
176
|
+
restartedClients?: number;
|
|
177
|
+
}): string | null {
|
|
178
|
+
if (attempt.operationScope !== "workspace-runtime" || attempt.restartedClients === undefined) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return formatStaleDiagnosticRestartsText(attempt.restartedClients);
|
|
146
182
|
}
|
|
147
183
|
|
|
148
184
|
function renderCapabilityWarningsSection(
|
|
@@ -193,49 +229,6 @@ function renderDiagnosticsSection(lines: string[], data: HealthData, cwd: string
|
|
|
193
229
|
lines.push("");
|
|
194
230
|
}
|
|
195
231
|
|
|
196
|
-
/**
|
|
197
|
-
* Render the tsconfig coverage verdict for a single-file health request.
|
|
198
|
-
*
|
|
199
|
-
* Written in plain vocabulary (no basis terms) so a reader without tsconfig
|
|
200
|
-
* background can act on it: the sentence names the deciding config and states
|
|
201
|
-
* whether the file's errors are part of workspace diagnostics. The structured
|
|
202
|
-
* decision basis stays in the diagnostics.scope debug event.
|
|
203
|
-
*/
|
|
204
|
-
function renderFileScopeStatus(
|
|
205
|
-
lines: string[],
|
|
206
|
-
observation: Extract<
|
|
207
|
-
HealthDiagnosticObservation,
|
|
208
|
-
{ kind: "completed" | "partial" | "unavailable" }
|
|
209
|
-
>,
|
|
210
|
-
cwd: string,
|
|
211
|
-
): void {
|
|
212
|
-
if (observation.scope.kind !== "file" || !observation.scopeStatus) return;
|
|
213
|
-
|
|
214
|
-
const decision = observation.scopeStatus;
|
|
215
|
-
switch (decision.status) {
|
|
216
|
-
case "included":
|
|
217
|
-
lines.push(
|
|
218
|
-
`**Tsconfig**: covered by ${formatConfigPath(decision.configPath, cwd)} — part of workspace diagnostics.`,
|
|
219
|
-
);
|
|
220
|
-
return;
|
|
221
|
-
case "excluded":
|
|
222
|
-
lines.push(
|
|
223
|
-
`**Tsconfig**: NOT covered by ${formatConfigPath(decision.configPath, cwd)} — not part of workspace diagnostics.`,
|
|
224
|
-
);
|
|
225
|
-
return;
|
|
226
|
-
case "no-config":
|
|
227
|
-
lines.push("**Tsconfig**: no tsconfig.json or jsconfig.json found — nothing filtered.");
|
|
228
|
-
return;
|
|
229
|
-
case "out-of-tree":
|
|
230
|
-
lines.push("**Tsconfig**: outside the project root — not part of workspace diagnostics.");
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function formatConfigPath(configPath: string | null, cwd: string): string {
|
|
235
|
-
if (!configPath) return "no config";
|
|
236
|
-
return `\`${makeRelative(cwd, configPath)}\``;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
232
|
function formatDiagnosticEvidence(evidence: {
|
|
240
233
|
requested: number;
|
|
241
234
|
confirmed: number;
|
|
@@ -250,7 +243,14 @@ function renderDiagnosticObservation(lines: string[], data: HealthData, cwd: str
|
|
|
250
243
|
const observation = data.diagnostics;
|
|
251
244
|
if (observation.kind === "not-requested") return;
|
|
252
245
|
if (observation.kind === "unavailable") {
|
|
253
|
-
|
|
246
|
+
if (
|
|
247
|
+
observation.scope.kind === "file" &&
|
|
248
|
+
isFileReadinessPending(currentRefreshAttempt(data), data.semanticState)
|
|
249
|
+
) {
|
|
250
|
+
lines.push("Diagnostics pending — LSP may still be warming; retry shortly.");
|
|
251
|
+
} else {
|
|
252
|
+
lines.push(`Diagnostics unavailable — ${asSentence(observation.reason)}`);
|
|
253
|
+
}
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
256
256
|
if (observation.kind === "partial") {
|
|
@@ -269,6 +269,10 @@ function renderDiagnosticObservation(lines: string[], data: HealthData, cwd: str
|
|
|
269
269
|
renderDiagnosticEntries(lines, data, cwd);
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
function currentRefreshAttempt(data: HealthData): HealthRefreshAttempt | null {
|
|
273
|
+
return data.refresh.kind === "completed" || data.refresh.kind === "failed" ? data.refresh : null;
|
|
274
|
+
}
|
|
275
|
+
|
|
272
276
|
function asSentence(text: string): string {
|
|
273
277
|
return /[.!?]$/.test(text) ? text : `${text}.`;
|
|
274
278
|
}
|
|
@@ -371,7 +375,3 @@ function formatDiagnosticScope(scope: HealthDiagnosticScope, cwd: string): strin
|
|
|
371
375
|
function plural(count: number): string {
|
|
372
376
|
return count === 1 ? "" : "s";
|
|
373
377
|
}
|
|
374
|
-
|
|
375
|
-
function makeRelative(cwd: string, file: string): string {
|
|
376
|
-
return file.startsWith(cwd) ? file.slice(cwd.length + 1) : file;
|
|
377
|
-
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ProcessCrashRecoveryEntry,
|
|
3
|
+
ProcessCrashRecoveryReport,
|
|
4
|
+
} from "@mrclrchtr/supi-lsp/api";
|
|
5
|
+
import type { SemanticHealthState } from "../../session/health-types.ts";
|
|
6
|
+
|
|
7
|
+
/** Report whether a file health result is waiting for semantic readiness. */
|
|
8
|
+
export function isFileReadinessPending(
|
|
9
|
+
attempt: { operationScope?: string; fileReadiness?: string } | null | undefined,
|
|
10
|
+
semanticState: SemanticHealthState | null | undefined,
|
|
11
|
+
): boolean {
|
|
12
|
+
if (attempt?.operationScope !== undefined) {
|
|
13
|
+
return (
|
|
14
|
+
attempt.operationScope === "file-runtime" &&
|
|
15
|
+
(attempt.fileReadiness === "pending" ||
|
|
16
|
+
(attempt.fileReadiness === undefined && semanticState?.kind === "pending"))
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return semanticState?.kind === "pending";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Format the outcome of stale-diagnostic client restarts. */
|
|
23
|
+
export function formatStaleDiagnosticRestarts(restartedClients: number): string {
|
|
24
|
+
return `stale diagnostic restarts: ${restartedClients} client${plural(restartedClients)} restarted`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Format process-crash counts for the compact health view. */
|
|
28
|
+
export function formatCompactProcessCrashRecovery(
|
|
29
|
+
report: ProcessCrashRecoveryReport | null | undefined,
|
|
30
|
+
): string | null {
|
|
31
|
+
if (
|
|
32
|
+
!report ||
|
|
33
|
+
(report.recoveredRoutes === 0 &&
|
|
34
|
+
report.skippedRoutes === 0 &&
|
|
35
|
+
report.failedRoutes === 0 &&
|
|
36
|
+
report.exhaustedRoutes === 0)
|
|
37
|
+
) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return `process-crash recovery: ${report.recoveredRoutes} route${plural(report.recoveredRoutes)} recovered (${report.skippedRoutes} skipped, ${report.failedRoutes} failed, ${report.exhaustedRoutes} exhausted)`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Format process-crash counts and bounded route entries for detailed health output. */
|
|
44
|
+
export function formatProcessCrashRecovery(
|
|
45
|
+
report: ProcessCrashRecoveryReport | null | undefined,
|
|
46
|
+
): string | null {
|
|
47
|
+
const summary = formatCompactProcessCrashRecovery(report);
|
|
48
|
+
if (!summary || !report) return summary;
|
|
49
|
+
const entries = report.entries.map(formatProcessCrashRecoveryEntry);
|
|
50
|
+
const omitted =
|
|
51
|
+
report.omittedEntries > 0
|
|
52
|
+
? `${report.omittedEntries} more route${plural(report.omittedEntries)}`
|
|
53
|
+
: null;
|
|
54
|
+
const details = [...entries, omitted]
|
|
55
|
+
.filter((value): value is string => value !== null)
|
|
56
|
+
.join("; ");
|
|
57
|
+
return details ? `${summary}; ${details}` : summary;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function formatProcessCrashRecoveryEntry(entry: ProcessCrashRecoveryEntry): string {
|
|
61
|
+
const outcome = entry.outcome.replaceAll("-", " ");
|
|
62
|
+
const action = entry.nextAction ? `; next: ${entry.nextAction.replaceAll("-", " ")}` : "";
|
|
63
|
+
const failure = entry.failureMessage ? `; ${entry.failureMessage}` : "";
|
|
64
|
+
return `${entry.name} @ ${entry.root}: ${outcome}${action}${failure}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Format the age of a retained refresh attempt for a status line. */
|
|
68
|
+
export function formatRefreshElapsed(milliseconds: number): string {
|
|
69
|
+
const seconds = Math.max(0, Math.round(milliseconds / 1_000));
|
|
70
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
71
|
+
return `${Math.round(seconds / 60)}m ago`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function plural(count: number): string {
|
|
75
|
+
return count === 1 ? "" : "s";
|
|
76
|
+
}
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_PROCESS_CRASH_RECOVERY_ENTRIES,
|
|
3
|
+
type ProcessCrashRecoveryEntry,
|
|
4
|
+
type ProcessCrashRecoveryOutcome,
|
|
5
|
+
type ProcessCrashRecoveryReport,
|
|
6
|
+
} from "@mrclrchtr/supi-lsp/api";
|
|
7
|
+
import {
|
|
8
|
+
formatCompactProcessCrashRecovery,
|
|
9
|
+
formatProcessCrashRecovery,
|
|
10
|
+
formatStaleDiagnosticRestarts,
|
|
11
|
+
isFileReadinessPending,
|
|
12
|
+
} from "./refresh-outcome.ts";
|
|
13
|
+
import { readSemanticHealthState } from "./semantic-state.ts";
|
|
14
|
+
|
|
1
15
|
/** Render current and retained health refresh status for the TUI. */
|
|
2
16
|
|
|
3
17
|
export function readRefreshStatus(data: Record<string, unknown> | null): string | null {
|
|
@@ -5,25 +19,10 @@ export function readRefreshStatus(data: Record<string, unknown> | null): string
|
|
|
5
19
|
if (!refresh) return null;
|
|
6
20
|
|
|
7
21
|
switch (refresh.kind) {
|
|
8
|
-
case "completed":
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const noOp = attempted === 0 && restarted === 0;
|
|
13
|
-
const label = refreshAttemptLabel(refresh);
|
|
14
|
-
const base = noOp
|
|
15
|
-
? `${label} completed no-op`
|
|
16
|
-
: `${label} completed: ${attempted} clients targeted, ${restarted} restarted`;
|
|
17
|
-
const evidence = formatDiagnosticEvidence(readRecord(refresh.diagnosticEvidence));
|
|
18
|
-
const withEvidence = evidence ? `${base}; ${evidence}` : base;
|
|
19
|
-
return stale?.suspected === true
|
|
20
|
-
? `${withEvidence}; stale pattern suspected in ${readNumber(stale.matchedFileCount)} files`
|
|
21
|
-
: withEvidence;
|
|
22
|
-
}
|
|
23
|
-
case "failed": {
|
|
24
|
-
const evidence = formatDiagnosticEvidence(readRecord(refresh.diagnosticEvidence));
|
|
25
|
-
return `${refreshAttemptLabel(refresh)} failed${typeof refresh.reason === "string" ? `: ${refresh.reason}` : ""}${evidence ? `; ${evidence}` : ""}`;
|
|
26
|
-
}
|
|
22
|
+
case "completed":
|
|
23
|
+
return formatCompletedRefreshStatus(refresh, isPendingFileReadiness(data));
|
|
24
|
+
case "failed":
|
|
25
|
+
return formatFailedRefreshStatus(refresh);
|
|
27
26
|
case "not-attempted":
|
|
28
27
|
return `refresh attempt not started${formatLastRefreshSuffix(refresh)}`;
|
|
29
28
|
case "not-requested":
|
|
@@ -33,6 +32,89 @@ export function readRefreshStatus(data: Record<string, unknown> | null): string
|
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
|
|
35
|
+
function formatCompletedRefreshStatus(
|
|
36
|
+
refresh: Record<string, unknown>,
|
|
37
|
+
fileReadinessPending: boolean,
|
|
38
|
+
): string {
|
|
39
|
+
const attempted = readNumber(refresh.attemptedActiveClients);
|
|
40
|
+
const restarted = readNumber(refresh.restartedClients);
|
|
41
|
+
const processCrashRecovery = formatProcessCrashRecovery(
|
|
42
|
+
readProcessCrashRecovery(refresh.processCrashRecovery),
|
|
43
|
+
);
|
|
44
|
+
const noOp =
|
|
45
|
+
!fileReadinessPending && attempted === 0 && restarted === 0 && processCrashRecovery === null;
|
|
46
|
+
const label = refreshAttemptLabel(refresh);
|
|
47
|
+
const base = fileReadinessPending
|
|
48
|
+
? `${label} waiting — LSP may still be warming; retry shortly`
|
|
49
|
+
: noOp
|
|
50
|
+
? `${label} completed no-op`
|
|
51
|
+
: `${label} completed: ${attempted} clients targeted`;
|
|
52
|
+
const outcomes = formatRefreshOutcomes(refresh, restarted, processCrashRecovery, noOp);
|
|
53
|
+
const withOutcome = outcomes.length > 0 ? `${base}; ${outcomes.join("; ")}` : base;
|
|
54
|
+
const evidence = formatDiagnosticEvidence(readRecord(refresh.diagnosticEvidence));
|
|
55
|
+
const withEvidence = evidence ? `${withOutcome}; ${evidence}` : withOutcome;
|
|
56
|
+
const stale = readRecord(refresh.staleAssessment);
|
|
57
|
+
return stale?.suspected === true
|
|
58
|
+
? `${withEvidence}; stale pattern suspected in ${readNumber(stale.matchedFileCount)} files`
|
|
59
|
+
: withEvidence;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function formatFailedRefreshStatus(refresh: Record<string, unknown>): string {
|
|
63
|
+
const processCrashRecovery = formatProcessCrashRecovery(
|
|
64
|
+
readProcessCrashRecovery(refresh.processCrashRecovery),
|
|
65
|
+
);
|
|
66
|
+
const staleRestart = formatStaleDiagnosticRestartsForRecord(refresh);
|
|
67
|
+
const evidence = formatDiagnosticEvidence(readRecord(refresh.diagnosticEvidence));
|
|
68
|
+
const reason = typeof refresh.reason === "string" ? `: ${refresh.reason}` : "";
|
|
69
|
+
return `${refreshAttemptLabel(refresh)} failed${reason}${staleRestart ? `; ${staleRestart}` : ""}${processCrashRecovery ? `; ${processCrashRecovery}` : ""}${evidence ? `; ${evidence}` : ""}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function formatRefreshOutcomes(
|
|
73
|
+
refresh: Record<string, unknown>,
|
|
74
|
+
restarted: number,
|
|
75
|
+
processCrashRecovery: string | null,
|
|
76
|
+
noOp: boolean,
|
|
77
|
+
): string[] {
|
|
78
|
+
const outcomes: string[] = [];
|
|
79
|
+
if (refresh.operationScope === "workspace-runtime" && !noOp) {
|
|
80
|
+
outcomes.push(formatStaleDiagnosticRestarts(restarted));
|
|
81
|
+
}
|
|
82
|
+
if (processCrashRecovery) outcomes.push(processCrashRecovery);
|
|
83
|
+
return outcomes;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Render only the material current recovery outcome for compact TUI chrome. */
|
|
87
|
+
export function readCompactRefreshStatus(data: Record<string, unknown> | null): string | null {
|
|
88
|
+
const refresh = readRecord(data?.refresh);
|
|
89
|
+
if (!refresh || (refresh.kind !== "completed" && refresh.kind !== "failed")) return null;
|
|
90
|
+
|
|
91
|
+
const processCrashRecovery = formatCompactProcessCrashRecovery(
|
|
92
|
+
readProcessCrashRecovery(refresh.processCrashRecovery),
|
|
93
|
+
);
|
|
94
|
+
if (refresh.kind === "failed") {
|
|
95
|
+
const staleRestart = formatStaleDiagnosticRestartsForRecord(refresh);
|
|
96
|
+
return (
|
|
97
|
+
[staleRestart, processCrashRecovery]
|
|
98
|
+
.filter((value): value is string => value !== null)
|
|
99
|
+
.join("; ") || null
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
const fileReadinessPending = isPendingFileReadiness(data);
|
|
103
|
+
if (
|
|
104
|
+
!processCrashRecovery &&
|
|
105
|
+
readNumber(refresh.restartedClients) === 0 &&
|
|
106
|
+
!fileReadinessPending
|
|
107
|
+
) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const staleRestart = formatStaleDiagnosticRestartsForRecord(refresh);
|
|
112
|
+
const readiness = fileReadinessPending ? "LSP may still be warming; retry shortly" : null;
|
|
113
|
+
return [staleRestart, processCrashRecovery, readiness]
|
|
114
|
+
.filter((value): value is string => value !== null)
|
|
115
|
+
.join("; ");
|
|
116
|
+
}
|
|
117
|
+
|
|
36
118
|
export function readPreviousRefreshStatus(data: Record<string, unknown> | null): string | null {
|
|
37
119
|
const refresh = readRecord(data?.refresh);
|
|
38
120
|
if (!refresh || (refresh.kind !== "not-requested" && refresh.kind !== "not-attempted")) {
|
|
@@ -41,11 +123,23 @@ export function readPreviousRefreshStatus(data: Record<string, unknown> | null):
|
|
|
41
123
|
const attempt = readRecord(refresh.lastAttempt);
|
|
42
124
|
if (!attempt) return null;
|
|
43
125
|
const evidence = formatCompactDiagnosticEvidence(readRecord(attempt.diagnosticEvidence));
|
|
126
|
+
const processCrashRecovery = formatCompactProcessCrashRecovery(
|
|
127
|
+
readProcessCrashRecovery(attempt.processCrashRecovery),
|
|
128
|
+
);
|
|
129
|
+
const staleRestart = formatStaleDiagnosticRestartsForRecord(attempt);
|
|
130
|
+
const fileReadinessPending =
|
|
131
|
+
attempt.kind === "completed" &&
|
|
132
|
+
isFileReadinessPending(attempt, readSemanticHealthState(data?.semanticState));
|
|
133
|
+
const readiness = fileReadinessPending ? "LSP may still be warming; retry shortly" : null;
|
|
134
|
+
const outcome = [readiness, staleRestart, processCrashRecovery, evidence]
|
|
135
|
+
.filter((value): value is string => value !== null)
|
|
136
|
+
.join("; ");
|
|
44
137
|
if (attempt.kind === "failed") {
|
|
45
|
-
return `last ${refreshAttemptLabel(attempt)} failed${
|
|
138
|
+
return `last ${refreshAttemptLabel(attempt)} failed${outcome ? ` (${outcome})` : ""}`;
|
|
46
139
|
}
|
|
47
140
|
if (attempt.kind === "completed") {
|
|
48
|
-
|
|
141
|
+
const status = fileReadinessPending ? "waiting" : "completed";
|
|
142
|
+
return `last ${refreshAttemptLabel(attempt)} ${status}${outcome ? ` (${outcome})` : ""}`;
|
|
49
143
|
}
|
|
50
144
|
return null;
|
|
51
145
|
}
|
|
@@ -54,16 +148,45 @@ function refreshAttemptLabel(attempt: Record<string, unknown>): string {
|
|
|
54
148
|
return attempt.operationScope === "file-runtime" ? "file maintenance attempt" : "refresh attempt";
|
|
55
149
|
}
|
|
56
150
|
|
|
151
|
+
function formatStaleDiagnosticRestartsForRecord(attempt: Record<string, unknown>): string | null {
|
|
152
|
+
if (
|
|
153
|
+
attempt.operationScope !== "workspace-runtime" ||
|
|
154
|
+
typeof attempt.restartedClients !== "number"
|
|
155
|
+
) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const processCrashRecovery = formatProcessCrashRecovery(
|
|
159
|
+
readProcessCrashRecovery(attempt.processCrashRecovery),
|
|
160
|
+
);
|
|
161
|
+
const noOp =
|
|
162
|
+
attempt.kind === "completed" &&
|
|
163
|
+
readNumber(attempt.attemptedActiveClients) === 0 &&
|
|
164
|
+
attempt.restartedClients === 0 &&
|
|
165
|
+
processCrashRecovery === null;
|
|
166
|
+
return noOp ? null : formatStaleDiagnosticRestarts(attempt.restartedClients);
|
|
167
|
+
}
|
|
168
|
+
|
|
57
169
|
function formatLastRefreshSuffix(refresh: Record<string, unknown>): string {
|
|
58
170
|
const attempt = readRecord(refresh.lastAttempt);
|
|
59
171
|
if (!attempt) return "";
|
|
60
172
|
const evidence = formatDiagnosticEvidence(readRecord(attempt.diagnosticEvidence));
|
|
173
|
+
const staleRestart = formatStaleDiagnosticRestartsForRecord(attempt);
|
|
174
|
+
const processCrashRecovery = formatProcessCrashRecovery(
|
|
175
|
+
readProcessCrashRecovery(attempt.processCrashRecovery),
|
|
176
|
+
);
|
|
177
|
+
const fileReadinessPending =
|
|
178
|
+
attempt.kind === "completed" && isFileReadinessPending(attempt, null);
|
|
179
|
+
const readiness = fileReadinessPending ? "LSP may still be warming; retry shortly" : null;
|
|
180
|
+
const outcome = [readiness, staleRestart, processCrashRecovery, evidence]
|
|
181
|
+
.filter((value): value is string => value !== null)
|
|
182
|
+
.join("; ");
|
|
61
183
|
if (attempt.kind === "failed") {
|
|
62
184
|
const reason = typeof attempt.reason === "string" ? `: ${attempt.reason}` : "";
|
|
63
|
-
return `; last ${refreshAttemptLabel(attempt)} failed${reason}${
|
|
185
|
+
return `; last ${refreshAttemptLabel(attempt)} failed${reason}${outcome ? `; ${outcome}` : ""}`;
|
|
64
186
|
}
|
|
65
187
|
if (attempt.kind === "completed") {
|
|
66
|
-
|
|
188
|
+
const status = fileReadinessPending ? "waiting" : "completed";
|
|
189
|
+
return `; last ${refreshAttemptLabel(attempt)} ${status}${outcome ? `; ${outcome}` : ""}`;
|
|
67
190
|
}
|
|
68
191
|
return "";
|
|
69
192
|
}
|
|
@@ -80,6 +203,72 @@ function formatDiagnosticEvidence(evidence: Record<string, unknown> | null): str
|
|
|
80
203
|
return `${counts[0]} requested, ${counts[1]} confirmed, ${counts[2]} unconfirmed, ${counts[3]} failed, ${counts[4]} removed`;
|
|
81
204
|
}
|
|
82
205
|
|
|
206
|
+
export function isPendingFileReadiness(data: Record<string, unknown> | null): boolean {
|
|
207
|
+
const observation = readRecord(data?.diagnosticObservation);
|
|
208
|
+
const scope = readRecord(observation?.scope);
|
|
209
|
+
if (scope?.kind !== "file") return false;
|
|
210
|
+
|
|
211
|
+
const refresh = readRecord(data?.refresh);
|
|
212
|
+
const attempt = refresh && typeof refresh.operationScope === "string" ? refresh : null;
|
|
213
|
+
return isFileReadinessPending(attempt, readSemanticHealthState(data?.semanticState));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function readProcessCrashRecovery(value: unknown): ProcessCrashRecoveryReport | null {
|
|
217
|
+
const report = readRecord(value);
|
|
218
|
+
if (!report) return null;
|
|
219
|
+
const recoveredRoutes = report.recoveredRoutes;
|
|
220
|
+
const skippedRoutes = report.skippedRoutes;
|
|
221
|
+
const failedRoutes = report.failedRoutes;
|
|
222
|
+
const exhaustedRoutes = report.exhaustedRoutes;
|
|
223
|
+
const omittedEntries = report.omittedEntries;
|
|
224
|
+
if (
|
|
225
|
+
!isEvidenceCount(recoveredRoutes) ||
|
|
226
|
+
!isEvidenceCount(skippedRoutes) ||
|
|
227
|
+
!isEvidenceCount(failedRoutes) ||
|
|
228
|
+
!isEvidenceCount(exhaustedRoutes) ||
|
|
229
|
+
!isEvidenceCount(omittedEntries) ||
|
|
230
|
+
!Array.isArray(report.entries) ||
|
|
231
|
+
report.entries.length > MAX_PROCESS_CRASH_RECOVERY_ENTRIES
|
|
232
|
+
) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const entries = report.entries
|
|
236
|
+
.map(readProcessCrashRecoveryEntry)
|
|
237
|
+
.filter((entry): entry is ProcessCrashRecoveryEntry => entry !== null);
|
|
238
|
+
if (entries.length !== report.entries.length) return null;
|
|
239
|
+
return { recoveredRoutes, skippedRoutes, failedRoutes, exhaustedRoutes, entries, omittedEntries };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function readProcessCrashRecoveryEntry(value: unknown): ProcessCrashRecoveryEntry | null {
|
|
243
|
+
const entry = readRecord(value);
|
|
244
|
+
if (!entry || typeof entry.name !== "string" || typeof entry.root !== "string") return null;
|
|
245
|
+
if (!isProcessCrashRecoveryOutcome(entry.outcome)) return null;
|
|
246
|
+
if (
|
|
247
|
+
entry.nextAction !== undefined &&
|
|
248
|
+
entry.nextAction !== "use-exact-file" &&
|
|
249
|
+
entry.nextAction !== "reload-workspace"
|
|
250
|
+
) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
if (entry.failureMessage !== undefined && typeof entry.failureMessage !== "string") return null;
|
|
254
|
+
return {
|
|
255
|
+
name: entry.name,
|
|
256
|
+
root: entry.root,
|
|
257
|
+
outcome: entry.outcome,
|
|
258
|
+
...(entry.nextAction !== undefined ? { nextAction: entry.nextAction } : {}),
|
|
259
|
+
...(entry.failureMessage !== undefined ? { failureMessage: entry.failureMessage } : {}),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function isProcessCrashRecoveryOutcome(value: unknown): value is ProcessCrashRecoveryOutcome {
|
|
264
|
+
return (
|
|
265
|
+
value === "recovered" ||
|
|
266
|
+
value === "skipped-no-retained-file" ||
|
|
267
|
+
value === "recovery-failed" ||
|
|
268
|
+
value === "recovery-exhausted"
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
83
272
|
function readEvidenceCounts(evidence: Record<string, unknown> | null): number[] | null {
|
|
84
273
|
if (!evidence) return null;
|
|
85
274
|
const counts = [
|
|
@@ -24,7 +24,12 @@ import {
|
|
|
24
24
|
type ToolResult,
|
|
25
25
|
} from "../../ui/tui/common.ts";
|
|
26
26
|
import type { CodeHealthToolParams } from "./execute.ts";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
isPendingFileReadiness,
|
|
29
|
+
readCompactRefreshStatus,
|
|
30
|
+
readPreviousRefreshStatus,
|
|
31
|
+
readRefreshStatus,
|
|
32
|
+
} from "./refresh-status.ts";
|
|
28
33
|
import { formatSemanticHealthState, readSemanticHealthState } from "./semantic-state.ts";
|
|
29
34
|
|
|
30
35
|
/** ── renderCall ────────────────────────────────────────────────── */
|
|
@@ -125,6 +130,7 @@ function buildCompactSummary(data: Record<string, unknown> | null, theme: Theme)
|
|
|
125
130
|
const semanticRequested = sections.some(
|
|
126
131
|
(section) => section.key === "diagnostics" || section.key === "servers",
|
|
127
132
|
);
|
|
133
|
+
const fileReadinessPending = isPendingFileReadiness(data);
|
|
128
134
|
const segments = sections.map((section) =>
|
|
129
135
|
formatSectionSummary(
|
|
130
136
|
section,
|
|
@@ -132,6 +138,7 @@ function buildCompactSummary(data: Record<string, unknown> | null, theme: Theme)
|
|
|
132
138
|
? formatCompactDiagnosticEvidence(readDiagnosticEvidence(data))
|
|
133
139
|
: null,
|
|
134
140
|
theme,
|
|
141
|
+
fileReadinessPending,
|
|
135
142
|
),
|
|
136
143
|
);
|
|
137
144
|
if (semanticRequested) {
|
|
@@ -142,8 +149,8 @@ function buildCompactSummary(data: Record<string, unknown> | null, theme: Theme)
|
|
|
142
149
|
`${theme.fg("dim", "lsp")} ${theme.fg(statusColor, semanticStatus)}${routeSummary ? ` ${theme.fg("warning", routeSummary)}` : ""}`,
|
|
143
150
|
);
|
|
144
151
|
}
|
|
145
|
-
const
|
|
146
|
-
if (
|
|
152
|
+
const refreshStatus = readCompactRefreshStatus(data) ?? readPreviousRefreshStatus(data);
|
|
153
|
+
if (refreshStatus) segments.push(theme.fg("dim", refreshStatus));
|
|
147
154
|
const capabilityWarningCount = readCapabilityWarnings(data).length;
|
|
148
155
|
if (capabilityWarningCount > 0) {
|
|
149
156
|
const label = capabilityWarningCount === 1 ? "capability warning" : "capability warnings";
|
|
@@ -158,11 +165,14 @@ function formatSectionSummary(
|
|
|
158
165
|
section: HealthSectionSummary,
|
|
159
166
|
coverage: string | null,
|
|
160
167
|
theme: Theme,
|
|
168
|
+
fileReadinessPending: boolean,
|
|
161
169
|
): string {
|
|
162
170
|
const label = sectionLabel(section.key);
|
|
163
171
|
const coverageSuffix = coverage ? ` (${coverage})` : "";
|
|
164
172
|
if (section.status === "unavailable" || !section.available) {
|
|
165
|
-
|
|
173
|
+
const status =
|
|
174
|
+
section.key === "diagnostics" && fileReadinessPending ? "pending" : "unavailable";
|
|
175
|
+
return `${theme.fg("dim", label)} ${theme.fg("warning", status)}${coverageSuffix}`;
|
|
166
176
|
}
|
|
167
177
|
if (section.status === "partial") {
|
|
168
178
|
return `${theme.fg("dim", label)} ${theme.fg("warning", "partial")}${coverageSuffix}`;
|
|
@@ -307,7 +317,10 @@ function buildDiagnosticSummary(data: Record<string, unknown> | null, theme: The
|
|
|
307
317
|
const section = readHealthSections(data).find((entry) => entry.key === "diagnostics");
|
|
308
318
|
if (!section) return new Text("", 0, 0);
|
|
309
319
|
if (section.status === "unavailable" || !section.available) {
|
|
310
|
-
|
|
320
|
+
const label = isPendingFileReadiness(data)
|
|
321
|
+
? "Diagnostics pending — LSP may still be warming; retry shortly"
|
|
322
|
+
: "Diagnostics unavailable";
|
|
323
|
+
return new Text(theme.fg("warning", label), 0, 0);
|
|
311
324
|
}
|
|
312
325
|
const trackedFiles = diagnosticScopeKind(data) === "tracked-files";
|
|
313
326
|
if (section.status === "partial") {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export const toolDescription =
|
|
1
|
+
export const toolDescription =
|
|
2
|
+
"Apply one fresh stored refactor plan by planId after safety checks; mutates its files.";
|
|
2
3
|
|
|
3
|
-
export const promptSnippet = "apply a
|
|
4
|
+
export const promptSnippet = "apply a stored refactor plan";
|
|
4
5
|
|
|
5
6
|
export const promptGuidelines: string[] = [];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const toolDescription =
|
|
2
|
-
"Preview one semantic rename or
|
|
2
|
+
"Preview one semantic rename, extraction, import cleanup, or dead-code deletion and return a planId without mutating files.";
|
|
3
3
|
|
|
4
4
|
export const promptSnippet = "preview a precise semantic refactor";
|
|
5
5
|
|