@treedy/vue-lsp-mcp 0.2.1 → 0.2.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/dist/index.js CHANGED
@@ -19666,6 +19666,17 @@ function getFileContent(filePath) {
19666
19666
  }
19667
19667
  return "";
19668
19668
  }
19669
+ function positionToOffset(content, line, character) {
19670
+ const lines = content.split(`
19671
+ `);
19672
+ const safeLine = Math.max(0, Math.min(line, lines.length - 1));
19673
+ let offset = 0;
19674
+ for (let i = 0;i < safeLine; i++) {
19675
+ offset += lines[i].length + 1;
19676
+ }
19677
+ const safeChar = Math.max(0, Math.min(character, lines[safeLine].length));
19678
+ return offset + safeChar;
19679
+ }
19669
19680
  function toUri(filePath) {
19670
19681
  return `file://${path.resolve(filePath)}`;
19671
19682
  }
@@ -19875,7 +19886,7 @@ async function getConnection(projectRoot) {
19875
19886
  }
19876
19887
  }
19877
19888
  }
19878
- await sendMessage(conn, "initialize", {
19889
+ const initResult = await sendMessage(conn, "initialize", {
19879
19890
  processId: process.pid,
19880
19891
  rootUri: toUri(projectRoot),
19881
19892
  rootPath: projectRoot,
@@ -19885,7 +19896,23 @@ async function getConnection(projectRoot) {
19885
19896
  completion: { completionItem: { snippetSupport: true } },
19886
19897
  signatureHelp: {},
19887
19898
  definition: {},
19899
+ implementation: {},
19900
+ typeDefinition: {},
19888
19901
  references: {},
19902
+ documentHighlight: {},
19903
+ selectionRange: {},
19904
+ foldingRange: {},
19905
+ documentLink: {},
19906
+ callHierarchy: {},
19907
+ codeAction: {
19908
+ dynamicRegistration: false,
19909
+ codeActionLiteralSupport: {
19910
+ codeActionKind: {
19911
+ valueSet: ["quickfix", "refactor", "source", "source.organizeImports"]
19912
+ }
19913
+ }
19914
+ },
19915
+ rename: { prepareSupport: true },
19889
19916
  publishDiagnostics: {},
19890
19917
  synchronization: {
19891
19918
  didOpen: true,
@@ -19914,6 +19941,7 @@ async function getConnection(projectRoot) {
19914
19941
  }
19915
19942
  ]
19916
19943
  });
19944
+ conn.serverCapabilities = initResult?.capabilities || {};
19917
19945
  sendNotification(conn, "initialized", {});
19918
19946
  conn.initialized = true;
19919
19947
  return conn;
@@ -20011,6 +20039,52 @@ async function getDefinition(filePath, line, column) {
20011
20039
  return [];
20012
20040
  }
20013
20041
  }
20042
+ async function getImplementation(filePath, line, column) {
20043
+ const projectRoot = findProjectRoot(filePath);
20044
+ const conn = await getConnection(projectRoot);
20045
+ await ensureDocumentOpen(conn, filePath);
20046
+ const result = await sendMessage(conn, "textDocument/implementation", {
20047
+ textDocument: { uri: toUri(filePath) },
20048
+ position: { line: line - 1, character: column - 1 }
20049
+ });
20050
+ if (!result)
20051
+ return [];
20052
+ const locations = Array.isArray(result) ? result : [result];
20053
+ return locations.map((loc) => {
20054
+ const uri = loc.targetUri || loc.uri;
20055
+ const range = loc.targetRange || loc.range;
20056
+ return {
20057
+ file: fromUri(uri),
20058
+ line: range.start.line + 1,
20059
+ column: range.start.character + 1,
20060
+ endLine: range.end.line + 1,
20061
+ endColumn: range.end.character + 1
20062
+ };
20063
+ });
20064
+ }
20065
+ async function getTypeDefinition(filePath, line, column) {
20066
+ const projectRoot = findProjectRoot(filePath);
20067
+ const conn = await getConnection(projectRoot);
20068
+ await ensureDocumentOpen(conn, filePath);
20069
+ const result = await sendMessage(conn, "textDocument/typeDefinition", {
20070
+ textDocument: { uri: toUri(filePath) },
20071
+ position: { line: line - 1, character: column - 1 }
20072
+ });
20073
+ if (!result)
20074
+ return [];
20075
+ const locations = Array.isArray(result) ? result : [result];
20076
+ return locations.map((loc) => {
20077
+ const uri = loc.targetUri || loc.uri;
20078
+ const range = loc.targetRange || loc.range;
20079
+ return {
20080
+ file: fromUri(uri),
20081
+ line: range.start.line + 1,
20082
+ column: range.start.character + 1,
20083
+ endLine: range.end.line + 1,
20084
+ endColumn: range.end.character + 1
20085
+ };
20086
+ });
20087
+ }
20014
20088
  async function getReferences(filePath, line, column) {
20015
20089
  const projectRoot = findProjectRoot(filePath);
20016
20090
  const conn = await getConnection(projectRoot);
@@ -20034,6 +20108,25 @@ async function getReferences(filePath, line, column) {
20034
20108
  return [];
20035
20109
  }
20036
20110
  }
20111
+ async function getDocumentHighlights(filePath, line, column) {
20112
+ const projectRoot = findProjectRoot(filePath);
20113
+ const conn = await getConnection(projectRoot);
20114
+ await ensureDocumentOpen(conn, filePath);
20115
+ const result = await sendMessage(conn, "textDocument/documentHighlight", {
20116
+ textDocument: { uri: toUri(filePath) },
20117
+ position: { line: line - 1, character: column - 1 }
20118
+ });
20119
+ if (!result || !Array.isArray(result))
20120
+ return [];
20121
+ return result.map((item) => ({
20122
+ file: path.resolve(filePath),
20123
+ line: item.range.start.line + 1,
20124
+ column: item.range.start.character + 1,
20125
+ endLine: item.range.end.line + 1,
20126
+ endColumn: item.range.end.character + 1,
20127
+ kind: item.kind ?? 1
20128
+ }));
20129
+ }
20037
20130
  async function getCompletions(filePath, line, column, limit = 20) {
20038
20131
  const projectRoot = findProjectRoot(filePath);
20039
20132
  const conn = await getConnection(projectRoot);
@@ -20114,6 +20207,29 @@ async function getSignatureHelp(filePath, line, column) {
20114
20207
  return null;
20115
20208
  }
20116
20209
  }
20210
+ async function getPrepareRename(filePath, line, column) {
20211
+ const projectRoot = findProjectRoot(filePath);
20212
+ const conn = await getConnection(projectRoot);
20213
+ await ensureDocumentOpen(conn, filePath);
20214
+ const result = await sendMessage(conn, "textDocument/prepareRename", {
20215
+ textDocument: { uri: toUri(filePath) },
20216
+ position: { line: line - 1, character: column - 1 }
20217
+ });
20218
+ if (!result)
20219
+ return { canRename: false };
20220
+ const range = "range" in result ? result.range : result;
20221
+ const placeholder = "placeholder" in result ? result.placeholder : undefined;
20222
+ return {
20223
+ canRename: true,
20224
+ placeholder,
20225
+ range: {
20226
+ line: range.start.line + 1,
20227
+ column: range.start.character + 1,
20228
+ endLine: range.end.line + 1,
20229
+ endColumn: range.end.character + 1
20230
+ }
20231
+ };
20232
+ }
20117
20233
  async function getInlayHints(filePath) {
20118
20234
  const projectRoot = findProjectRoot(filePath);
20119
20235
  const conn = await getConnection(projectRoot);
@@ -20138,6 +20254,228 @@ async function getInlayHints(filePath) {
20138
20254
  return [];
20139
20255
  }
20140
20256
  }
20257
+ async function getSemanticTokens(filePath) {
20258
+ const projectRoot = findProjectRoot(filePath);
20259
+ const conn = await getConnection(projectRoot);
20260
+ await ensureDocumentOpen(conn, filePath);
20261
+ const result = await sendMessage(conn, "textDocument/semanticTokens/full", {
20262
+ textDocument: { uri: toUri(filePath) }
20263
+ });
20264
+ if (!result || !Array.isArray(result.data)) {
20265
+ return { tokens: [], count: 0 };
20266
+ }
20267
+ const legend = conn.serverCapabilities?.semanticTokensProvider?.legend || {};
20268
+ const tokenTypes = Array.isArray(legend.tokenTypes) ? legend.tokenTypes : [
20269
+ "namespace",
20270
+ "type",
20271
+ "class",
20272
+ "enum",
20273
+ "interface",
20274
+ "struct",
20275
+ "typeParameter",
20276
+ "parameter",
20277
+ "variable",
20278
+ "property",
20279
+ "enumMember",
20280
+ "event",
20281
+ "function",
20282
+ "method",
20283
+ "macro",
20284
+ "keyword",
20285
+ "modifier",
20286
+ "comment",
20287
+ "string",
20288
+ "number",
20289
+ "regexp",
20290
+ "operator",
20291
+ "decorator"
20292
+ ];
20293
+ const tokenModifiers = Array.isArray(legend.tokenModifiers) ? legend.tokenModifiers : [];
20294
+ let line = 0;
20295
+ let character = 0;
20296
+ const decoded = [];
20297
+ for (let i = 0;i < result.data.length; i += 5) {
20298
+ const deltaLine = result.data[i];
20299
+ const deltaStart = result.data[i + 1];
20300
+ const length = result.data[i + 2];
20301
+ const tokenType = result.data[i + 3];
20302
+ const modifierBits = result.data[i + 4];
20303
+ line = line + deltaLine;
20304
+ character = deltaLine > 0 ? deltaStart : character + deltaStart;
20305
+ const modifiers = tokenModifiers.filter((_, idx) => (modifierBits & 1 << idx) !== 0);
20306
+ decoded.push({
20307
+ line: line + 1,
20308
+ column: character + 1,
20309
+ endLine: line + 1,
20310
+ endColumn: character + length + 1,
20311
+ token_type: tokenTypes[tokenType] || String(tokenType),
20312
+ token_modifiers: modifiers
20313
+ });
20314
+ }
20315
+ return { tokens: decoded, count: decoded.length };
20316
+ }
20317
+ async function getSelectionRanges(filePath, line, column) {
20318
+ const projectRoot = findProjectRoot(filePath);
20319
+ const conn = await getConnection(projectRoot);
20320
+ await ensureDocumentOpen(conn, filePath);
20321
+ const result = await sendMessage(conn, "textDocument/selectionRange", {
20322
+ textDocument: { uri: toUri(filePath) },
20323
+ positions: [{ line: line - 1, character: column - 1 }]
20324
+ });
20325
+ if (!Array.isArray(result) || result.length === 0)
20326
+ return [];
20327
+ const ranges = [];
20328
+ let current = result[0];
20329
+ while (current) {
20330
+ const itemRange = current.range;
20331
+ ranges.push({
20332
+ line: itemRange.start.line + 1,
20333
+ column: itemRange.start.character + 1,
20334
+ endLine: itemRange.end.line + 1,
20335
+ endColumn: itemRange.end.character + 1
20336
+ });
20337
+ current = current.parent;
20338
+ }
20339
+ return ranges;
20340
+ }
20341
+ async function getFoldingRanges(filePath) {
20342
+ const projectRoot = findProjectRoot(filePath);
20343
+ const conn = await getConnection(projectRoot);
20344
+ await ensureDocumentOpen(conn, filePath);
20345
+ const result = await sendMessage(conn, "textDocument/foldingRange", {
20346
+ textDocument: { uri: toUri(filePath) }
20347
+ });
20348
+ if (!Array.isArray(result))
20349
+ return [];
20350
+ return result.map((item) => ({
20351
+ kind: item.kind,
20352
+ line: (item.startLine ?? 0) + 1,
20353
+ column: (item.startCharacter ?? 0) + 1,
20354
+ endLine: (item.endLine ?? 0) + 1,
20355
+ endColumn: (item.endCharacter ?? 0) + 1
20356
+ }));
20357
+ }
20358
+ async function getDocumentLinks(filePath) {
20359
+ const projectRoot = findProjectRoot(filePath);
20360
+ const conn = await getConnection(projectRoot);
20361
+ await ensureDocumentOpen(conn, filePath);
20362
+ const result = await sendMessage(conn, "textDocument/documentLink", {
20363
+ textDocument: { uri: toUri(filePath) }
20364
+ });
20365
+ if (!Array.isArray(result))
20366
+ return [];
20367
+ return result.map((item) => ({
20368
+ target: item.target,
20369
+ line: item.range.start.line + 1,
20370
+ column: item.range.start.character + 1,
20371
+ endLine: item.range.end.line + 1,
20372
+ endColumn: item.range.end.character + 1
20373
+ }));
20374
+ }
20375
+ async function getCallHierarchy(filePath, line, column, direction = "both") {
20376
+ const projectRoot = findProjectRoot(filePath);
20377
+ const conn = await getConnection(projectRoot);
20378
+ await ensureDocumentOpen(conn, filePath);
20379
+ const prepared = await sendMessage(conn, "textDocument/prepareCallHierarchy", {
20380
+ textDocument: { uri: toUri(filePath) },
20381
+ position: { line: line - 1, character: column - 1 }
20382
+ });
20383
+ if (!prepared || Array.isArray(prepared) && prepared.length === 0) {
20384
+ return { items: [], count: 0, direction };
20385
+ }
20386
+ const baseItems = Array.isArray(prepared) ? prepared : [prepared];
20387
+ const includeIncoming = direction === "both" || direction === "incoming";
20388
+ const includeOutgoing = direction === "both" || direction === "outgoing";
20389
+ const items = await Promise.all(baseItems.map(async (item) => {
20390
+ const normalizeItem = (node) => ({
20391
+ name: node.name,
20392
+ kind: node.kind,
20393
+ containerName: node.containerName,
20394
+ file: fromUri(node.uri),
20395
+ line: (node.selectionRange?.start?.line ?? node.range.start.line) + 1,
20396
+ column: (node.selectionRange?.start?.character ?? node.range.start.character) + 1
20397
+ });
20398
+ const incoming = includeIncoming ? await sendMessage(conn, "callHierarchy/incomingCalls", { item }) || [] : [];
20399
+ const outgoing = includeOutgoing ? await sendMessage(conn, "callHierarchy/outgoingCalls", { item }) || [] : [];
20400
+ return {
20401
+ symbol: normalizeItem(item),
20402
+ incoming: incoming.map((call) => ({
20403
+ from: normalizeItem(call.from),
20404
+ call_count: Array.isArray(call.fromRanges) ? call.fromRanges.length : 0
20405
+ })),
20406
+ outgoing: outgoing.map((call) => ({
20407
+ to: normalizeItem(call.to),
20408
+ call_count: Array.isArray(call.fromRanges) ? call.fromRanges.length : 0
20409
+ }))
20410
+ };
20411
+ }));
20412
+ return { items, count: items.length, direction };
20413
+ }
20414
+ async function getCodeActions(filePath, line, column) {
20415
+ const projectRoot = findProjectRoot(filePath);
20416
+ const conn = await getConnection(projectRoot);
20417
+ await ensureDocumentOpen(conn, filePath);
20418
+ const result = await sendMessage(conn, "textDocument/codeAction", {
20419
+ textDocument: { uri: toUri(filePath) },
20420
+ range: {
20421
+ start: { line: line - 1, character: column - 1 },
20422
+ end: { line: line - 1, character: column - 1 }
20423
+ },
20424
+ context: { diagnostics: [] }
20425
+ });
20426
+ return Array.isArray(result) ? result : [];
20427
+ }
20428
+ async function executeCommand(filePath, command, args = []) {
20429
+ const projectRoot = findProjectRoot(filePath);
20430
+ const conn = await getConnection(projectRoot);
20431
+ return sendMessage(conn, "workspace/executeCommand", { command, arguments: args });
20432
+ }
20433
+ async function applyWorkspaceEdit(edit) {
20434
+ const allEdits = new Map;
20435
+ if (edit?.changes && typeof edit.changes === "object") {
20436
+ for (const [uri, edits] of Object.entries(edit.changes)) {
20437
+ allEdits.set(uri, Array.isArray(edits) ? edits : []);
20438
+ }
20439
+ }
20440
+ if (Array.isArray(edit?.documentChanges)) {
20441
+ for (const change of edit.documentChanges) {
20442
+ if (change?.textDocument?.uri && Array.isArray(change.edits)) {
20443
+ const uri = change.textDocument.uri;
20444
+ const existing = allEdits.get(uri) || [];
20445
+ existing.push(...change.edits);
20446
+ allEdits.set(uri, existing);
20447
+ }
20448
+ }
20449
+ }
20450
+ let filesChanged = 0;
20451
+ let editsApplied = 0;
20452
+ for (const [uri, edits] of allEdits) {
20453
+ const filePath = fromUri(uri);
20454
+ if (!fs.existsSync(filePath))
20455
+ continue;
20456
+ const original = getFileContent(filePath);
20457
+ let content = original;
20458
+ const sorted = [...edits].sort((a, b) => {
20459
+ if (a.range.start.line !== b.range.start.line)
20460
+ return b.range.start.line - a.range.start.line;
20461
+ return b.range.start.character - a.range.start.character;
20462
+ });
20463
+ for (const textEdit of sorted) {
20464
+ const start = textEdit.range.start;
20465
+ const end = textEdit.range.end;
20466
+ const startOffset = positionToOffset(content, start.line, start.character);
20467
+ const endOffset = positionToOffset(content, end.line, end.character);
20468
+ content = content.slice(0, startOffset) + (textEdit.newText || "") + content.slice(endOffset);
20469
+ editsApplied += 1;
20470
+ }
20471
+ if (content !== original) {
20472
+ fs.writeFileSync(filePath, content, "utf-8");
20473
+ await updateDocument(filePath, content);
20474
+ filesChanged += 1;
20475
+ }
20476
+ }
20477
+ return { filesChanged, editsApplied };
20478
+ }
20141
20479
  async function getDiagnostics(filePath) {
20142
20480
  const projectRoot = findProjectRoot(filePath);
20143
20481
  const absPath = path.resolve(filePath);
@@ -20687,6 +21025,18 @@ async function getDefinition3(file, line, column) {
20687
21025
  }
20688
21026
  return getDefinition2(absPath, line, column);
20689
21027
  }
21028
+ async function getImplementation2(file, line, column) {
21029
+ const { absPath, error: error2 } = resolveFilePath(file);
21030
+ if (error2 || !absPath)
21031
+ throw new Error(error2 || "Invalid path");
21032
+ return getImplementation(absPath, line, column);
21033
+ }
21034
+ async function getTypeDefinition2(file, line, column) {
21035
+ const { absPath, error: error2 } = resolveFilePath(file);
21036
+ if (error2 || !absPath)
21037
+ throw new Error(error2 || "Invalid path");
21038
+ return getTypeDefinition(absPath, line, column);
21039
+ }
20690
21040
  async function getReferences3(file, line, column) {
20691
21041
  const { absPath, error: error2 } = resolveFilePath(file);
20692
21042
  if (error2 || !absPath)
@@ -20697,6 +21047,12 @@ async function getReferences3(file, line, column) {
20697
21047
  }
20698
21048
  return getReferences2(absPath, line, column);
20699
21049
  }
21050
+ async function getDocumentHighlights2(file, line, column) {
21051
+ const { absPath, error: error2 } = resolveFilePath(file);
21052
+ if (error2 || !absPath)
21053
+ throw new Error(error2 || "Invalid path");
21054
+ return getDocumentHighlights(absPath, line, column);
21055
+ }
20700
21056
  async function getCompletions3(file, line, column, limit = 20) {
20701
21057
  const { absPath, error: error2 } = resolveFilePath(file);
20702
21058
  if (error2 || !absPath)
@@ -20717,6 +21073,39 @@ async function getSignatureHelp3(file, line, column) {
20717
21073
  }
20718
21074
  return getSignatureHelp2(absPath, line, column);
20719
21075
  }
21076
+ function symbolAtPosition(content, line, column) {
21077
+ const lines = content.split(`
21078
+ `);
21079
+ if (line < 1 || line > lines.length)
21080
+ return "";
21081
+ const text = lines[line - 1] || "";
21082
+ if (!text.length)
21083
+ return "";
21084
+ const idx = Math.max(0, Math.min(text.length - 1, column - 1));
21085
+ const re = /[A-Za-z_][A-Za-z0-9_]*/g;
21086
+ let match;
21087
+ while ((match = re.exec(text)) !== null) {
21088
+ if (match.index <= idx && idx < match.index + match[0].length) {
21089
+ return match[0];
21090
+ }
21091
+ }
21092
+ return "";
21093
+ }
21094
+ function packageNameFromPath(filePath) {
21095
+ const normalized = filePath.replace(/\\/g, "/");
21096
+ const marker = "/node_modules/";
21097
+ const idx = normalized.lastIndexOf(marker);
21098
+ if (idx < 0)
21099
+ return null;
21100
+ const rest = normalized.slice(idx + marker.length);
21101
+ const parts = rest.split("/");
21102
+ if (!parts.length)
21103
+ return null;
21104
+ if (parts[0].startsWith("@") && parts.length > 1) {
21105
+ return `${parts[0]}/${parts[1]}`;
21106
+ }
21107
+ return parts[0] || null;
21108
+ }
20720
21109
  var require2 = createRequire3(import.meta.url);
20721
21110
  var packageJson = require2("../package.json");
20722
21111
  var server = new McpServer({
@@ -20800,6 +21189,88 @@ server.tool("definition", "Go to definition of a symbol at a specific position i
20800
21189
  };
20801
21190
  }
20802
21191
  });
21192
+ server.tool("implementation", "Go to implementation of a symbol at a specific position in a Vue SFC file", {
21193
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21194
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21195
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21196
+ }, async ({ file, line, column }) => {
21197
+ try {
21198
+ const implementations = await getImplementation2(file, line, column);
21199
+ if (!implementations || implementations.length === 0) {
21200
+ return {
21201
+ content: [{ type: "text", text: JSON.stringify({ error: "No implementation found" }) }]
21202
+ };
21203
+ }
21204
+ return {
21205
+ content: [{
21206
+ type: "text",
21207
+ text: JSON.stringify(implementations.length === 1 ? implementations[0] : implementations)
21208
+ }]
21209
+ };
21210
+ } catch (error2) {
21211
+ const message = String(error2);
21212
+ if (message.includes("Method not found") || message.includes("implementation")) {
21213
+ return {
21214
+ content: [{
21215
+ type: "text",
21216
+ text: JSON.stringify({
21217
+ error: "NOT_IMPLEMENTED",
21218
+ error_code: "NOT_IMPLEMENTED",
21219
+ message: "Vue backend does not expose implementation in this environment.",
21220
+ next_step: "Use definition/references or switch to TypeScript backend for this feature.",
21221
+ install_commands: [],
21222
+ missing_packages: [],
21223
+ strict_mode: true
21224
+ })
21225
+ }]
21226
+ };
21227
+ }
21228
+ return {
21229
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21230
+ };
21231
+ }
21232
+ });
21233
+ server.tool("type_definition", "Go to type definition of a symbol at a specific position in a Vue SFC file", {
21234
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21235
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21236
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21237
+ }, async ({ file, line, column }) => {
21238
+ try {
21239
+ const typeDefinitions = await getTypeDefinition2(file, line, column);
21240
+ if (!typeDefinitions || typeDefinitions.length === 0) {
21241
+ return {
21242
+ content: [{ type: "text", text: JSON.stringify({ error: "No type definition found" }) }]
21243
+ };
21244
+ }
21245
+ return {
21246
+ content: [{
21247
+ type: "text",
21248
+ text: JSON.stringify(typeDefinitions.length === 1 ? typeDefinitions[0] : typeDefinitions)
21249
+ }]
21250
+ };
21251
+ } catch (error2) {
21252
+ const message = String(error2);
21253
+ if (message.includes("Method not found") || message.includes("typeDefinition")) {
21254
+ return {
21255
+ content: [{
21256
+ type: "text",
21257
+ text: JSON.stringify({
21258
+ error: "NOT_IMPLEMENTED",
21259
+ error_code: "NOT_IMPLEMENTED",
21260
+ message: "Vue backend does not expose type_definition in this environment.",
21261
+ next_step: "Use hover/definition or switch to TypeScript backend for this feature.",
21262
+ install_commands: [],
21263
+ missing_packages: [],
21264
+ strict_mode: true
21265
+ })
21266
+ }]
21267
+ };
21268
+ }
21269
+ return {
21270
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21271
+ };
21272
+ }
21273
+ });
20803
21274
  server.tool("references", "Find all references to a symbol at a specific position in a Vue SFC file", {
20804
21275
  file: exports_external.string().describe("Absolute path to the .vue file"),
20805
21276
  line: exports_external.number().int().positive().describe("Line number (1-based)"),
@@ -20819,6 +21290,85 @@ server.tool("references", "Find all references to a symbol at a specific positio
20819
21290
  };
20820
21291
  }
20821
21292
  });
