@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.
Files changed (72) hide show
  1. package/README.md +112 -0
  2. package/node_modules/@mrclrchtr/supi-core/README.md +90 -0
  3. package/node_modules/@mrclrchtr/supi-core/package.json +26 -0
  4. package/node_modules/@mrclrchtr/supi-core/src/config-settings.ts +76 -0
  5. package/node_modules/@mrclrchtr/supi-core/src/config.ts +186 -0
  6. package/node_modules/@mrclrchtr/supi-core/src/context-messages.ts +119 -0
  7. package/node_modules/@mrclrchtr/supi-core/src/context-provider-registry.ts +36 -0
  8. package/node_modules/@mrclrchtr/supi-core/src/context-tag.ts +31 -0
  9. package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +255 -0
  10. package/node_modules/@mrclrchtr/supi-core/src/index.ts +83 -0
  11. package/node_modules/@mrclrchtr/supi-core/src/project-roots.ts +170 -0
  12. package/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +54 -0
  13. package/node_modules/@mrclrchtr/supi-core/src/session-utils.ts +29 -0
  14. package/node_modules/@mrclrchtr/supi-core/src/settings-command.ts +15 -0
  15. package/node_modules/@mrclrchtr/supi-core/src/settings-registry.ts +41 -0
  16. package/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +226 -0
  17. package/node_modules/@mrclrchtr/supi-core/src/terminal.ts +60 -0
  18. package/package.json +16 -11
  19. package/{capabilities.ts → src/capabilities.ts} +8 -0
  20. package/src/client/client-refresh.ts +229 -0
  21. package/{client.ts → src/client/client.ts} +178 -30
  22. package/{transport.ts → src/client/transport.ts} +10 -6
  23. package/src/config.ts +143 -0
  24. package/src/defaults.json +82 -0
  25. package/src/diagnostics/diagnostic-augmentation.ts +82 -0
  26. package/src/diagnostics/diagnostic-display.ts +68 -0
  27. package/{diagnostic-summary.ts → src/diagnostics/diagnostic-summary.ts} +11 -7
  28. package/{diagnostics.ts → src/diagnostics/diagnostics.ts} +9 -4
  29. package/src/diagnostics/stale-diagnostics.ts +47 -0
  30. package/src/diagnostics/suppression-diagnostics.ts +58 -0
  31. package/src/format.ts +359 -0
  32. package/src/guidance.ts +163 -0
  33. package/src/index.ts +17 -0
  34. package/src/lsp-state.ts +82 -0
  35. package/src/lsp.ts +481 -0
  36. package/src/manager/manager-client-state.ts +34 -0
  37. package/src/manager/manager-diagnostics.ts +139 -0
  38. package/src/manager/manager-helpers.ts +39 -0
  39. package/src/manager/manager-project-info.ts +46 -0
  40. package/src/manager/manager-stale-resync.ts +47 -0
  41. package/src/manager/manager-types.ts +39 -0
  42. package/src/manager/manager-workspace-recovery.ts +83 -0
  43. package/src/manager/manager-workspace-symbol.ts +18 -0
  44. package/src/manager/manager.ts +550 -0
  45. package/src/overrides.ts +173 -0
  46. package/src/pattern-matcher.ts +197 -0
  47. package/src/renderer.ts +120 -0
  48. package/src/scanner.ts +153 -0
  49. package/src/search-fallback.ts +98 -0
  50. package/src/service-registry.ts +153 -0
  51. package/src/settings-registration.ts +292 -0
  52. package/{summary.ts → src/summary.ts} +44 -9
  53. package/src/tool-actions.ts +430 -0
  54. package/src/tree-persist.ts +48 -0
  55. package/src/tsconfig-scope.ts +156 -0
  56. package/{types.ts → src/types.ts} +123 -0
  57. package/src/ui.ts +358 -0
  58. package/{utils.ts → src/utils.ts} +8 -25
  59. package/src/workspace-sentinels.ts +114 -0
  60. package/bash-guard.ts +0 -58
  61. package/config.ts +0 -99
  62. package/defaults.json +0 -40
  63. package/format.ts +0 -190
  64. package/guidance.ts +0 -140
  65. package/lsp.ts +0 -375
  66. package/manager.ts +0 -396
  67. package/overrides.ts +0 -95
  68. package/recent-paths.ts +0 -126
  69. package/runtime-state.ts +0 -113
  70. package/tool-actions.ts +0 -211
  71. package/tsconfig.json +0 -5
  72. 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
+ }