@mrclrchtr/supi-lsp 1.16.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +44 -56
  2. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  3. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  4. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  5. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  6. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  7. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  8. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  9. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  10. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  11. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  12. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  13. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  14. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  15. package/node_modules/@mrclrchtr/supi-code-runtime/package.json +3 -2
  16. package/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +7 -0
  17. package/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +56 -2
  18. package/node_modules/@mrclrchtr/supi-code-runtime/src/evidence-badge.ts +40 -0
  19. package/node_modules/@mrclrchtr/supi-code-runtime/src/index.ts +5 -0
  20. package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +76 -3
  21. package/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/runtime.ts +37 -2
  22. package/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  23. package/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  24. package/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  25. package/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  26. package/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  27. package/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  28. package/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  29. package/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  30. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  31. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  32. package/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  33. package/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  34. package/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  35. package/node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.d.ts +21 -2
  36. package/node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.js +1 -0
  37. package/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineValue.d.ts +2 -1
  38. package/node_modules/vscode-languageserver-protocol/package.json +1 -1
  39. package/package.json +4 -31
  40. package/src/api.ts +27 -0
  41. package/src/client/client-refresh.ts +5 -0
  42. package/src/client/client.ts +246 -1
  43. package/src/client/transport.ts +4 -0
  44. package/src/config/capabilities.ts +3 -0
  45. package/src/config/config.ts +4 -2
  46. package/src/config/lsp-settings.ts +102 -0
  47. package/src/config/server-actions.ts +59 -0
  48. package/src/config/server-config.ts +4 -0
  49. package/src/index.ts +11 -0
  50. package/src/manager/capability-index.ts +1 -1
  51. package/src/manager/manager-project-info.ts +2 -1
  52. package/src/manager/manager.ts +115 -26
  53. package/src/provider/lsp-semantic-provider.ts +177 -134
  54. package/src/provider/refactor-planning.ts +214 -0
  55. package/src/session/runtime-controller.ts +320 -0
  56. package/src/session/runtime-registration.ts +26 -5
  57. package/src/session/service-registry.ts +81 -4
  58. package/src/summary.ts +2 -0
  59. package/src/extension.ts +0 -1
  60. package/src/format.ts +0 -373
  61. package/src/handlers/diagnostic-injection.ts +0 -182
  62. package/src/handlers/session-lifecycle.ts +0 -149
  63. package/src/handlers/status-command.ts +0 -38
  64. package/src/handlers/workspace-recovery.ts +0 -92
  65. package/src/lsp.ts +0 -37
  66. package/src/session/lsp-state.ts +0 -93
  67. package/src/session/settings-registration.ts +0 -296
  68. package/src/session/tree-persist.ts +0 -75
  69. package/src/tool/guidance.ts +0 -69
  70. package/src/tool/names.ts +0 -27
  71. package/src/tool/overrides.ts +0 -204
  72. package/src/tool/register-tools.ts +0 -69
  73. package/src/tool/service-actions.ts +0 -399
  74. package/src/tool/tool-specs.ts +0 -248
  75. package/src/ui/renderer.ts +0 -120
  76. package/src/ui/ui.ts +0 -360
  77. package/src/workspace-change.ts +0 -40