21293
+ server.tool("call_hierarchy", "Get incoming/outgoing call hierarchy for symbol at a specific position in a Vue SFC file", {
21294
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21295
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21296
+ column: exports_external.number().int().positive().describe("Column number (1-based)"),
21297
+ direction: exports_external.enum(["incoming", "outgoing", "both"]).default("both").optional().describe("Call hierarchy direction to include")
21298
+ }, async ({ file, line, column, direction }) => {
21299
+ try {
21300
+ const { absPath, error: error2 } = resolveFilePath(file);
21301
+ if (error2 || !absPath) {
21302
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21303
+ }
21304
+ const result = await getCallHierarchy(absPath, line, column, direction || "both");
21305
+ if (!result.count) {
21306
+ return {
21307
+ content: [{ type: "text", text: JSON.stringify({ error: "No call hierarchy found", ...result }) }]
21308
+ };
21309
+ }
21310
+ return {
21311
+ content: [{ type: "text", text: JSON.stringify(result) }]
21312
+ };
21313
+ } catch (error2) {
21314
+ const message = String(error2);
21315
+ if (message.includes("Method not found") || message.includes("callHierarchy")) {
21316
+ return {
21317
+ content: [{
21318
+ type: "text",
21319
+ text: JSON.stringify({
21320
+ error: "NOT_IMPLEMENTED",
21321
+ error_code: "NOT_IMPLEMENTED",
21322
+ message: "Vue backend does not expose call_hierarchy in this environment.",
21323
+ next_step: "Use references/definition or switch to TypeScript backend for call_hierarchy.",
21324
+ install_commands: [],
21325
+ missing_packages: [],
21326
+ strict_mode: true
21327
+ })
21328
+ }]
21329
+ };
21330
+ }
21331
+ return {
21332
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21333
+ };
21334
+ }
21335
+ });
21336
+ server.tool("document_highlight", "Find symbol highlights in current Vue document at a specific position", {
21337
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21338
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21339
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21340
+ }, async ({ file, line, column }) => {
21341
+ try {
21342
+ const highlights = await getDocumentHighlights2(file, line, column);
21343
+ return {
21344
+ content: [{
21345
+ type: "text",
21346
+ text: JSON.stringify({ highlights, count: highlights.length })
21347
+ }]
21348
+ };
21349
+ } catch (error2) {
21350
+ const message = String(error2);
21351
+ if (message.includes("Method not found") || message.includes("documentHighlight")) {
21352
+ return {
21353
+ content: [{
21354
+ type: "text",
21355
+ text: JSON.stringify({
21356
+ error: "NOT_IMPLEMENTED",
21357
+ error_code: "NOT_IMPLEMENTED",
21358
+ message: "Vue backend does not expose document_highlight in this environment.",
21359
+ next_step: "Use references as fallback for symbol occurrences.",
21360
+ install_commands: [],
21361
+ missing_packages: [],
21362
+ strict_mode: true
21363
+ })
21364
+ }]
21365
+ };
21366
+ }
21367
+ return {
21368
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21369
+ };
21370
+ }
21371
+ });
20822
21372
  server.tool("completions", "Get code completion suggestions at a specific position in a Vue SFC file", {
20823
21373
  file: exports_external.string().describe("Absolute path to the .vue file"),
20824
21374
  line: exports_external.number().int().positive().describe("Line number (1-based)"),
@@ -20888,6 +21438,77 @@ server.tool("inlay_hints", "Get inlay hints (type annotations, parameter names)
20888
21438
  };
20889
21439
  }
20890
21440
  });
