@mrclrchtr/supi-lsp 0.1.0 → 1.1.2
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 +112 -0
- package/node_modules/@mrclrchtr/supi-core/README.md +90 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +26 -0
- package/node_modules/@mrclrchtr/supi-core/src/config-settings.ts +76 -0
- package/node_modules/@mrclrchtr/supi-core/src/config.ts +186 -0
- package/node_modules/@mrclrchtr/supi-core/src/context-messages.ts +119 -0
- package/node_modules/@mrclrchtr/supi-core/src/context-provider-registry.ts +36 -0
- package/node_modules/@mrclrchtr/supi-core/src/context-tag.ts +31 -0
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +255 -0
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +83 -0
- package/node_modules/@mrclrchtr/supi-core/src/project-roots.ts +170 -0
- package/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +54 -0
- package/node_modules/@mrclrchtr/supi-core/src/session-utils.ts +29 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings-command.ts +15 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings-registry.ts +41 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +226 -0
- package/node_modules/@mrclrchtr/supi-core/src/terminal.ts +60 -0
- package/package.json +16 -11
- package/{capabilities.ts → src/capabilities.ts} +8 -0
- package/src/client/client-refresh.ts +229 -0
- package/{client.ts → src/client/client.ts} +178 -30
- package/{transport.ts → src/client/transport.ts} +10 -6
- package/src/config.ts +143 -0
- package/src/defaults.json +82 -0
- package/src/diagnostics/diagnostic-augmentation.ts +82 -0
- package/src/diagnostics/diagnostic-display.ts +68 -0
- package/{diagnostic-summary.ts → src/diagnostics/diagnostic-summary.ts} +11 -7
- package/{diagnostics.ts → src/diagnostics/diagnostics.ts} +9 -4
- package/src/diagnostics/stale-diagnostics.ts +47 -0
- package/src/diagnostics/suppression-diagnostics.ts +58 -0
- package/src/format.ts +359 -0
- package/src/guidance.ts +163 -0
- package/src/index.ts +17 -0
- package/src/lsp-state.ts +82 -0
- package/src/lsp.ts +481 -0
- package/src/manager/manager-client-state.ts +34 -0
- package/src/manager/manager-diagnostics.ts +139 -0
- package/src/manager/manager-helpers.ts +39 -0
- package/src/manager/manager-project-info.ts +46 -0
- package/src/manager/manager-stale-resync.ts +47 -0
- package/src/manager/manager-types.ts +39 -0
- package/src/manager/manager-workspace-recovery.ts +83 -0
- package/src/manager/manager-workspace-symbol.ts +18 -0
- package/src/manager/manager.ts +550 -0
- package/src/overrides.ts +173 -0
- package/src/pattern-matcher.ts +197 -0
- package/src/renderer.ts +120 -0
- package/src/scanner.ts +153 -0
- package/src/search-fallback.ts +98 -0
- package/src/service-registry.ts +153 -0
- package/src/settings-registration.ts +292 -0
- package/{summary.ts → src/summary.ts} +44 -9
- package/src/tool-actions.ts +430 -0
- package/src/tree-persist.ts +48 -0
- package/src/tsconfig-scope.ts +156 -0
- package/{types.ts → src/types.ts} +123 -0
- package/src/ui.ts +358 -0
- package/{utils.ts → src/utils.ts} +8 -25
- package/src/workspace-sentinels.ts +114 -0
- package/bash-guard.ts +0 -58
- package/config.ts +0 -99
- package/defaults.json +0 -40
- package/format.ts +0 -190
- package/guidance.ts +0 -140
- package/lsp.ts +0 -375
- package/manager.ts +0 -396
- package/overrides.ts +0 -95
- package/recent-paths.ts +0 -126
- package/runtime-state.ts +0 -113
- package/tool-actions.ts +0 -211
- package/tsconfig.json +0 -5
- package/ui.ts +0 -303
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { LspClient } from "../client/client.ts";
|
|
2
|
+
import { displayRelativeFilePath } from "../summary.ts";
|
|
3
|
+
import type { ProjectServerInfo } from "../types.ts";
|
|
4
|
+
|
|
5
|
+
interface ProjectServerInfoInput {
|
|
6
|
+
serverName: string;
|
|
7
|
+
root: string;
|
|
8
|
+
fileTypes: string[];
|
|
9
|
+
client: LspClient | undefined;
|
|
10
|
+
unavailable: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function buildProjectServerInfo(
|
|
14
|
+
input: ProjectServerInfoInput,
|
|
15
|
+
cwd: string,
|
|
16
|
+
): ProjectServerInfo {
|
|
17
|
+
const status = input.unavailable
|
|
18
|
+
? "unavailable"
|
|
19
|
+
: input.client?.status === "running"
|
|
20
|
+
? "running"
|
|
21
|
+
: input.client?.status === "error"
|
|
22
|
+
? "error"
|
|
23
|
+
: "unavailable";
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
name: input.serverName,
|
|
27
|
+
root: input.root,
|
|
28
|
+
fileTypes: input.fileTypes,
|
|
29
|
+
status,
|
|
30
|
+
supportedActions: getSupportedActions(input.client?.serverCapabilities),
|
|
31
|
+
openFiles: input.client?.openFiles.map((file) => displayRelativeFilePath(file, cwd)) ?? [],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getSupportedActions(capabilities: LspClient["serverCapabilities"] | undefined): string[] {
|
|
36
|
+
if (!capabilities) return [];
|
|
37
|
+
|
|
38
|
+
const actions: string[] = ["diagnostics [optional file]"];
|
|
39
|
+
if (capabilities.hoverProvider) actions.push("hover(file,line,char)");
|
|
40
|
+
if (capabilities.definitionProvider) actions.push("definition(file,line,char)");
|
|
41
|
+
if (capabilities.referencesProvider) actions.push("references(file,line,char)");
|
|
42
|
+
if (capabilities.documentSymbolProvider) actions.push("symbols(file)");
|
|
43
|
+
if (capabilities.renameProvider) actions.push("rename(file,line,char,newName)");
|
|
44
|
+
if (capabilities.codeActionProvider) actions.push("code_actions(file,line,char)");
|
|
45
|
+
return actions;
|
|
46
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { isLikelyStaleDiagnostic } from "../diagnostics/stale-diagnostics.ts";
|
|
3
|
+
import type { LspManager } from "./manager.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Force re-open files with module-resolution errors (e.g., "Cannot find module")
|
|
7
|
+
* to trigger fresh analysis by the language server.
|
|
8
|
+
*
|
|
9
|
+
* The TypeScript server caches diagnostics by file content hash. When a new
|
|
10
|
+
* file is created that resolves an existing file's import, the stale diagnostic
|
|
11
|
+
* persists because the importing file's content hasn't changed. Re-opening the
|
|
12
|
+
* file (didClose + didOpen) forces the server to re-resolve all imports.
|
|
13
|
+
*
|
|
14
|
+
* Returns true if any files were re-synced.
|
|
15
|
+
*/
|
|
16
|
+
export async function forceResyncStaleModuleFiles(
|
|
17
|
+
manager: LspManager,
|
|
18
|
+
cwd: string,
|
|
19
|
+
): Promise<boolean> {
|
|
20
|
+
const outstanding = manager.getOutstandingDiagnostics(1);
|
|
21
|
+
const staleFiles: string[] = [];
|
|
22
|
+
|
|
23
|
+
for (const entry of outstanding) {
|
|
24
|
+
if (entry.diagnostics.some((d) => isLikelyStaleDiagnostic(d))) {
|
|
25
|
+
staleFiles.push(entry.file);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (staleFiles.length === 0) return false;
|
|
30
|
+
|
|
31
|
+
for (const file of staleFiles) {
|
|
32
|
+
const filePath = path.resolve(cwd, file);
|
|
33
|
+
// Close the file to clear cached diagnostics and remove from openDocs
|
|
34
|
+
manager.closeFile(filePath);
|
|
35
|
+
// Re-open to force the server to re-resolve imports
|
|
36
|
+
await manager.ensureFileOpen(filePath);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Re-sync and wait for fresh diagnostics after the re-opens
|
|
40
|
+
try {
|
|
41
|
+
await manager.refreshOpenDiagnostics({ quietMs: 300, maxWaitMs: 2000 });
|
|
42
|
+
} catch {
|
|
43
|
+
// Best-effort: don't fail the agent turn if refresh has issues
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// LSP manager types — shared summaries and status shapes used by UI/guidance.
|
|
2
|
+
|
|
3
|
+
export interface ServerStatus {
|
|
4
|
+
name: string;
|
|
5
|
+
status: "running" | "error" | "unavailable";
|
|
6
|
+
root: string;
|
|
7
|
+
openFiles: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DiagnosticSummary {
|
|
11
|
+
file: string;
|
|
12
|
+
errors: number;
|
|
13
|
+
warnings: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CoverageSummaryEntry {
|
|
17
|
+
name: string;
|
|
18
|
+
fileTypes: string[];
|
|
19
|
+
active: boolean;
|
|
20
|
+
openFiles: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ActiveCoverageSummaryEntry {
|
|
24
|
+
name: string;
|
|
25
|
+
openFiles: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface OutstandingDiagnosticSummaryEntry {
|
|
29
|
+
file: string;
|
|
30
|
+
total: number;
|
|
31
|
+
errors: number;
|
|
32
|
+
warnings: number;
|
|
33
|
+
information: number;
|
|
34
|
+
hints: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ManagerStatus {
|
|
38
|
+
servers: ServerStatus[];
|
|
39
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assessStaleDiagnostics,
|
|
3
|
+
type StaleDiagnosticAssessment,
|
|
4
|
+
} from "../diagnostics/stale-diagnostics.ts";
|
|
5
|
+
import type { Diagnostic, FileEvent } from "../types.ts";
|
|
6
|
+
|
|
7
|
+
export interface WorkspaceRecoveryResult {
|
|
8
|
+
refreshedClients: number;
|
|
9
|
+
restartedClients: number;
|
|
10
|
+
staleAssessment: StaleDiagnosticAssessment;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface WorkspaceRecoveryHost {
|
|
14
|
+
clearAllPullResultIds(): void;
|
|
15
|
+
notifyWorkspaceFileChanges(changes: FileEvent[]): void;
|
|
16
|
+
refreshOpenDiagnostics(options?: { maxWaitMs?: number; quietMs?: number }): Promise<void>;
|
|
17
|
+
getOutstandingDiagnostics(
|
|
18
|
+
maxSeverity?: number,
|
|
19
|
+
): Array<{ file: string; diagnostics: Diagnostic[] }>;
|
|
20
|
+
getStatus(): { servers: Array<{ status: "running" | "error" | "unavailable" }> };
|
|
21
|
+
restartClientsForFiles(filePaths: string[]): Promise<string[]>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Clear cached pull IDs and forward watched-file changes to active clients. */
|
|
25
|
+
export function softRecoverWorkspaceDiagnostics(
|
|
26
|
+
host: WorkspaceRecoveryHost,
|
|
27
|
+
changes: FileEvent[] = [],
|
|
28
|
+
): number {
|
|
29
|
+
host.clearAllPullResultIds();
|
|
30
|
+
if (changes.length > 0) host.notifyWorkspaceFileChanges(changes);
|
|
31
|
+
return countRunningClients(host);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Run a recovery pass, refreshing diagnostics and escalating if stale state remains. */
|
|
35
|
+
export async function recoverWorkspaceDiagnostics(
|
|
36
|
+
host: WorkspaceRecoveryHost,
|
|
37
|
+
options: {
|
|
38
|
+
changes?: FileEvent[];
|
|
39
|
+
restartIfStillStale?: boolean;
|
|
40
|
+
maxWaitMs?: number;
|
|
41
|
+
quietMs?: number;
|
|
42
|
+
} = {},
|
|
43
|
+
): Promise<WorkspaceRecoveryResult> {
|
|
44
|
+
const refreshedClients = softRecoverWorkspaceDiagnostics(host, options.changes ?? []);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await host.refreshOpenDiagnostics({ maxWaitMs: options.maxWaitMs, quietMs: options.quietMs });
|
|
48
|
+
} catch {
|
|
49
|
+
// Recovery should be best-effort.
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let staleAssessment = assessStaleDiagnostics(host.getOutstandingDiagnostics(1));
|
|
53
|
+
let restartedClients = 0;
|
|
54
|
+
|
|
55
|
+
if (options.restartIfStillStale && staleAssessment.suspected) {
|
|
56
|
+
const restarted = await host.restartClientsForFiles(
|
|
57
|
+
staleAssessment.matchedFiles.map((entry) => entry.file),
|
|
58
|
+
);
|
|
59
|
+
restartedClients = restarted.length;
|
|
60
|
+
|
|
61
|
+
if (restartedClients > 0) {
|
|
62
|
+
try {
|
|
63
|
+
await host.refreshOpenDiagnostics({
|
|
64
|
+
maxWaitMs: options.maxWaitMs,
|
|
65
|
+
quietMs: options.quietMs,
|
|
66
|
+
});
|
|
67
|
+
} catch {
|
|
68
|
+
// Keep the previous assessment if the follow-up refresh fails.
|
|
69
|
+
}
|
|
70
|
+
staleAssessment = assessStaleDiagnostics(host.getOutstandingDiagnostics(1));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
refreshedClients,
|
|
76
|
+
restartedClients,
|
|
77
|
+
staleAssessment,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function countRunningClients(host: WorkspaceRecoveryHost): number {
|
|
82
|
+
return host.getStatus().servers.filter((server) => server.status === "running").length;
|
|
83
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LspClient } from "../client/client.ts";
|
|
2
|
+
import type { SymbolInformation, WorkspaceSymbol } from "../types.ts";
|
|
3
|
+
|
|
4
|
+
export async function managerWorkspaceSymbol(
|
|
5
|
+
clients: Iterable<LspClient>,
|
|
6
|
+
query: string,
|
|
7
|
+
): Promise<(SymbolInformation | WorkspaceSymbol)[] | null> {
|
|
8
|
+
const all: (SymbolInformation | WorkspaceSymbol)[] = [];
|
|
9
|
+
let hasSupport = false;
|
|
10
|
+
for (const client of clients) {
|
|
11
|
+
if (client.status !== "running") continue;
|
|
12
|
+
if (!client.serverCapabilities?.workspaceSymbolProvider) continue;
|
|
13
|
+
hasSupport = true;
|
|
14
|
+
const result = await client.workspaceSymbol(query);
|
|
15
|
+
if (result) all.push(...result);
|
|
16
|
+
}
|
|
17
|
+
return hasSupport ? all : null;
|
|
18
|
+
}
|