typegraph-mcp 0.9.44 → 0.9.45

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/dist/benchmark.js CHANGED
@@ -25,6 +25,7 @@ var TsServerClient = class {
25
25
  shuttingDown = false;
26
26
  restartCount = 0;
27
27
  maxRestarts = 3;
28
+ projectsDirty = false;
28
29
  // ─── Path Resolution ────────────────────────────────────────────────────
29
30
  resolvePath(file) {
30
31
  return path.isAbsolute(file) ? file : path.resolve(this.projectRoot, file);
@@ -201,6 +202,24 @@ var TsServerClient = class {
201
202
  this.sendNotification("open", { file: absPath });
202
203
  await new Promise((r) => setTimeout(r, 50));
203
204
  }
205
+ /**
206
+ * Mark tsserver's view of the disk as stale (a file changed that is NOT open
207
+ * in tsserver). tsserver's own disk watching silently decays in long-lived
208
+ * instances at monorepo scale, leaving closed-file contents frozen at project
209
+ * load time and new files unassigned (they land in single-file inferred
210
+ * projects, producing definition-only reference results). The next query
211
+ * forces a `reloadProjects`, which re-globs configs and re-reads closed files
212
+ * from disk. Open files are unaffected by design — their content is
213
+ * protocol-owned and refreshed via reloadOpenFile().
214
+ */
215
+ markProjectsDirty() {
216
+ this.projectsDirty = true;
217
+ }
218
+ refreshIfDirty() {
219
+ if (!this.projectsDirty) return;
220
+ this.projectsDirty = false;
221
+ this.sendNotification("reloadProjects");
222
+ }
204
223
  async reloadOpenFile(file) {
205
224
  const absPath = this.resolvePath(file);
206
225
  if (!this.openFiles.has(absPath)) return false;
@@ -218,6 +237,7 @@ var TsServerClient = class {
218
237
  }
219
238
  // ─── Public API ────────────────────────────────────────────────────────
220
239
  async definition(file, line, offset) {
240
+ this.refreshIfDirty();
221
241
  const absPath = this.resolvePath(file);
222
242
  await this.ensureOpen(absPath);
223
243
  const body = await this.sendRequest("definition", {
@@ -232,6 +252,7 @@ var TsServerClient = class {
232
252
  }));
233
253
  }
234
254
  async references(file, line, offset) {
255
+ this.refreshIfDirty();
235
256
  const absPath = this.resolvePath(file);
236
257
  await this.ensureOpen(absPath);
237
258
  const body = await this.sendRequest("references", {
@@ -246,6 +267,7 @@ var TsServerClient = class {
246
267
  }));
247
268
  }
248
269
  async quickinfo(file, line, offset) {
270
+ this.refreshIfDirty();
249
271
  const absPath = this.resolvePath(file);
250
272
  await this.ensureOpen(absPath);
251
273
  try {
@@ -260,6 +282,7 @@ var TsServerClient = class {
260
282
  }
261
283
  }
262
284
  async navto(searchValue, maxResults = 10, file) {
285
+ this.refreshIfDirty();
263
286
  if (file) await this.ensureOpen(file);
264
287
  const args = {
265
288
  searchValue,
@@ -274,6 +297,7 @@ var TsServerClient = class {
274
297
  }));
275
298
  }
276
299
  async navbar(file) {
300
+ this.refreshIfDirty();
277
301
  const absPath = this.resolvePath(file);
278
302
  await this.ensureOpen(absPath);
279
303
  const body = await this.sendRequest("navbar", {
package/dist/cli.js CHANGED
@@ -954,6 +954,7 @@ var init_tsserver_client = __esm({
954
954
  shuttingDown = false;
955
955
  restartCount = 0;
956
956
  maxRestarts = 3;
957
+ projectsDirty = false;
957
958
  // ─── Path Resolution ────────────────────────────────────────────────────
958
959
  resolvePath(file) {
959
960
  return path4.isAbsolute(file) ? file : path4.resolve(this.projectRoot, file);
@@ -1130,6 +1131,24 @@ var init_tsserver_client = __esm({
1130
1131
  this.sendNotification("open", { file: absPath2 });
1131
1132
  await new Promise((r) => setTimeout(r, 50));
1132
1133
  }
1134
+ /**
1135
+ * Mark tsserver's view of the disk as stale (a file changed that is NOT open
1136
+ * in tsserver). tsserver's own disk watching silently decays in long-lived
1137
+ * instances at monorepo scale, leaving closed-file contents frozen at project
1138
+ * load time and new files unassigned (they land in single-file inferred
1139
+ * projects, producing definition-only reference results). The next query
1140
+ * forces a `reloadProjects`, which re-globs configs and re-reads closed files
1141
+ * from disk. Open files are unaffected by design — their content is
1142
+ * protocol-owned and refreshed via reloadOpenFile().
1143
+ */
1144
+ markProjectsDirty() {
1145
+ this.projectsDirty = true;
1146
+ }
1147
+ refreshIfDirty() {
1148
+ if (!this.projectsDirty) return;
1149
+ this.projectsDirty = false;
1150
+ this.sendNotification("reloadProjects");
1151
+ }
1133
1152
  async reloadOpenFile(file) {
1134
1153
  const absPath2 = this.resolvePath(file);
1135
1154
  if (!this.openFiles.has(absPath2)) return false;
@@ -1147,6 +1166,7 @@ var init_tsserver_client = __esm({
1147
1166
  }
1148
1167
  // ─── Public API ────────────────────────────────────────────────────────
1149
1168
  async definition(file, line, offset) {
1169
+ this.refreshIfDirty();
1150
1170
  const absPath2 = this.resolvePath(file);
1151
1171
  await this.ensureOpen(absPath2);
1152
1172
  const body = await this.sendRequest("definition", {
@@ -1161,6 +1181,7 @@ var init_tsserver_client = __esm({
1161
1181
  }));
1162
1182
  }
1163
1183
  async references(file, line, offset) {
1184
+ this.refreshIfDirty();
1164
1185
  const absPath2 = this.resolvePath(file);
1165
1186
  await this.ensureOpen(absPath2);
1166
1187
  const body = await this.sendRequest("references", {
@@ -1175,6 +1196,7 @@ var init_tsserver_client = __esm({
1175
1196
  }));
1176
1197
  }
1177
1198
  async quickinfo(file, line, offset) {
1199
+ this.refreshIfDirty();
1178
1200
  const absPath2 = this.resolvePath(file);
1179
1201
  await this.ensureOpen(absPath2);
1180
1202
  try {
@@ -1189,6 +1211,7 @@ var init_tsserver_client = __esm({
1189
1211
  }
1190
1212
  }
1191
1213
  async navto(searchValue, maxResults = 10, file) {
1214
+ this.refreshIfDirty();
1192
1215
  if (file) await this.ensureOpen(file);
1193
1216
  const args2 = {
1194
1217
  searchValue,
@@ -1203,6 +1226,7 @@ var init_tsserver_client = __esm({
1203
1226
  }));
1204
1227
  }
1205
1228
  async navbar(file) {
1229
+ this.refreshIfDirty();
1206
1230
  const absPath2 = this.resolvePath(file);
1207
1231
  await this.ensureOpen(absPath2);
1208
1232
  const body = await this.sendRequest("navbar", {
@@ -2697,11 +2721,18 @@ async function main4() {
2697
2721
  moduleGraph = graphResult.graph;
2698
2722
  moduleResolver = graphResult.resolver;
2699
2723
  startWatcher(projectRoot2, moduleGraph, graphResult.resolver, {
2700
- onFileUpdated: (filePath) => client.reloadOpenFile(filePath).catch((err) => {
2701
- log3(`Failed to reload open file ${relPath2(filePath)}:`, err);
2702
- }),
2724
+ onFileUpdated: (filePath) => client.reloadOpenFile(filePath).then(
2725
+ (wasOpen) => {
2726
+ if (!wasOpen) client.markProjectsDirty();
2727
+ },
2728
+ (err) => {
2729
+ client.markProjectsDirty();
2730
+ log3(`Failed to reload open file ${relPath2(filePath)}:`, err);
2731
+ }
2732
+ ),
2703
2733
  onFileDeleted: (filePath) => {
2704
2734
  client.closeFile(filePath);
2735
+ client.markProjectsDirty();
2705
2736
  }
2706
2737
  });
2707
2738
  const transport = new StdioServerTransport();
package/dist/server.js CHANGED
@@ -26,6 +26,7 @@ var TsServerClient = class {
26
26
  shuttingDown = false;
27
27
  restartCount = 0;
28
28
  maxRestarts = 3;
29
+ projectsDirty = false;
29
30
  // ─── Path Resolution ────────────────────────────────────────────────────
30
31
  resolvePath(file) {
31
32
  return path.isAbsolute(file) ? file : path.resolve(this.projectRoot, file);
@@ -202,6 +203,24 @@ var TsServerClient = class {
202
203
  this.sendNotification("open", { file: absPath2 });
203
204
  await new Promise((r) => setTimeout(r, 50));
204
205
  }
206
+ /**
207
+ * Mark tsserver's view of the disk as stale (a file changed that is NOT open
208
+ * in tsserver). tsserver's own disk watching silently decays in long-lived
209
+ * instances at monorepo scale, leaving closed-file contents frozen at project
210
+ * load time and new files unassigned (they land in single-file inferred
211
+ * projects, producing definition-only reference results). The next query
212
+ * forces a `reloadProjects`, which re-globs configs and re-reads closed files
213
+ * from disk. Open files are unaffected by design — their content is
214
+ * protocol-owned and refreshed via reloadOpenFile().
215
+ */
216
+ markProjectsDirty() {
217
+ this.projectsDirty = true;
218
+ }
219
+ refreshIfDirty() {
220
+ if (!this.projectsDirty) return;
221
+ this.projectsDirty = false;
222
+ this.sendNotification("reloadProjects");
223
+ }
205
224
  async reloadOpenFile(file) {
206
225
  const absPath2 = this.resolvePath(file);
207
226
  if (!this.openFiles.has(absPath2)) return false;
@@ -219,6 +238,7 @@ var TsServerClient = class {
219
238
  }
220
239
  // ─── Public API ────────────────────────────────────────────────────────
221
240
  async definition(file, line, offset) {
241
+ this.refreshIfDirty();
222
242
  const absPath2 = this.resolvePath(file);
223
243
  await this.ensureOpen(absPath2);
224
244
  const body = await this.sendRequest("definition", {
@@ -233,6 +253,7 @@ var TsServerClient = class {
233
253
  }));
234
254
  }
235
255
  async references(file, line, offset) {
256
+ this.refreshIfDirty();
236
257
  const absPath2 = this.resolvePath(file);
237
258
  await this.ensureOpen(absPath2);
238
259
  const body = await this.sendRequest("references", {
@@ -247,6 +268,7 @@ var TsServerClient = class {
247
268
  }));
248
269
  }
249
270
  async quickinfo(file, line, offset) {
271
+ this.refreshIfDirty();
250
272
  const absPath2 = this.resolvePath(file);
251
273
  await this.ensureOpen(absPath2);
252
274
  try {
@@ -261,6 +283,7 @@ var TsServerClient = class {
261
283
  }
262
284
  }
263
285
  async navto(searchValue, maxResults = 10, file) {
286
+ this.refreshIfDirty();
264
287
  if (file) await this.ensureOpen(file);
265
288
  const args = {
266
289
  searchValue,
@@ -275,6 +298,7 @@ var TsServerClient = class {
275
298
  }));
276
299
  }
277
300
  async navbar(file) {
301
+ this.refreshIfDirty();
278
302
  const absPath2 = this.resolvePath(file);
279
303
  await this.ensureOpen(absPath2);
280
304
  const body = await this.sendRequest("navbar", {
@@ -1695,11 +1719,18 @@ async function main() {
1695
1719
  moduleGraph = graphResult.graph;
1696
1720
  moduleResolver = graphResult.resolver;
1697
1721
  startWatcher(projectRoot, moduleGraph, graphResult.resolver, {
1698
- onFileUpdated: (filePath) => client.reloadOpenFile(filePath).catch((err) => {
1699
- log3(`Failed to reload open file ${relPath(filePath)}:`, err);
1700
- }),
1722
+ onFileUpdated: (filePath) => client.reloadOpenFile(filePath).then(
1723
+ (wasOpen) => {
1724
+ if (!wasOpen) client.markProjectsDirty();
1725
+ },
1726
+ (err) => {
1727
+ client.markProjectsDirty();
1728
+ log3(`Failed to reload open file ${relPath(filePath)}:`, err);
1729
+ }
1730
+ ),
1701
1731
  onFileDeleted: (filePath) => {
1702
1732
  client.closeFile(filePath);
1733
+ client.markProjectsDirty();
1703
1734
  }
1704
1735
  });
1705
1736
  const transport = new StdioServerTransport();
@@ -24,6 +24,7 @@ var TsServerClient = class {
24
24
  shuttingDown = false;
25
25
  restartCount = 0;
26
26
  maxRestarts = 3;
27
+ projectsDirty = false;
27
28
  // ─── Path Resolution ────────────────────────────────────────────────────
28
29
  resolvePath(file) {
29
30
  return path.isAbsolute(file) ? file : path.resolve(this.projectRoot, file);
@@ -200,6 +201,24 @@ var TsServerClient = class {
200
201
  this.sendNotification("open", { file: absPath });
201
202
  await new Promise((r) => setTimeout(r, 50));
202
203
  }
204
+ /**
205
+ * Mark tsserver's view of the disk as stale (a file changed that is NOT open
206
+ * in tsserver). tsserver's own disk watching silently decays in long-lived
207
+ * instances at monorepo scale, leaving closed-file contents frozen at project
208
+ * load time and new files unassigned (they land in single-file inferred
209
+ * projects, producing definition-only reference results). The next query
210
+ * forces a `reloadProjects`, which re-globs configs and re-reads closed files
211
+ * from disk. Open files are unaffected by design — their content is
212
+ * protocol-owned and refreshed via reloadOpenFile().
213
+ */
214
+ markProjectsDirty() {
215
+ this.projectsDirty = true;
216
+ }
217
+ refreshIfDirty() {
218
+ if (!this.projectsDirty) return;
219
+ this.projectsDirty = false;
220
+ this.sendNotification("reloadProjects");
221
+ }
203
222
  async reloadOpenFile(file) {
204
223
  const absPath = this.resolvePath(file);
205
224
  if (!this.openFiles.has(absPath)) return false;
@@ -217,6 +236,7 @@ var TsServerClient = class {
217
236
  }
218
237
  // ─── Public API ────────────────────────────────────────────────────────
219
238
  async definition(file, line, offset) {
239
+ this.refreshIfDirty();
220
240
  const absPath = this.resolvePath(file);
221
241
  await this.ensureOpen(absPath);
222
242
  const body = await this.sendRequest("definition", {
@@ -231,6 +251,7 @@ var TsServerClient = class {
231
251
  }));
232
252
  }
233
253
  async references(file, line, offset) {
254
+ this.refreshIfDirty();
234
255
  const absPath = this.resolvePath(file);
235
256
  await this.ensureOpen(absPath);
236
257
  const body = await this.sendRequest("references", {
@@ -245,6 +266,7 @@ var TsServerClient = class {
245
266
  }));
246
267
  }
247
268
  async quickinfo(file, line, offset) {
269
+ this.refreshIfDirty();
248
270
  const absPath = this.resolvePath(file);
249
271
  await this.ensureOpen(absPath);
250
272
  try {
@@ -259,6 +281,7 @@ var TsServerClient = class {
259
281
  }
260
282
  }
261
283
  async navto(searchValue, maxResults = 10, file) {
284
+ this.refreshIfDirty();
262
285
  if (file) await this.ensureOpen(file);
263
286
  const args = {
264
287
  searchValue,
@@ -273,6 +296,7 @@ var TsServerClient = class {
273
296
  }));
274
297
  }
275
298
  async navbar(file) {
299
+ this.refreshIfDirty();
276
300
  const absPath = this.resolvePath(file);
277
301
  await this.ensureOpen(absPath);
278
302
  const body = await this.sendRequest("navbar", {
@@ -19,6 +19,7 @@ var TsServerClient = class {
19
19
  shuttingDown = false;
20
20
  restartCount = 0;
21
21
  maxRestarts = 3;
22
+ projectsDirty = false;
22
23
  // ─── Path Resolution ────────────────────────────────────────────────────
23
24
  resolvePath(file) {
24
25
  return path.isAbsolute(file) ? file : path.resolve(this.projectRoot, file);
@@ -195,6 +196,24 @@ var TsServerClient = class {
195
196
  this.sendNotification("open", { file: absPath });
196
197
  await new Promise((r) => setTimeout(r, 50));
197
198
  }
199
+ /**
200
+ * Mark tsserver's view of the disk as stale (a file changed that is NOT open
201
+ * in tsserver). tsserver's own disk watching silently decays in long-lived
202
+ * instances at monorepo scale, leaving closed-file contents frozen at project
203
+ * load time and new files unassigned (they land in single-file inferred
204
+ * projects, producing definition-only reference results). The next query
205
+ * forces a `reloadProjects`, which re-globs configs and re-reads closed files
206
+ * from disk. Open files are unaffected by design — their content is
207
+ * protocol-owned and refreshed via reloadOpenFile().
208
+ */
209
+ markProjectsDirty() {
210
+ this.projectsDirty = true;
211
+ }
212
+ refreshIfDirty() {
213
+ if (!this.projectsDirty) return;
214
+ this.projectsDirty = false;
215
+ this.sendNotification("reloadProjects");
216
+ }
198
217
  async reloadOpenFile(file) {
199
218
  const absPath = this.resolvePath(file);
200
219
  if (!this.openFiles.has(absPath)) return false;
@@ -212,6 +231,7 @@ var TsServerClient = class {
212
231
  }
213
232
  // ─── Public API ────────────────────────────────────────────────────────
214
233
  async definition(file, line, offset) {
234
+ this.refreshIfDirty();
215
235
  const absPath = this.resolvePath(file);
216
236
  await this.ensureOpen(absPath);
217
237
  const body = await this.sendRequest("definition", {
@@ -226,6 +246,7 @@ var TsServerClient = class {
226
246
  }));
227
247
  }
228
248
  async references(file, line, offset) {
249
+ this.refreshIfDirty();
229
250
  const absPath = this.resolvePath(file);
230
251
  await this.ensureOpen(absPath);
231
252
  const body = await this.sendRequest("references", {
@@ -240,6 +261,7 @@ var TsServerClient = class {
240
261
  }));
241
262
  }
242
263
  async quickinfo(file, line, offset) {
264
+ this.refreshIfDirty();
243
265
  const absPath = this.resolvePath(file);
244
266
  await this.ensureOpen(absPath);
245
267
  try {
@@ -254,6 +276,7 @@ var TsServerClient = class {
254
276
  }
255
277
  }
256
278
  async navto(searchValue, maxResults = 10, file) {
279
+ this.refreshIfDirty();
257
280
  if (file) await this.ensureOpen(file);
258
281
  const args = {
259
282
  searchValue,
@@ -268,6 +291,7 @@ var TsServerClient = class {
268
291
  }));
269
292
  }
270
293
  async navbar(file) {
294
+ this.refreshIfDirty();
271
295
  const absPath = this.resolvePath(file);
272
296
  await this.ensureOpen(absPath);
273
297
  const body = await this.sendRequest("navbar", {
@@ -114,6 +114,12 @@ async function main(): Promise<void> {
114
114
  );
115
115
  writeFile(projectRoot, "src/test.ts", "export const oldName = 1 as const;\n");
116
116
  writeFile(projectRoot, "src/util.ts", "export const helper = 1 as const;\n");
117
+ writeFile(projectRoot, "src/closed.ts", "export const closedValue = 1 as const;\n");
118
+ writeFile(
119
+ projectRoot,
120
+ "src/closed-consumer.ts",
121
+ 'import { closedValue } from "./closed";\nexport const observed = closedValue;\n'
122
+ );
117
123
 
118
124
  fs.mkdirSync(path.join(projectRoot, "node_modules"), { recursive: true });
119
125
  fs.symlinkSync(
@@ -196,6 +202,25 @@ async function main(): Promise<void> {
196
202
  assert.ok(!exportsResult.exports.some((item) => item.symbol === "oldName"));
197
203
  });
198
204
 
205
+ // Change a file that tsserver has not opened. The watcher should mark
206
+ // projects dirty so the next semantic query reloads closed-file contents.
207
+ writeFile(projectRoot, "src/closed.ts", "export const closedValue = 2 as const;\n");
208
+
209
+ await waitFor("closed file update to refresh semantic project state", async () => {
210
+ const deps = await callTool<DependencyTreeResult>("ts_dependency_tree", {
211
+ file: "src/closed-consumer.ts",
212
+ });
213
+ const normalizedDeps = deps.files.map(normalize);
214
+ assert.ok(normalizedDeps.includes("src/closed.ts"), `Expected src/closed.ts in ${normalizedDeps}`);
215
+
216
+ const typeInfo = await callTool<TypeInfoResult>("ts_type_info", {
217
+ file: "src/closed-consumer.ts",
218
+ line: 2,
219
+ column: 14,
220
+ });
221
+ assert.match(typeInfo.type ?? "", /\b2\b/);
222
+ });
223
+
199
224
  // Open util.ts directly so tsserver tracks it, then delete it from disk.
200
225
  const utilInfo = await callTool<TypeInfoResult>("ts_type_info", {
201
226
  file: "src/util.ts",
@@ -223,6 +248,7 @@ async function main(): Promise<void> {
223
248
  console.log("==============================");
224
249
  console.log(" ✓ import swaps keep dependency_tree and type_info aligned");
225
250
  console.log(" ✓ export renames refresh ts_module_exports semantic metadata");
251
+ console.log(" ✓ closed-file edits refresh tsserver project state");
226
252
  console.log(" ✓ deleted open files do not survive as tsserver ghost snapshots");
227
253
  } finally {
228
254
  await transport.close().catch(() => {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typegraph-mcp",
3
- "version": "0.9.44",
3
+ "version": "0.9.45",
4
4
  "description": "Type-aware codebase navigation for AI coding agents — 14 MCP tools powered by tsserver + oxc",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/server.ts CHANGED
@@ -1134,11 +1134,20 @@ async function main() {
1134
1134
  moduleResolver = graphResult.resolver;
1135
1135
  startWatcher(projectRoot, moduleGraph, graphResult.resolver, {
1136
1136
  onFileUpdated: (filePath) =>
1137
- client.reloadOpenFile(filePath).catch((err) => {
1138
- log(`Failed to reload open file ${relPath(filePath)}:`, err);
1139
- }),
1137
+ client.reloadOpenFile(filePath).then(
1138
+ (wasOpen) => {
1139
+ // Closed files: tsserver's own disk watching decays in long-lived
1140
+ // instances; force a projects reload before the next query.
1141
+ if (!wasOpen) client.markProjectsDirty();
1142
+ },
1143
+ (err) => {
1144
+ client.markProjectsDirty();
1145
+ log(`Failed to reload open file ${relPath(filePath)}:`, err);
1146
+ }
1147
+ ),
1140
1148
  onFileDeleted: (filePath) => {
1141
1149
  client.closeFile(filePath);
1150
+ client.markProjectsDirty();
1142
1151
  },
1143
1152
  });
1144
1153
 
@@ -90,6 +90,7 @@ export class TsServerClient {
90
90
  private shuttingDown = false;
91
91
  private restartCount = 0;
92
92
  private readonly maxRestarts = 3;
93
+ private projectsDirty = false;
93
94
 
94
95
  constructor(
95
96
  private readonly projectRoot: string,
@@ -323,6 +324,29 @@ export class TsServerClient {
323
324
  await new Promise((r) => setTimeout(r, 50));
324
325
  }
325
326
 
327
+ /**
328
+ * Mark tsserver's view of the disk as stale (a file changed that is NOT open
329
+ * in tsserver). tsserver's own disk watching silently decays in long-lived
330
+ * instances at monorepo scale, leaving closed-file contents frozen at project
331
+ * load time and new files unassigned (they land in single-file inferred
332
+ * projects, producing definition-only reference results). The next query
333
+ * forces a `reloadProjects`, which re-globs configs and re-reads closed files
334
+ * from disk. Open files are unaffected by design — their content is
335
+ * protocol-owned and refreshed via reloadOpenFile().
336
+ */
337
+ markProjectsDirty(): void {
338
+ this.projectsDirty = true;
339
+ }
340
+
341
+ private refreshIfDirty(): void {
342
+ if (!this.projectsDirty) return;
343
+ this.projectsDirty = false;
344
+ // reloadProjects sends no response (notRequired), so fire it as a
345
+ // notification; the following request queues behind the reload on
346
+ // tsserver's single-threaded loop.
347
+ this.sendNotification("reloadProjects");
348
+ }
349
+
326
350
  async reloadOpenFile(file: string): Promise<boolean> {
327
351
  const absPath = this.resolvePath(file);
328
352
  if (!this.openFiles.has(absPath)) return false;
@@ -343,6 +367,7 @@ export class TsServerClient {
343
367
  // ─── Public API ────────────────────────────────────────────────────────
344
368
 
345
369
  async definition(file: string, line: number, offset: number): Promise<DefinitionResult[]> {
370
+ this.refreshIfDirty();
346
371
  const absPath = this.resolvePath(file);
347
372
  await this.ensureOpen(absPath);
348
373
 
@@ -361,6 +386,7 @@ export class TsServerClient {
361
386
  }
362
387
 
363
388
  async references(file: string, line: number, offset: number): Promise<ReferenceEntry[]> {
389
+ this.refreshIfDirty();
364
390
  const absPath = this.resolvePath(file);
365
391
  await this.ensureOpen(absPath);
366
392
 
@@ -379,6 +405,7 @@ export class TsServerClient {
379
405
  }
380
406
 
381
407
  async quickinfo(file: string, line: number, offset: number): Promise<QuickInfoResult | null> {
408
+ this.refreshIfDirty();
382
409
  const absPath = this.resolvePath(file);
383
410
  await this.ensureOpen(absPath);
384
411
 
@@ -398,6 +425,7 @@ export class TsServerClient {
398
425
  }
399
426
 
400
427
  async navto(searchValue: string, maxResults = 10, file?: string): Promise<NavToItem[]> {
428
+ this.refreshIfDirty();
401
429
  // If a file is specified, open it first so tsserver knows about it
402
430
  if (file) await this.ensureOpen(file);
403
431
 
@@ -418,6 +446,7 @@ export class TsServerClient {
418
446
  }
419
447
 
420
448
  async navbar(file: string): Promise<NavBarItem[]> {
449
+ this.refreshIfDirty();
421
450
  const absPath = this.resolvePath(file);
422
451
  await this.ensureOpen(absPath);
423
452