@@ -1,149 +0,0 @@
1
- // Session lifecycle handlers — session_start, session_shutdown, and agent_end.
2
- //
3
- // Extracted from lsp.ts to keep each orchestration concern in its own module.
4
-
5
- import type {
6
- AgentEndEvent,
7
- ExtensionAPI,
8
- ExtensionContext,
9
- SessionStartEvent,
10
- } from "@earendil-works/pi-coding-agent";
11
- import type { WorkspaceRuntime } from "@mrclrchtr/supi-code-runtime/api";
12
- import { loadConfig, resolveLanguageAlias } from "../config/config.ts";
13
- import { clearTsconfigCache } from "../config/tsconfig-scope.ts";
14
- import { scanWorkspaceSentinels } from "../diagnostics/workspace-sentinels.ts";
15
- import { LspManager } from "../manager/manager.ts";
16
- import {
17
- disableLspState,
18
- ensureLspToolsActive,
19
- type LspRuntimeState,
20
- refreshProjectServers,
21
- } from "../session/lsp-state.ts";
22
- import {
23
- registerLspCapabilities,
24
- unregisterLspCapabilities,
25
- } from "../session/runtime-registration.ts";
26
- import {
27
- scanMissingServers,
28
- scanProjectCapabilities,
29
- startDetectedServers,
30
- } from "../session/scanner.ts";
31
- import {
32
- clearSessionLspService,
33
- SessionLspService,
34
- setSessionLspServiceState,
35
- } from "../session/service-registry.ts";
36
- import { loadLspSettings } from "../session/settings-registration.ts";
37
- import { persistLspActiveState, persistLspInactiveState } from "../session/tree-persist.ts";
38
- import { buildLspToolPromptSurfaces } from "../tool/guidance.ts";
39
- import { registerLspTools } from "../tool/register-tools.ts";
40
- import { updateLspUi } from "../ui/ui.ts";
41
-
42
- /**
43
- * Register session lifecycle handlers (start, shutdown, and agent-end cleanup).
44
- *
45
- * - `session_start`: initialises the LspManager, starts detected servers, wires
46
- * dynamic tool guidance, publishes runtime capabilities, and syncs UI state.
47
- * - `session_shutdown`: tears down the manager and clears runtime state.
48
- * - `agent_end`: refreshes project-server info and updates the LSP status UI.
49
- */
50
- export function registerSessionLifecycleHandlers(
51
- pi: ExtensionAPI,
52
- state: LspRuntimeState,
53
- runtime: WorkspaceRuntime,
54
- ): void {
55
- // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: session_start orchestrates setup, server detection, settings, and persistence.
56
- pi.on("session_start", async (_event: SessionStartEvent, ctx: ExtensionContext) => {
57
- if (state.manager) {
58
- clearSessionLspService(state.manager.getCwd());
59
- await state.manager.shutdownAll();
60
- }
61
-
62
- const cwd = ctx.cwd;
63
- clearTsconfigCache();
64
- const lspSettings = loadLspSettings(cwd);
65
-
66
- if (!lspSettings.enabled) {
67
- clearSessionLspService(cwd);
68
- disableLspState(pi, state);
69
- persistLspInactiveState(pi, state);
70
- setSessionLspServiceState(cwd, { kind: "disabled" });
71
- return;
72
- }
73
-
74
- state.inlineSeverity = lspSettings.severity;
75
-
76
- const config = loadConfig(cwd);
77
-
78
- // Apply server allowlist filter from supi shared config
79
- if (lspSettings.active.length > 0) {
80
- const allowList = new Set(lspSettings.active.map(resolveLanguageAlias));
81
- for (const name of Object.keys(config.servers)) {
82
- if (!allowList.has(name)) {
83
- delete config.servers[name];
84
- }
85
- }
86
- }
87
-
88
- clearSessionLspService(cwd);
89
- state.manager = new LspManager(config, cwd);
90
- state.manager.setExcludePatterns(lspSettings.exclude ?? []);
91
- setSessionLspServiceState(cwd, { kind: "pending" });
92
- state.detectedServers = scanProjectCapabilities(config, cwd);
93
- state.manager.registerDetectedServers(state.detectedServers);
94
- await startDetectedServers(state.manager, state.detectedServers);
95
-
96
- const missing = scanMissingServers(config, cwd);
97
- if (missing.length > 0) {
98
- const parts = missing.map((m) => `${m.name} (${m.command})`);
99
- ctx.ui.notify(
100
- `LSP server not found for: ${parts.join(", ")}. Install the server to enable language intelligence.`,
101
- "warning",
102
- );
103
- }
104
-
105
- state.sentinelSnapshot = scanWorkspaceSentinels(cwd);
106
- state.lastWorkspaceChangeAt = 0;
107
- state.staleSuspected = false;
108
- refreshProjectServers(state);
109
- state.lastDiagnosticsFingerprint = null;
110
- state.currentContextToken = null;
111
- state.lspActive = true;
112
- const service = new SessionLspService(state.manager);
113
- setSessionLspServiceState(cwd, { kind: "ready", service });
114
- registerLspCapabilities(runtime, cwd, service);
115
- registerLspTools(pi, buildLspToolPromptSurfaces(state.projectServers, cwd));
116
- ensureLspToolsActive(pi);
117
- persistLspActiveState(pi, state);
118
- updateLspUi(ctx, state.manager, state.inlineSeverity, state.projectServers);
119
- });
120
-
121
- pi.on("session_shutdown", async () => {
122
- clearTsconfigCache();
123
- if (state.manager) {
124
- const cwd = state.manager.getCwd();
125
- unregisterLspCapabilities(runtime, cwd);
126
- clearSessionLspService(cwd);
127
- await state.manager.shutdownAll();
128
- state.manager = null;
129
- }
130
-
131
- state.inspector.close?.();
132
- state.detectedServers = [];
133
- state.projectServers = [];
134
- state.lastDiagnosticsFingerprint = null;
135
- state.currentContextToken = null;
136
- state.staleSuspected = false;
137
- state.lastWorkspaceChangeAt = 0;
138
- state.sentinelSnapshot = new Map();
139
- });
140
-
141
- pi.on("agent_end", async (_event: AgentEndEvent, ctx: ExtensionContext) => {
142
- state.currentContextToken = null;
143
- refreshProjectServers(state);
144
-
145
- if (state.manager) {
146
- updateLspUi(ctx, state.manager, state.inlineSeverity, state.projectServers);
147
- }
148
- });
149
- }
@@ -1,38 +0,0 @@
1
- // LSP status command — /lsp-status overlay.
2
- //
3
- // Extracted from lsp.ts to keep each orchestration concern in its own module.
4
-
5
- import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
6
- import { type LspRuntimeState, refreshProjectServers } from "../session/lsp-state.ts";
7
- import { getLspDisabledMessage, loadLspSettings } from "../session/settings-registration.ts";
8
- import { toggleLspStatusOverlay } from "../ui/ui.ts";
9
-
10
- /**
11
- * Register the /lsp-status command that opens an LSP inspector overlay.
12
- */
13
- export function registerLspStatusCommand(pi: ExtensionAPI, state: LspRuntimeState): void {
14
- pi.registerCommand("lsp-status", {
15
- description: "Show detected LSP servers, roots, open files, and diagnostics",
16
- handler: async (_args: string, ctx: ExtensionContext) => {
17
- const lspSettings = loadLspSettings(ctx.cwd);
18
- if (!lspSettings.enabled) {
19
- ctx.ui.notify(getLspDisabledMessage(ctx.cwd), "warning");
20
- return;
21
- }
22
-
23
- if (!state.manager) {
24
- ctx.ui.notify("LSP not initialized", "warning");
25
- return;
26
- }
27
-
28
- refreshProjectServers(state);
29
- toggleLspStatusOverlay(
30
- ctx,
31
- state.manager,
32
- state.inlineSeverity,
33
- state.inspector,
34
- state.projectServers,
35
- );
36
- },
37
- });
38
- }
@@ -1,92 +0,0 @@
1
- // Workspace recovery handler — tool_result event.
2
- //
3
- // Extracted from lsp.ts to keep each orchestration concern in its own module.
4
-
5
- import type {
6
- ExtensionAPI,
7
- ExtensionContext,
8
- ToolResultEvent,
9
- } from "@earendil-works/pi-coding-agent";
10
- import { clearTsconfigCache } from "../config/tsconfig-scope.ts";
11
- import { FileChangeType, type FileEvent } from "../config/types.ts";
12
- import {
13
- isWorkspaceRecoveryTrigger,
14
- syncWorkspaceSentinelSnapshot,
15
- } from "../diagnostics/workspace-sentinels.ts";
16
- import {
17
- isLspAwareTool,
18
- type LspRuntimeState,
19
- refreshProjectServers,
20
- } from "../session/lsp-state.ts";
21
- import { updateLspUi } from "../ui/ui.ts";
22
- import { fileToUri, resolveSessionPath } from "../utils.ts";
23
- import {
24
- shouldInvalidateTsconfigScopeCache,
25
- softRecoverWorkspaceChanges,
26
- } from "../workspace-change.ts";
27
-
28
- /**
29
- * Register the tool_result handler that detects workspace changes from
30
- * write / edit tool results and recovers LSP state accordingly.
31
- */
32
- export function registerWorkspaceRecoveryHandler(pi: ExtensionAPI, state: LspRuntimeState): void {
33
- pi.on("tool_result", async (event: ToolResultEvent, ctx: ExtensionContext) => {
34
- if (!state.manager) return;
35
-
36
- const recoveryTriggered = recoverWorkspaceChangesFromToolResult(state, ctx.cwd, {
37
- toolName: event.toolName,
38
- isError: event.isError,
39
- input: (event as { input?: unknown }).input,
40
- });
41
-
42
- if (recoveryTriggered || isLspAwareTool(event.toolName)) {
43
- refreshProjectServers(state);
44
- updateLspUi(ctx, state.manager, state.inlineSeverity, state.projectServers);
45
- }
46
- });
47
- }
48
-
49
- /**
50
- * Determine whether a tool result (write/edit) should trigger workspace recovery.
51
- *
52
- * Returns true and recovers when the file is:
53
- * - a sentinel file (package.json, tsconfig, lockfile, .d.ts)
54
- * - a source file whose extension matches an active language server's file types
55
- * - a .json / .jsonc file (tsconfig cache invalidation)
56
- */
57
- function recoverWorkspaceChangesFromToolResult(
58
- state: LspRuntimeState,
59
- cwd: string,
60
- event: { toolName: string; isError: boolean; input?: unknown },
61
- ): boolean {
62
- if (!state.manager || event.isError) return false;
63
- if (event.toolName !== "write" && event.toolName !== "edit") return false;
64
- if (!event.input || typeof event.input !== "object") return false;
65
-
66
- const pathValue = (event.input as { path?: unknown }).path;
67
- if (typeof pathValue !== "string") return false;
68
-
69
- const resolvedPath = resolveSessionPath(cwd, pathValue);
70
- if (shouldInvalidateTsconfigScopeCache(resolvedPath)) {
71
- clearTsconfigCache();
72
- }
73
- const fileEvent: FileEvent = { uri: fileToUri(resolvedPath), type: FileChangeType.Changed };
74
-
75
- // Sentinel files (package.json, tsconfig.json, lockfiles, .d.ts)
76
- if (isWorkspaceRecoveryTrigger(resolvedPath, cwd)) {
77
- if (resolvedPath.endsWith(".d.ts")) {
78
- return softRecoverWorkspaceChanges(state, [fileEvent]);
79
- }
80
-
81
- const { snapshot, changes } = syncWorkspaceSentinelSnapshot(cwd, state.sentinelSnapshot);
82
- state.sentinelSnapshot = snapshot;
83
- return softRecoverWorkspaceChanges(state, changes.length > 0 ? changes : [fileEvent]);
84
- }
85
-
86
- // Source files matching an active language server's file types
87
- if (state.manager.hasServerForExtension(resolvedPath)) {
88
- return softRecoverWorkspaceChanges(state, [fileEvent]);
89
- }
90
-
91
- return false;
92
- }
package/src/lsp.ts DELETED
@@ -1,37 +0,0 @@
1
- // LSP Extension for pi — wires together the expert semantic toolset and all
2
- // event/behaviour handlers. Handler registration is delegated to focused
3
- // modules so each orchestration concern lives in its own file.
4
-
5
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
- import { getDefaultWorkspaceRuntime } from "@mrclrchtr/supi-code-runtime/api";
7
- import { registerDiagnosticInjectionHandlers } from "./handlers/diagnostic-injection.ts";
8
- import { registerSessionLifecycleHandlers } from "./handlers/session-lifecycle.ts";
9
- import { registerLspStatusCommand } from "./handlers/status-command.ts";
10
- import { registerWorkspaceRecoveryHandler } from "./handlers/workspace-recovery.ts";
11
- import { createRuntimeState } from "./session/lsp-state.ts";
12
- import { registerLspSettings } from "./session/settings-registration.ts";
13
- import { registerTreePersistHandlers } from "./session/tree-persist.ts";
14
- import { defaultLspToolPromptSurfaces } from "./tool/guidance.ts";
15
- import { registerLspAwareToolOverrides } from "./tool/overrides.ts";
16
- import { registerLspTools } from "./tool/register-tools.ts";
17
- import { registerLspMessageRenderer } from "./ui/renderer.ts";
18
-
19
- export default function lspExtension(pi: ExtensionAPI) {
20
- registerLspSettings();
21
- const state = createRuntimeState();
22
- const runtime = getDefaultWorkspaceRuntime();
23
-
24
- registerLspAwareToolOverrides(pi, {
25
- getInlineSeverity: () => state.inlineSeverity,
26
- getManager: () => state.manager,
27
- isActive: () => state.lspActive,
28
- });
29
-
30
- registerLspTools(pi, defaultLspToolPromptSurfaces);
31
- registerSessionLifecycleHandlers(pi, state, runtime);
32
- registerDiagnosticInjectionHandlers(pi, state);
33
- registerWorkspaceRecoveryHandler(pi, state);
34
- registerTreePersistHandlers(pi, state);
35
- registerLspStatusCommand(pi, state);
36
- registerLspMessageRenderer(pi);
37
- }
@@ -1,93 +0,0 @@
1
- // LSP extension runtime state and tool management helpers.
2
- // Extracted from lsp.ts to keep file sizes within Biome limits.
3
-
4
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
- import type { DetectedProjectServer, ProjectServerInfo } from "../config/server-config.ts";
6
- import type { LspManager } from "../manager/manager.ts";
7
- import { LSP_TOOL_NAMES } from "../tool/names.ts";
8
- import type { LspInspectorState } from "../ui/ui.ts";
9
- import { introspectCapabilities } from "./scanner.ts";
10
- import { clearSessionLspService } from "./service-registry.ts";
11
-
12
- export interface LspRuntimeState {
13
- manager: LspManager | null;
14
- inlineSeverity: number;
15
- inspector: LspInspectorState;
16
- detectedServers: DetectedProjectServer[];
17
- projectServers: ProjectServerInfo[];
18
- lastDiagnosticsFingerprint: string | null;
19
- currentContextToken: string | null;
20
- contextCounter: number;
21
- lspActive: boolean;
22
- sentinelSnapshot: Map<string, number>;
23
- staleSuspected: boolean;
24
- lastWorkspaceChangeAt: number;
25
- }
26
-
27
- export function createRuntimeState(): LspRuntimeState {
28
- return {
29
- manager: null,
30
- inlineSeverity: 1,
31
- inspector: { handle: null, close: null },
32
- detectedServers: [],
33
- projectServers: [],
34
- lastDiagnosticsFingerprint: null,
35
- currentContextToken: null,
36
- contextCounter: 0,
37
- lspActive: false,
38
- sentinelSnapshot: new Map(),
39
- staleSuspected: false,
40
- lastWorkspaceChangeAt: 0,
41
- };
42
- }
43
-
44
- export function refreshProjectServers(state: LspRuntimeState): void {
45
- if (!state.manager) {
46
- state.projectServers = [];
47
- return;
48
- }
49
- state.projectServers = introspectCapabilities(state.manager, state.detectedServers);
50
- }
51
-
52
- export function isLspAwareTool(toolName: string): boolean {
53
- return (
54
- LSP_TOOL_NAMES.includes(toolName as (typeof LSP_TOOL_NAMES)[number]) ||
55
- toolName === "read" ||
56
- toolName === "write" ||
57
- toolName === "edit"
58
- );
59
- }
60
-
61
- export function disableLspState(pi: ExtensionAPI, state: LspRuntimeState): void {
62
- if (state.manager) {
63
- clearSessionLspService(state.manager.getCwd());
64
- }
65
- state.inspector.close?.();
66
- state.manager = null;
67
- state.detectedServers = [];
68
- state.projectServers = [];
69
- state.lastDiagnosticsFingerprint = null;
70
- state.currentContextToken = null;
71
- state.staleSuspected = false;
72
- state.lastWorkspaceChangeAt = 0;
73
- state.sentinelSnapshot = new Map();
74
- state.lspActive = false;
75
- removeLspTools(pi);
76
- }
77
-
78
- export function removeLspTools(pi: ExtensionAPI): void {
79
- const activeTools = pi.getActiveTools();
80
- const nextTools = activeTools.filter(
81
- (toolName: string) => !LSP_TOOL_NAMES.includes(toolName as (typeof LSP_TOOL_NAMES)[number]),
82
- );
83
- if (nextTools.length !== activeTools.length) {
84
- pi.setActiveTools(nextTools);
85
- }
86
- }
87
-
88
- export function ensureLspToolsActive(pi: ExtensionAPI): void {
89
- const activeTools = pi.getActiveTools();
90
- const missing = LSP_TOOL_NAMES.filter((toolName) => !activeTools.includes(toolName));
91
- if (missing.length === 0) return;
92
- pi.setActiveTools([...activeTools, ...missing]);
93
- }