@mrclrchtr/supi-lsp 1.0.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "0.2.0",
3
+ "version": "1.1.2",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,9 +22,5 @@
22
22
  "@earendil-works/pi-coding-agent": "*",
23
23
  "@earendil-works/pi-tui": "*"
24
24
  },
25
- "devDependencies": {
26
- "@types/node": "25.6.2",
27
- "vitest": "4.1.5"
28
- },
29
25
  "main": "src/index.ts"
30
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-lsp",
3
- "version": "1.0.0",
3
+ "version": "1.1.2",
4
4
  "description": "SuPi LSP extension — Language Server Protocol integration for pi",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -21,7 +21,7 @@
21
21
  "!__tests__"
22
22
  ],
23
23
  "dependencies": {
24
- "@mrclrchtr/supi-core": "workspace:*"
24
+ "@mrclrchtr/supi-core": "1.1.2"
25
25
  },
26
26
  "bundledDependencies": [
27
27
  "@mrclrchtr/supi-core"
@@ -32,10 +32,6 @@
32
32
  "@earendil-works/pi-tui": "*",
33
33
  "typebox": "*"
34
34
  },
35
- "devDependencies": {
36
- "vitest": "4.1.5",
37
- "@mrclrchtr/supi-test-utils": "workspace:*"
38
- },
39
35
  "pi": {
40
36
  "extensions": [
41
37
  "./src/lsp.ts"
@@ -31,7 +31,7 @@ export function assessStaleDiagnostics(
31
31
  };
32
32
  }
33
33
 
34
- function isLikelyStaleDiagnostic(diagnostic: Diagnostic): boolean {
34
+ export function isLikelyStaleDiagnostic(diagnostic: Diagnostic): boolean {
35
35
  if (diagnostic.severity === undefined) return false;
36
36
  if (diagnostic.code !== undefined) {
37
37
  if (typeof diagnostic.code === "number" && MODULE_RESOLUTION_CODES.has(diagnostic.code)) {
package/src/lsp.ts CHANGED
@@ -29,6 +29,7 @@ import {
29
29
  removeLspTool,
30
30
  } from "./lsp-state.ts";
31
31
  import { LspManager } from "./manager/manager.ts";
32
+ import { forceResyncStaleModuleFiles } from "./manager/manager-stale-resync.ts";
32
33
  import { registerLspAwareToolOverrides } from "./overrides.ts";
33
34
  import { registerLspMessageRenderer } from "./renderer.ts";
34
35
  import { scanMissingServers, scanProjectCapabilities, startDetectedServers } from "./scanner.ts";
@@ -305,6 +306,16 @@ function registerBehaviorHandlers(pi: ExtensionAPI, state: LspRuntimeState): voi
305
306
  // Refresh failures must not prevent agent startup
306
307
  }
307
308
  state.manager.pruneMissingFiles();
309
+
310
+ // Force re-open files with module-resolution errors to clear stale
311
+ // diagnostics that persist when the TS server caches by content hash.
312
+ // Must run before the diagnostic summary so fresh results are captured.
313
+ try {
314
+ await forceResyncStaleModuleFiles(state.manager, ctx.cwd);
315
+ } catch {
316
+ // Best-effort: don't fail the agent turn
317
+ }
318
+
308
319
  refreshProjectServers(state);
309
320
  updateLspUi(ctx, state.manager, state.inlineSeverity, state.projectServers);
310
321
 
@@ -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
+ }
@@ -151,7 +151,7 @@ function buildLspSettingItems(
151
151
  id: "exclude",
152
152
  label: "Exclude Patterns",
153
153
  description:
154
- "Gitignore patterns to suppress LSP diagnostics (e.g. __tests__/, *.generated.ts)",
154
+ "Gitignore patterns to suppress LSP diagnostics. Edit .pi/supi/config.json → lsp.exclude (or ~/.pi/agent/supi/config.json for global). Patterns like __tests__/ exclude a directory, *.test.ts wildcards match at any depth, /dist anchors to root.",
155
155
  currentValue: settings.exclude.length > 0 ? settings.exclude.join(", ") : "none",
156
156
  submenu: (_currentValue, done) => createExcludeSubmenu(scope, cwd, settings, done),
157
157
  },