21441
+ server.tool("semantic_tokens", "Get semantic tokens for a Vue SFC file", {
21442
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)")
21443
+ }, async ({ file }) => {
21444
+ try {
21445
+ const { absPath, error: error2 } = resolveFilePath(file);
21446
+ if (error2 || !absPath) {
21447
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21448
+ }
21449
+ const result = await getSemanticTokens(absPath);
21450
+ return {
21451
+ content: [{
21452
+ type: "text",
21453
+ text: JSON.stringify(result)
21454
+ }]
21455
+ };
21456
+ } catch (error2) {
21457
+ const message = String(error2);
21458
+ if (message.includes("Method not found") || message.includes("semanticTokens")) {
21459
+ return {
21460
+ content: [{
21461
+ type: "text",
21462
+ text: JSON.stringify({
21463
+ error: "NOT_IMPLEMENTED",
21464
+ error_code: "NOT_IMPLEMENTED",
21465
+ message: "Vue backend does not expose semantic tokens in this environment.",
21466
+ next_step: "Use hover/definition/references or switch to TypeScript/Python where semantic_tokens is available.",
21467
+ install_commands: [],
21468
+ missing_packages: [],
21469
+ strict_mode: true
21470
+ })
21471
+ }]
21472
+ };
21473
+ }
21474
+ return {
21475
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21476
+ };
21477
+ }
21478
+ });
21479
+ server.tool("moniker", "Get moniker-like symbol identity for cross-package tracking in Vue files", {
21480
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21481
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21482
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21483
+ }, async ({ file, line, column }) => {
21484
+ try {
21485
+ const { absPath, error: error2 } = resolveFilePath(file);
21486
+ if (error2 || !absPath) {
21487
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21488
+ }
21489
+ const definitions = await getDefinition3(absPath, line, column);
21490
+ const sourceFile = definitions.length > 0 ? definitions[0].file : absPath;
21491
+ const content = getFileContent(absPath);
21492
+ const symbol = symbolAtPosition(content, line, column);
21493
+ const packageName = packageNameFromPath(sourceFile);
21494
+ const identifier = packageName ? `npm:${packageName}:${symbol || `${line}:${column}`}` : `workspace:${sourceFile}:${symbol || `${line}:${column}`}`;
21495
+ return {
21496
+ content: [{
21497
+ type: "text",
21498
+ text: JSON.stringify({
21499
+ symbol,
21500
+ identifier,
21501
+ package_name: packageName,
21502
+ source_file: sourceFile
21503
+ })
21504
+ }]
21505
+ };
21506
+ } catch (error2) {
21507
+ return {
21508
+ content: [{ type: "text", text: JSON.stringify({ error: String(error2) }) }]
21509
+ };
21510
+ }
21511
+ });
20891
21512
  server.tool("diagnostics", "Get type errors and warnings for Vue SFC files", {
20892
21513
  path: exports_external.string().describe("Path to a .vue file or directory to check (absolute or relative to active workspace)")
20893
21514
  }, async ({ path: inputPath }) => {
@@ -21025,6 +21646,150 @@ server.tool("symbols", "Extract symbols (variables, functions, components) from
21025
21646
  };
21026
21647
  }
21027
21648
  });
