@treedy/lsp-mcp 0.1.8 → 0.1.9

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 (34) hide show
  1. package/dist/bundled/python/src/rope_mcp/config.py +50 -14
  2. package/dist/bundled/python/src/rope_mcp/lsp/client.py +243 -4
  3. package/dist/bundled/python/src/rope_mcp/lsp/types.py +1 -0
  4. package/dist/bundled/python/src/rope_mcp/server.py +331 -77
  5. package/dist/bundled/python/src/rope_mcp/tools/__init__.py +0 -2
  6. package/dist/bundled/typescript/dist/index.js +6129 -5891
  7. package/dist/bundled/typescript/dist/index.js.map +5 -5
  8. package/dist/bundled/vue/dist/index.js +136 -71
  9. package/dist/bundled/vue/dist/vue-service.d.ts +16 -0
  10. package/dist/index.js +567 -314
  11. package/dist/index.js.map +6 -6
  12. package/package.json +1 -1
  13. package/dist/bundled/python/src/rope_mcp/__pycache__/__init__.cpython-312.pyc +0 -0
  14. package/dist/bundled/python/src/rope_mcp/__pycache__/__init__.cpython-313.pyc +0 -0
  15. package/dist/bundled/python/src/rope_mcp/__pycache__/config.cpython-312.pyc +0 -0
  16. package/dist/bundled/python/src/rope_mcp/__pycache__/config.cpython-313.pyc +0 -0
  17. package/dist/bundled/python/src/rope_mcp/__pycache__/pyright_client.cpython-313.pyc +0 -0
  18. package/dist/bundled/python/src/rope_mcp/__pycache__/rope_client.cpython-313.pyc +0 -0
  19. package/dist/bundled/python/src/rope_mcp/__pycache__/server.cpython-312.pyc +0 -0
  20. package/dist/bundled/python/src/rope_mcp/__pycache__/server.cpython-313.pyc +0 -0
  21. package/dist/bundled/python/src/rope_mcp/lsp/__pycache__/__init__.cpython-313.pyc +0 -0
  22. package/dist/bundled/python/src/rope_mcp/lsp/__pycache__/client.cpython-313.pyc +0 -0
  23. package/dist/bundled/python/src/rope_mcp/lsp/__pycache__/types.cpython-313.pyc +0 -0
  24. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  25. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/change_signature.cpython-313.pyc +0 -0
  26. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/completions.cpython-313.pyc +0 -0
  27. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/definition.cpython-313.pyc +0 -0
  28. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/diagnostics.cpython-313.pyc +0 -0
  29. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/hover.cpython-313.pyc +0 -0
  30. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/move.cpython-313.pyc +0 -0
  31. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/references.cpython-313.pyc +0 -0
  32. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/rename.cpython-313.pyc +0 -0
  33. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/search.cpython-313.pyc +0 -0
  34. package/dist/bundled/python/src/rope_mcp/tools/__pycache__/symbols.cpython-313.pyc +0 -0
@@ -19594,17 +19594,25 @@ function setActiveWorkspace(workspace) {
19594
19594
  activeWorkspace = path.resolve(workspace);
19595
19595
  return activeWorkspace;
19596
19596
  }
19597
- function isFileInWorkspace(filePath) {
19598
- if (!activeWorkspace)
19599
- return true;
19600
- const absPath = path.resolve(filePath);
19601
- return absPath.startsWith(activeWorkspace);
19602
- }
19603
- function validateFileWorkspace(filePath) {
19604
- if (!isFileInWorkspace(filePath)) {
19605
- return JSON.stringify({
19606
- error: "Context Mismatch",
19607
- message: `The file '${filePath}' is outside the active workspace '${activeWorkspace}'.
19597
+ function resolveFilePath(filePath) {
19598
+ const pathObj = path.parse(filePath);
19599
+ let absPath;
19600
+ if (!path.isAbsolute(filePath)) {
19601
+ if (activeWorkspace) {
19602
+ absPath = path.resolve(activeWorkspace, filePath);
19603
+ } else {
19604
+ absPath = path.resolve(filePath);
19605
+ }
19606
+ } else {
19607
+ absPath = filePath;
19608
+ }
19609
+ absPath = path.resolve(absPath);
19610
+ if (activeWorkspace && !absPath.startsWith(activeWorkspace)) {
19611
+ return {
19612
+ absPath: null,
19613
+ error: JSON.stringify({
19614
+ error: "Context Mismatch",
19615
+ message: `The file '${filePath}' resolves to '${absPath}', which is outside the active workspace '${activeWorkspace}'.
19608
19616
 
19609
19617
  Current Logic:
19610
19618
  1. I only analyze files from the active project to ensure accuracy and save resources.
@@ -19612,10 +19620,16 @@ Current Logic:
19612
19620
 
19613
19621
  Action Required:
19614
19622
  Please call 'switch_workspace(path="...")' with the new project root before retrying.`,
19615
- currentWorkspace: activeWorkspace
19616
- });
19623
+ currentWorkspace: activeWorkspace,
19624
+ resolvedPath: absPath
19625
+ })
19626
+ };
19617
19627
  }
19618
- return null;
19628
+ return { absPath, error: null };
19629
+ }
19630
+ function validateFileWorkspace(filePath) {
19631
+ const { error: error2 } = resolveFilePath(filePath);
19632
+ return error2;
19619
19633
  }
19620
19634
  function clearAllConnections() {
19621
19635
  for (const conn of activeConnections) {
@@ -20100,6 +20114,30 @@ async function getSignatureHelp(filePath, line, column) {
20100
20114
  return null;
20101
20115
  }
20102
20116
  }
20117
+ async function getInlayHints(filePath) {
20118
+ const projectRoot = findProjectRoot(filePath);
20119
+ const conn = await getConnection(projectRoot);
20120
+ await ensureDocumentOpen(conn, filePath);
20121
+ try {
20122
+ const content = getFileContent(filePath);
20123
+ const lines = content.split(`
20124
+ `);
20125
+ const result = await sendMessage(conn, "textDocument/inlayHint", {
20126
+ textDocument: { uri: toUri(filePath) },
20127
+ range: {
20128
+ start: { line: 0, character: 0 },
20129
+ end: { line: lines.length, character: lines[lines.length - 1].length }
20130
+ }
20131
+ });
20132
+ if (!result) {
20133
+ return [];
20134
+ }
20135
+ return Array.isArray(result) ? result : [];
20136
+ } catch (error2) {
20137
+ console.error("Inlay hints error:", error2);
20138
+ return [];
20139
+ }
20140
+ }
20103
20141
  async function getDiagnostics(filePath) {
20104
20142
  const projectRoot = findProjectRoot(filePath);
20105
20143
  const absPath = path.resolve(filePath);
@@ -20630,54 +20668,54 @@ async function getRenameLocations(filePath, line, column) {
20630
20668
 
20631
20669
  // src/index.ts
20632
20670
  async function getQuickInfo3(file, line, column) {
20633
- const error2 = validateFileWorkspace(file);
20634
- if (error2)
20635
- throw new Error(error2);
20636
- const lspResult = await getQuickInfo(file, line, column);
20671
+ const { absPath, error: error2 } = resolveFilePath(file);
20672
+ if (error2 || !absPath)
20673
+ throw new Error(error2 || "Invalid path");
20674
+ const lspResult = await getQuickInfo(absPath, line, column);
20637
20675
  if (lspResult && lspResult.contents) {
20638
20676
  return lspResult;
20639
20677
  }
20640
- return getQuickInfo2(file, line, column);
20678
+ return getQuickInfo2(absPath, line, column);
20641
20679
  }
20642
20680
  async function getDefinition3(file, line, column) {
20643
- const error2 = validateFileWorkspace(file);
20644
- if (error2)
20645
- throw new Error(error2);
20646
- const lspResult = await getDefinition(file, line, column);
20681
+ const { absPath, error: error2 } = resolveFilePath(file);
20682
+ if (error2 || !absPath)
20683
+ throw new Error(error2 || "Invalid path");
20684
+ const lspResult = await getDefinition(absPath, line, column);
20647
20685
  if (lspResult && lspResult.length > 0) {
20648
20686
  return lspResult;
20649
20687
  }
20650
- return getDefinition2(file, line, column);
20688
+ return getDefinition2(absPath, line, column);
20651
20689
  }
20652
20690
  async function getReferences3(file, line, column) {
20653
- const error2 = validateFileWorkspace(file);
20654
- if (error2)
20655
- throw new Error(error2);
20656
- const lspResult = await getReferences(file, line, column);
20691
+ const { absPath, error: error2 } = resolveFilePath(file);
20692
+ if (error2 || !absPath)
20693
+ throw new Error(error2 || "Invalid path");
20694
+ const lspResult = await getReferences(absPath, line, column);
20657
20695
  if (lspResult && lspResult.length > 0) {
20658
20696
  return lspResult;
20659
20697
  }
20660
- return getReferences2(file, line, column);
20698
+ return getReferences2(absPath, line, column);
20661
20699
  }
20662
20700
  async function getCompletions3(file, line, column, limit = 20) {
20663
- const error2 = validateFileWorkspace(file);
20664
- if (error2)
20665
- throw new Error(error2);
20666
- const lspResult = await getCompletions(file, line, column, limit);
20701
+ const { absPath, error: error2 } = resolveFilePath(file);
20702
+ if (error2 || !absPath)
20703
+ throw new Error(error2 || "Invalid path");
20704
+ const lspResult = await getCompletions(absPath, line, column, limit);
20667
20705
  if (lspResult && lspResult.items && lspResult.items.length > 0) {
20668
20706
  return lspResult;
20669
20707
  }
20670
- return getCompletions2(file, line, column, limit);
20708
+ return getCompletions2(absPath, line, column, limit);
20671
20709
  }
20672
20710
  async function getSignatureHelp3(file, line, column) {
20673
- const error2 = validateFileWorkspace(file);
20674
- if (error2)
20675
- throw new Error(error2);
20676
- const lspResult = await getSignatureHelp(file, line, column);
20711
+ const { absPath, error: error2 } = resolveFilePath(file);
20712
+ if (error2 || !absPath)
20713
+ throw new Error(error2 || "Invalid path");
20714
+ const lspResult = await getSignatureHelp(absPath, line, column);
20677
20715
  if (lspResult && lspResult.signatures && lspResult.signatures.length > 0) {
20678
20716
  return lspResult;
20679
20717
  }
20680
- return getSignatureHelp2(file, line, column);
20718
+ return getSignatureHelp2(absPath, line, column);
20681
20719
  }
20682
20720
  var require2 = createRequire3(import.meta.url);
20683
20721
  var packageJson = require2("../package.json");
@@ -20829,15 +20867,35 @@ server.tool("signature_help", "Get function signature help at a specific positio
20829
20867
  };
20830
20868
  }
20831
20869
  });
20870
+ server.tool("inlay_hints", "Get inlay hints (type annotations, parameter names) for a Vue SFC file", {
20871
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)")
20872
+ }, async ({ file }) => {
20873
+ try {
20874
+ const { absPath, error: error2 } = resolveFilePath(file);
20875
+ if (error2 || !absPath) {
20876
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
20877
+ }
20878
+ const hints = await getInlayHints(absPath);
20879
+ return {
20880
+ content: [{
20881
+ type: "text",
20882
+ text: JSON.stringify({ hints, count: hints.length })
20883
+ }]
20884
+ };
20885
+ } catch (error2) {
20886
+ return {
20887
+ content: [{ type: "text", text: JSON.stringify({ error: String(error2) }) }]
20888
+ };
20889
+ }
20890
+ });
20832
20891
  server.tool("diagnostics", "Get type errors and warnings for Vue SFC files", {
20833
- path: exports_external.string().describe("Path to a .vue file or directory to check")
20892
+ path: exports_external.string().describe("Path to a .vue file or directory to check (absolute or relative to active workspace)")
20834
20893
  }, async ({ path: inputPath }) => {
20835
20894
  try {
20836
- const error2 = validateFileWorkspace(inputPath);
20837
- if (error2) {
20838
- return { content: [{ type: "text", text: error2 }] };
20895
+ const { absPath, error: error2 } = resolveFilePath(inputPath);
20896
+ if (error2 || !absPath) {
20897
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
20839
20898
  }
20840
- const absPath = path3.resolve(inputPath);
20841
20899
  const stats = fs3.statSync(absPath);
20842
20900
  let files = [];
20843
20901
  if (stats.isDirectory()) {
@@ -20882,19 +20940,19 @@ server.tool("diagnostics", "Get type errors and warnings for Vue SFC files", {
20882
20940
  }
20883
20941
  });
20884
20942
  server.tool("update_document", "Update Vue file content for incremental analysis without writing to disk", {
20885
- file: exports_external.string().describe("Absolute path to the .vue file"),
20943
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
20886
20944
  content: exports_external.string().describe("New content for the file")
20887
20945
  }, async ({ file, content }) => {
20888
20946
  try {
20889
- const error2 = validateFileWorkspace(file);
20890
- if (error2) {
20891
- return { content: [{ type: "text", text: error2 }] };
20947
+ const { absPath, error: error2 } = resolveFilePath(file);
20948
+ if (error2 || !absPath) {
20949
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
20892
20950
  }
20893
- await updateDocument(file, content);
20951
+ await updateDocument(absPath, content);
20894
20952
  return {
20895
20953
  content: [{
20896
20954
  type: "text",
20897
- text: JSON.stringify({ success: true, file })
20955
+ text: JSON.stringify({ success: true, file: absPath })
20898
20956
  }]
20899
20957
  };
20900
20958
  } catch (error2) {
@@ -20904,7 +20962,7 @@ server.tool("update_document", "Update Vue file content for incremental analysis
20904
20962
  }
20905
20963
  });
20906
20964
  server.tool("symbols", "Extract symbols (variables, functions, components) from a Vue SFC file", {
20907
- file: exports_external.string().describe("Absolute path to the .vue file"),
20965
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
20908
20966
  query: exports_external.string().optional().describe("Optional filter query for symbol names")
20909
20967
  }, async ({ file, query }) => {
20910
20968
  try {
@@ -20939,11 +20997,11 @@ server.tool("symbols", "Extract symbols (variables, functions, components) from
20939
20997
  }
20940
20998
  }
20941
20999
  };
20942
- const error2 = validateFileWorkspace(file);
20943
- if (error2) {
20944
- return { content: [{ type: "text", text: error2 }] };
21000
+ const { absPath, error: error2 } = resolveFilePath(file);
21001
+ if (error2 || !absPath) {
21002
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
20945
21003
  }
20946
- const tree = await getDocumentSymbols(file);
21004
+ const tree = await getDocumentSymbols(absPath);
20947
21005
  if (!tree) {
20948
21006
  return {
20949
21007
  content: [{ type: "text", text: JSON.stringify({ error: "Failed to get symbols" }) }]
@@ -20968,17 +21026,17 @@ server.tool("symbols", "Extract symbols (variables, functions, components) from
20968
21026
  }
20969
21027
  });
20970
21028
  server.tool("rename", "Preview renaming a symbol at a specific position (shows all locations that would be renamed)", {
20971
- file: exports_external.string().describe("Absolute path to the .vue file"),
21029
+ file: exports_external.string().describe("Path to the .vue file (absolute or relative to active workspace)"),
20972
21030
  line: exports_external.number().int().positive().describe("Line number (1-based)"),
20973
21031
  column: exports_external.number().int().positive().describe("Column number (1-based)"),
20974
21032
  newName: exports_external.string().describe("New name for the symbol")
20975
21033
  }, async ({ file, line, column, newName }) => {
20976
21034
  try {
20977
- const error2 = validateFileWorkspace(file);
20978
- if (error2) {
20979
- return { content: [{ type: "text", text: error2 }] };
21035
+ const { absPath, error: error2 } = resolveFilePath(file);
21036
+ if (error2 || !absPath) {
21037
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
20980
21038
  }
20981
- const locations = await getRenameLocations(file, line, column);
21039
+ const locations = await getRenameLocations(absPath, line, column);
20982
21040
  if (!locations || locations.length === 0) {
20983
21041
  return {
20984
21042
  content: [{ type: "text", text: JSON.stringify({ error: "Cannot rename symbol at this position" }) }]
@@ -21015,17 +21073,24 @@ server.tool("rename", "Preview renaming a symbol at a specific position (shows a
21015
21073
  });
21016
21074
  server.tool("search", "Search for a pattern in Vue files using ripgrep", {
21017
21075
  pattern: exports_external.string().describe("The regex pattern to search for"),
21018
- path: exports_external.string().optional().describe("Directory or file to search in"),
21076
+ path: exports_external.string().optional().describe("Directory or file to search in (absolute or relative to active workspace)"),
21019
21077
  glob: exports_external.string().optional().describe("Glob pattern to filter files (e.g., '*.vue')"),
21020
21078
  caseSensitive: exports_external.boolean().default(true).describe("Whether the search is case sensitive"),
21021
21079
  maxResults: exports_external.number().int().positive().default(50).describe("Maximum number of results")
21022
21080
  }, async ({ pattern, path: searchPath, glob, caseSensitive, maxResults }) => {
21023
21081
  try {
21082
+ let absSearchPath;
21024
21083
  if (searchPath) {
21025
- const error2 = validateFileWorkspace(searchPath);
21026
- if (error2) {
21027
- return { content: [{ type: "text", text: error2 }] };
21084
+ const { absPath, error: error2 } = validateFileWorkspace(searchPath) ? { absPath: null, error: validateFileWorkspace(searchPath) } : { absPath: path3.resolve(searchPath), error: null };
21085
+ const result2 = resolveFilePath(searchPath);
21086
+ if (result2.error || !result2.absPath) {
21087
+ return { content: [{ type: "text", text: result2.error || "Invalid path" }] };
21028
21088
  }
21089
+ absSearchPath = result2.absPath;
21090
+ } else {
21091
+ const { absPath } = resolveFilePath(".");
21092
+ if (absPath)
21093
+ absSearchPath = absPath;
21029
21094
  }
21030
21095
  const { execSync } = await import("child_process");
21031
21096
  const args = ["rg", "--json", "-n"];
@@ -21038,8 +21103,8 @@ server.tool("search", "Search for a pattern in Vue files using ripgrep", {
21038
21103
  }
21039
21104
  args.push("--max-count", maxResults.toString());
21040
21105
  args.push(pattern);
21041
- if (searchPath)
21042
- args.push(searchPath);
21106
+ if (absSearchPath)
21107
+ args.push(absSearchPath);
21043
21108
  const result = execSync(args.join(" "), {
21044
21109
  encoding: "utf-8",
21045
21110
  maxBuffer: 10485760,
@@ -21080,14 +21145,14 @@ server.tool("search", "Search for a pattern in Vue files using ripgrep", {
21080
21145
  }
21081
21146
  });
21082
21147
  server.tool("status", "Check Vue Language Server status for a project", {
21083
- file: exports_external.string().describe("A .vue file path to check the project status for")
21148
+ file: exports_external.string().describe("A .vue file path to check the project status for (absolute or relative to active workspace)")
21084
21149
  }, async ({ file }) => {
21085
21150
  try {
21086
- const error2 = validateFileWorkspace(file);
21087
- if (error2) {
21088
- return { content: [{ type: "text", text: error2 }] };
21151
+ const { absPath, error: error2 } = resolveFilePath(file);
21152
+ if (error2 || !absPath) {
21153
+ return { content: [{ type: "text", text: error2 || "Invalid path" }] };
21089
21154
  }
21090
- const status = await getProjectStatus(file);
21155
+ const status = await getProjectStatus(absPath);
21091
21156
  return {
21092
21157
  content: [{
21093
21158
  type: "text",
@@ -16,8 +16,20 @@ export declare function getActiveWorkspace(): string | null;
16
16
  * Check if a file is in the active workspace.
17
17
  */
18
18
  export declare function isFileInWorkspace(filePath: string): boolean;
19
+ /**
20
+ * Resolve a file path and validate it against the active workspace.
21
+ *
22
+ * Supports:
23
+ * 1. Absolute paths (must be within active workspace)
24
+ * 2. Relative paths (resolved against active workspace)
25
+ */
26
+ export declare function resolveFilePath(filePath: string): {
27
+ absPath: string | null;
28
+ error: string | null;
29
+ };
19
30
  /**
20
31
  * Validate that a file is within the active workspace.
32
+ * @deprecated Use resolveFilePath instead.
21
33
  */
22
34
  export declare function validateFileWorkspace(filePath: string): string | null;
23
35
  /**
@@ -92,6 +104,10 @@ export declare function getSignatureHelp(filePath: string, line: number, column:
92
104
  activeSignature: number;
93
105
  activeParameter: number;
94
106
  } | null>;
107
+ /**
108
+ * Get inlay hints for a file
109
+ */
110
+ export declare function getInlayHints(filePath: string): Promise<any[]>;
95
111
  /**
96
112
  * Diagnostic type for internal use
97
113
  */