21649
+ server.tool("code_action", "Get available code actions (quick fixes/refactors) at a specific position in a Vue SFC file", {
21650
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21651
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21652
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21653
+ }, async ({ file, line, column }) => {
21654
+ try {
21655
+ const { absPath, error: error2 } = resolveFilePath(file);
21656
+ if (error2 || !absPath) {
21657
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21658
+ }
21659
+ const actions = await getCodeActions(absPath, line, column);
21660
+ const formatted = actions.map((action) => ({
21661
+ title: action.title,
21662
+ kind: action.kind || "quickfix",
21663
+ hasEdit: Boolean(action.edit),
21664
+ hasCommand: Boolean(action.command),
21665
+ data: action.data
21666
+ }));
21667
+ return {
21668
+ content: [{ type: "text", text: JSON.stringify({ actions: formatted, count: formatted.length }) }]
21669
+ };
21670
+ } catch (error2) {
21671
+ const message = String(error2);
21672
+ if (message.includes("Method not found") || message.includes("codeAction")) {
21673
+ return {
21674
+ content: [{
21675
+ type: "text",
21676
+ text: JSON.stringify({
21677
+ error: "NOT_IMPLEMENTED",
21678
+ error_code: "NOT_IMPLEMENTED",
21679
+ message: "Vue backend does not expose code_action in this environment.",
21680
+ next_step: "Use diagnostics + manual edits as fallback.",
21681
+ install_commands: [],
21682
+ missing_packages: [],
21683
+ strict_mode: true
21684
+ })
21685
+ }]
21686
+ };
21687
+ }
21688
+ return {
21689
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21690
+ };
21691
+ }
21692
+ });
21693
+ server.tool("run_code_action", "Run a specific code action at a position in a Vue SFC file", {
21694
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21695
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21696
+ column: exports_external.number().int().positive().describe("Column number (1-based)"),
21697
+ title: exports_external.string().describe("Code action title (exact match from code_action output)")
21698
+ }, async ({ file, line, column, title }) => {
21699
+ try {
21700
+ const { absPath, error: error2 } = resolveFilePath(file);
21701
+ if (error2 || !absPath) {
21702
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21703
+ }
21704
+ const actions = await getCodeActions(absPath, line, column);
21705
+ const action = actions.find((a) => a.title === title);
21706
+ if (!action) {
21707
+ return {
21708
+ content: [{ type: "text", text: JSON.stringify({ error: `Action '${title}' not found` }) }]
21709
+ };
21710
+ }
21711
+ let editResult = null;
21712
+ if (action.edit) {
21713
+ editResult = await applyWorkspaceEdit(action.edit);
21714
+ }
21715
+ if (action.command) {
21716
+ const commandName = typeof action.command === "string" ? action.command : action.command.command;
21717
+ const args = typeof action.command === "string" ? [] : action.command.arguments || [];
21718
+ await executeCommand(absPath, commandName, args);
21719
+ }
21720
+ return {
21721
+ content: [{
21722
+ type: "text",
21723
+ text: JSON.stringify({
21724
+ success: true,
21725
+ title: action.title,
21726
+ kind: action.kind || "quickfix",
21727
+ appliedEdit: Boolean(action.edit),
21728
+ executedCommand: Boolean(action.command),
21729
+ editResult
21730
+ })
21731
+ }]
21732
+ };
21733
+ } catch (error2) {
21734
+ const message = String(error2);
21735
+ if (message.includes("Method not found") || message.includes("codeAction") || message.includes("executeCommand")) {
21736
+ return {
21737
+ content: [{
21738
+ type: "text",
21739
+ text: JSON.stringify({
21740
+ error: "NOT_IMPLEMENTED",
21741
+ error_code: "NOT_IMPLEMENTED",
21742
+ message: "Vue backend cannot run code actions in this environment.",
21743
+ next_step: "Use code_action for hints and apply edits manually.",
21744
+ install_commands: [],
21745
+ missing_packages: [],
21746
+ strict_mode: true
21747
+ })
21748
+ }]
21749
+ };
21750
+ }
21751
+ return {
21752
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21753
+ };
21754
+ }
21755
+ });
21756
+ server.tool("prepare_rename", "Check whether a symbol can be safely renamed at a specific position in a Vue SFC file", {
21757
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21758
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21759
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21760
+ }, async ({ file, line, column }) => {
21761
+ try {
21762
+ const { absPath, error: error2 } = resolveFilePath(file);
21763
+ if (error2 || !absPath) {
21764
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21765
+ }
21766
+ const result = await getPrepareRename(absPath, line, column);
21767
+ return {
21768
+ content: [{ type: "text", text: JSON.stringify(result) }]
21769
+ };
21770
+ } catch (error2) {
21771
+ const message = String(error2);
21772
+ if (message.includes("Method not found") || message.includes("prepareRename")) {
21773
+ return {
21774
+ content: [{
21775
+ type: "text",
21776
+ text: JSON.stringify({
21777
+ error: "NOT_IMPLEMENTED",
21778
+ error_code: "NOT_IMPLEMENTED",
21779
+ message: "Vue backend does not expose prepare_rename in this environment.",
21780
+ next_step: "Use rename preview and verify affected ranges manually.",
21781
+ install_commands: [],
21782
+ missing_packages: [],
21783
+ strict_mode: true
21784
+ })
21785
+ }]
21786
+ };
21787
+ }
21788
+ return {
21789
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21790
+ };
21791
+ }
21792
+ });
21028
21793
  server.tool("rename", "Preview renaming a symbol at a specific position (shows all locations that would be renamed)", {
21029
21794
  file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21030
21795
  line: exports_external.number().int().positive().describe("Line number (1-based)"),
@@ -21071,6 +21836,153 @@ server.tool("rename", "Preview renaming a symbol at a specific position (shows a
21071
21836
  };
21072
21837
  }
21073
21838
  });
21839
+ server.tool("linked_editing_range", "Get linked editing ranges at a specific position in a Vue SFC file", {
21840
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21841
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21842
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21843
+ }, async ({ file, line, column }) => {
21844
+ try {
21845
+ const { absPath, error: error2 } = resolveFilePath(file);
21846
+ if (error2 || !absPath) {
21847
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21848
+ }
21849
+ const locations = await getRenameLocations(absPath, line, column);
21850
+ if (!locations || locations.length === 0) {
21851
+ return {
21852
+ content: [{ type: "text", text: JSON.stringify({ ranges: [], count: 0 }) }]
21853
+ };
21854
+ }
21855
+ const current = path3.resolve(absPath);
21856
+ const ranges = locations.filter((loc) => path3.resolve(loc.file) === current).map((loc) => ({
21857
+ line: loc.line,
21858
+ column: loc.column,
21859
+ endLine: loc.line,
21860
+ endColumn: loc.column + loc.length
21861
+ }));
21862
+ return {
21863
+ content: [{
21864
+ type: "text",
21865
+ text: JSON.stringify({ ranges, count: ranges.length })
21866
+ }]
21867
+ };
21868
+ } catch (error2) {
21869
+ return {
21870
+ content: [{ type: "text", text: JSON.stringify({ error: String(error2) }) }]
21871
+ };
21872
+ }
21873
+ });
21874
+ server.tool("selection_range", "Get nested smart selection ranges at a specific position in a Vue SFC file", {
21875
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
21876
+ line: exports_external.number().int().positive().describe("Line number (1-based)"),
21877
+ column: exports_external.number().int().positive().describe("Column number (1-based)")
21878
+ }, async ({ file, line, column }) => {
21879
+ try {
21880
+ const { absPath, error: error2 } = resolveFilePath(file);
21881
+ if (error2 || !absPath) {
21882
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21883
+ }
21884
+ const ranges = await getSelectionRanges(absPath, line, column);
21885
+ if (!ranges.length) {
21886
+ return {
21887
+ content: [{ type: "text", text: JSON.stringify({ error: "No selection range found" }) }]
21888
+ };
21889
+ }
21890
+ return {
21891
+ content: [{ type: "text", text: JSON.stringify({ ranges, count: ranges.length }) }]
21892
+ };
21893
+ } catch (error2) {
21894
+ const message = String(error2);
21895
+ if (message.includes("Method not found") || message.includes("selectionRange")) {
21896
+ return {
21897
+ content: [{
21898
+ type: "text",
21899
+ text: JSON.stringify({
21900
+ error: "NOT_IMPLEMENTED",
21901
+ error_code: "NOT_IMPLEMENTED",
21902
+ message: "Vue backend does not expose selection_range in this environment.",
21903
+ next_step: "Use read_file_with_hints/symbols and explicit ranges as fallback.",
21904
+ install_commands: [],
21905
+ missing_packages: [],
21906
+ strict_mode: true
21907
+ })
21908
+ }]
21909
+ };
21910
+ }
21911
+ return {
21912
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21913
+ };
21914
+ }
21915
+ });
21916
+ server.tool("folding_range", "Get foldable ranges in a Vue SFC file", {
21917
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)")
21918
+ }, async ({ file }) => {
21919
+ try {
21920
+ const { absPath, error: error2 } = resolveFilePath(file);
21921
+ if (error2 || !absPath) {
21922
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21923
+ }
21924
+ const ranges = await getFoldingRanges(absPath);
21925
+ return {
21926
+ content: [{ type: "text", text: JSON.stringify({ ranges, count: ranges.length }) }]
21927
+ };
21928
+ } catch (error2) {
21929
+ const message = String(error2);
21930
+ if (message.includes("Method not found") || message.includes("foldingRange")) {
21931
+ return {
21932
+ content: [{
21933
+ type: "text",
21934
+ text: JSON.stringify({
21935
+ error: "NOT_IMPLEMENTED",
21936
+ error_code: "NOT_IMPLEMENTED",
21937
+ message: "Vue backend does not expose folding_range in this environment.",
21938
+ next_step: "Use symbols-based sections for manual folding.",
21939
+ install_commands: [],
21940
+ missing_packages: [],
21941
+ strict_mode: true
21942
+ })
21943
+ }]
21944
+ };
21945
+ }
21946
+ return {
21947
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21948
+ };
21949
+ }
21950
+ });
21951
+ server.tool("document_link", "Extract links (imports/URLs) from a Vue SFC file", {
21952
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)")
21953
+ }, async ({ file }) => {
21954
+ try {
21955
+ const { absPath, error: error2 } = resolveFilePath(file);
21956
+ if (error2 || !absPath) {
21957
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21958
+ }
21959
+ const links = await getDocumentLinks(absPath);
21960
+ return {
21961
+ content: [{ type: "text", text: JSON.stringify({ links, count: links.length }) }]
21962
+ };
21963
+ } catch (error2) {
21964
+ const message = String(error2);
21965
+ if (message.includes("Method not found") || message.includes("documentLink")) {
21966
+ return {
21967
+ content: [{
21968
+ type: "text",
21969
+ text: JSON.stringify({
21970
+ error: "NOT_IMPLEMENTED",
21971
+ error_code: "NOT_IMPLEMENTED",
21972
+ message: "Vue backend does not expose document_link in this environment.",
21973
+ next_step: "Use search over import/url patterns as fallback.",
21974
+ install_commands: [],
21975
+ missing_packages: [],
21976
+ strict_mode: true
21977
+ })
21978
+ }]
21979
+ };
21980
+ }
21981
+ return {
21982
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }]
21983
+ };
21984
+ }
21985
+ });
21074
21986
  server.tool("search", "Search for a pattern in Vue files using ripgrep", {
21075
21987
  pattern: exports_external.string().describe("The regex pattern to search for"),
21076
21988
  path: exports_external.string().optional().describe("Directory or file to search in (absolute or relative to active workspace)"),
@@ -75,6 +75,26 @@ export declare function getDefinition(filePath: string, line: number, column: nu
75
75
  line: number;
76
76
  column: number;
77
77
  }>>;
78
+ /**
79
+ * Get implementation locations
80
+ */
81
+ export declare function getImplementation(filePath: string, line: number, column: number): Promise<Array<{
82
+ file: string;
83
+ line: number;
84
+ column: number;
85
+ endLine: number;
86
+ endColumn: number;
87
+ }>>;
88
+ /**
89
+ * Get type definition locations
90
+ */
91
+ export declare function getTypeDefinition(filePath: string, line: number, column: number): Promise<Array<{
92
+ file: string;
93
+ line: number;
94
+ column: number;
95
+ endLine: number;
96
+ endColumn: number;
97
+ }>>;
78
98
  /**
79
99
  * Get all references to a symbol
80
100
  */
@@ -83,6 +103,17 @@ export declare function getReferences(filePath: string, line: number, column: nu
83
103
  line: number;
84
104
  column: number;
85
105
  }>>;
106
+ /**
107
+ * Get document highlights for a symbol
108
+ */
109
+ export declare function getDocumentHighlights(filePath: string, line: number, column: number): Promise<Array<{
110
+ file: string;
111
+ line: number;
112
+ column: number;
113
+ endLine: number;
114
+ endColumn: number;
115
+ kind: number;
116
+ }>>;
86
117
  /**
87
118
  * Get completions at a position
88
119
  */
@@ -104,10 +135,82 @@ export declare function getSignatureHelp(filePath: string, line: number, column:
104
135
  activeSignature: number;
105
136
  activeParameter: number;
106
137
  } | null>;
138
+ /**
139
+ * Check whether rename is valid at this position
140
+ */
141
+ export declare function getPrepareRename(filePath: string, line: number, column: number): Promise<{
142
+ canRename: boolean;
143
+ placeholder?: string;
144
+ range?: {
145
+ line: number;
146
+ column: number;
147
+ endLine: number;
148
+ endColumn: number;
149
+ };
150
+ }>;
107
151
  /**
108
152
  * Get inlay hints for a file
109
153
  */
110
154
  export declare function getInlayHints(filePath: string): Promise<any[]>;
155
+ /**
156
+ * Get semantic tokens for a file and decode to absolute positions.
157
+ */
158
+ export declare function getSemanticTokens(filePath: string): Promise<{
159
+ tokens: any[];
160
+ count: number;
161
+ }>;
162
+ /**
163
+ * Get nested smart selection ranges for a position.
164
+ */
165
+ export declare function getSelectionRanges(filePath: string, line: number, column: number): Promise<Array<{
166
+ line: number;
167
+ column: number;
168
+ endLine: number;
169
+ endColumn: number;
170
+ }>>;
171
+ /**
172
+ * Get foldable ranges in a file.
173
+ */
174
+ export declare function getFoldingRanges(filePath: string): Promise<Array<{
175
+ kind?: string;
176
+ line: number;
177
+ column: number;
178
+ endLine: number;
179
+ endColumn: number;
180
+ }>>;
181
+ /**
182
+ * Get document links (imports/URLs).
183
+ */
184
+ export declare function getDocumentLinks(filePath: string): Promise<Array<{
185
+ target?: string;
186
+ line: number;
187
+ column: number;
188
+ endLine: number;
189
+ endColumn: number;
190
+ }>>;
191
+ /**
192
+ * Get call hierarchy around a symbol.
193
+ */
194
+ export declare function getCallHierarchy(filePath: string, line: number, column: number, direction?: "incoming" | "outgoing" | "both"): Promise<{
195
+ items: any[];
196
+ count: number;
197
+ direction: "incoming" | "outgoing" | "both";
198
+ }>;
199
+ /**
200
+ * Get code actions at a position.
201
+ */
202
+ export declare function getCodeActions(filePath: string, line: number, column: number): Promise<any[]>;
203
+ /**
204
+ * Execute command from code action.
205
+ */
206
+ export declare function executeCommand(filePath: string, command: string, args?: any[]): Promise<any>;
207
+ /**
208
+ * Apply WorkspaceEdit to disk and sync open docs.
209
+ */
210
+ export declare function applyWorkspaceEdit(edit: any): Promise<{
211
+ filesChanged: number;
212
+ editsApplied: number;
213
+ }>;
111
214
  /**
112
215
  * Diagnostic type for internal use
113
216
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treedy/vue-lsp-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },